Implement basic condition DSL framework for tests:
Instead of interrupting task evaluation when condition is not met, allow the whole task to be evaluated (including condition and evaluation) so that the interpreter will get all tasks actions (whether condition is met or not) and be able to query the condition. * Modify Interpreter#process_task: test if task condition is met before applying the actions; * Implement condition handling in Task and Task::DSL; * Implement Condition and Condition::DSL (useless as they are, but needed to implement later test keywords as part of the condition DSL.
This commit is contained in:
parent
0008f0255a
commit
639bdc1c73
@ -1,13 +1,12 @@
|
||||
Feature: `condition' task keyword
|
||||
|
||||
Scenario: prevents task evaluation when condition is not met
|
||||
Scenario: prevents task actions application when condition is not met
|
||||
Given a recipe with:
|
||||
"""
|
||||
task :hello do
|
||||
condition { false }
|
||||
|
||||
puts 'evaluated'
|
||||
exit 70
|
||||
echo 'evaluated'
|
||||
end
|
||||
"""
|
||||
When I execute the recipe
|
||||
|
@ -2,6 +2,8 @@ require 'producer/core/action'
|
||||
require 'producer/core/actions/echo'
|
||||
require 'producer/core/actions/shell_command'
|
||||
require 'producer/core/cli'
|
||||
require 'producer/core/condition'
|
||||
require 'producer/core/condition/dsl'
|
||||
require 'producer/core/env'
|
||||
require 'producer/core/errors'
|
||||
require 'producer/core/interpreter'
|
||||
|
19
lib/producer/core/condition.rb
Normal file
19
lib/producer/core/condition.rb
Normal file
@ -0,0 +1,19 @@
|
||||
module Producer
|
||||
module Core
|
||||
class Condition
|
||||
class << self
|
||||
def evaluate(env, &block)
|
||||
DSL.evaluate(env, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(expression)
|
||||
@expression = expression
|
||||
end
|
||||
|
||||
def !
|
||||
!@expression
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
lib/producer/core/condition/dsl.rb
Normal file
22
lib/producer/core/condition/dsl.rb
Normal file
@ -0,0 +1,22 @@
|
||||
module Producer
|
||||
module Core
|
||||
class Condition
|
||||
class DSL
|
||||
class << self
|
||||
def evaluate(env, &block)
|
||||
dsl = new(&block)
|
||||
Condition.new(dsl.evaluate)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
def evaluate
|
||||
@block.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -6,7 +6,7 @@ module Producer
|
||||
end
|
||||
|
||||
def process_task(task)
|
||||
task.actions.each(&:apply)
|
||||
task.actions.each(&:apply) if task.condition_met?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +1,20 @@
|
||||
module Producer
|
||||
module Core
|
||||
class Task
|
||||
attr_reader :name, :actions
|
||||
attr_reader :name, :actions, :condition
|
||||
|
||||
def self.evaluate(name, env, &block)
|
||||
DSL.evaluate(name, env, &block)
|
||||
end
|
||||
|
||||
def initialize(name, actions = [])
|
||||
@name = name
|
||||
@actions = actions
|
||||
def initialize(name, actions = [], condition = true)
|
||||
@name = name
|
||||
@actions = actions
|
||||
@condition = condition
|
||||
end
|
||||
|
||||
def condition_met?
|
||||
!!@condition
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -6,7 +6,7 @@ module Producer
|
||||
def evaluate(name, env, &block)
|
||||
dsl = new(&block)
|
||||
dsl.evaluate(env)
|
||||
Task.new(name, dsl.actions)
|
||||
Task.new(name, dsl.actions, dsl.condition)
|
||||
end
|
||||
|
||||
def define_action(keyword, klass)
|
||||
@ -22,20 +22,19 @@ module Producer
|
||||
attr_accessor :actions
|
||||
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
@actions = []
|
||||
@block = block
|
||||
@actions = []
|
||||
@condition = true
|
||||
end
|
||||
|
||||
def evaluate(env)
|
||||
@env = env
|
||||
instance_eval &@block
|
||||
rescue ConditionNotMetError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def condition(&block)
|
||||
fail ConditionNotMetError unless block.call
|
||||
@condition = Condition.evaluate(@env, &block) if block
|
||||
@condition
|
||||
end
|
||||
end
|
||||
end
|
||||
|
47
spec/producer/core/condition/dsl_spec.rb
Normal file
47
spec/producer/core/condition/dsl_spec.rb
Normal file
@ -0,0 +1,47 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Producer::Core
|
||||
describe Condition::DSL do
|
||||
let(:block) { proc { :some_condition_code } }
|
||||
let(:env) { double('env') }
|
||||
subject(:dsl) { Condition::DSL.new(&block) }
|
||||
|
||||
describe '.evaluate' do
|
||||
it 'builds a new DSL sandbox with given code' do
|
||||
expect(Condition::DSL).to receive(:new).with(&block).and_call_original
|
||||
Condition::DSL.evaluate(env, &block)
|
||||
end
|
||||
|
||||
it 'evaluates the DSL sandbox code' do
|
||||
dsl = double('dsl')
|
||||
allow(Condition::DSL).to receive(:new) { dsl }
|
||||
expect(dsl).to receive(:evaluate)
|
||||
Condition::DSL.evaluate(env, &block)
|
||||
end
|
||||
|
||||
it 'builds a condition with value returned from DSL evaluation' do
|
||||
expect(Condition)
|
||||
.to receive(:new).with(dsl.evaluate)
|
||||
Condition::DSL.evaluate(env, &block)
|
||||
end
|
||||
|
||||
it 'returns the condition' do
|
||||
condition = double('task')
|
||||
allow(Condition).to receive(:new) { condition }
|
||||
expect(Condition::DSL.evaluate(env, &block)).to be condition
|
||||
end
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'assigns the code' do
|
||||
expect(dsl.instance_eval { @block }).to be block
|
||||
end
|
||||
end
|
||||
|
||||
describe '#evaluate' do
|
||||
it 'returns the value returned by the assigned block' do
|
||||
expect(dsl.evaluate).to eq block.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
39
spec/producer/core/condition_spec.rb
Normal file
39
spec/producer/core/condition_spec.rb
Normal file
@ -0,0 +1,39 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Producer::Core
|
||||
describe Condition do
|
||||
let(:expression) { double('expression') }
|
||||
let(:condition) { Condition.new(expression) }
|
||||
|
||||
describe '.evaluate' do
|
||||
let(:env) { double('env') }
|
||||
let(:block) { proc { :some_condition_code } }
|
||||
|
||||
it 'delegates to DSL.evaluate' do
|
||||
expect(Condition::DSL)
|
||||
.to receive(:evaluate).with(env) do |&b|
|
||||
expect(b.call).to eq :some_condition_code
|
||||
end
|
||||
Condition.evaluate(env, &block)
|
||||
end
|
||||
|
||||
it 'returns the evaluated condition' do
|
||||
condition = double('condition')
|
||||
allow(Condition::DSL).to receive(:evaluate) { condition }
|
||||
expect(Condition.evaluate(env, &block)).to be condition
|
||||
end
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'assigns the expression' do
|
||||
expect(condition.instance_eval { @expression }).to be expression
|
||||
end
|
||||
end
|
||||
|
||||
describe '#!' do
|
||||
it 'returns the negated expression' do
|
||||
expect(condition.!).to be !expression
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -12,12 +12,29 @@ module Producer::Core
|
||||
end
|
||||
|
||||
describe '#process_task' do
|
||||
it 'applies the task actions' do
|
||||
action = double('action')
|
||||
task = double('task')
|
||||
let(:action) { double('action') }
|
||||
let(:task) { double('task').as_null_object }
|
||||
|
||||
before do
|
||||
allow(task).to receive(:actions) { [action] }
|
||||
expect(action).to receive(:apply)
|
||||
interpreter.process_task(task)
|
||||
end
|
||||
|
||||
context 'when task condition is met' do
|
||||
it 'applies the actions' do
|
||||
expect(action).to receive(:apply)
|
||||
interpreter.process_task(task)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when task condition is not met' do
|
||||
before do
|
||||
allow(task).to receive(:condition_met?) { false }
|
||||
end
|
||||
|
||||
it 'does not apply the actions' do
|
||||
expect(action).not_to receive(:apply)
|
||||
interpreter.process_task(task)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -27,11 +27,13 @@ module Producer::Core
|
||||
Task::DSL.evaluate(name, env, &block)
|
||||
end
|
||||
|
||||
it 'builds a task with its name and registered actions' do
|
||||
it 'builds a task with its name, actions and condition' do
|
||||
dsl = double('dsl').as_null_object
|
||||
allow(Task::DSL).to receive(:new) { dsl }
|
||||
allow(dsl).to receive(:actions) { [:some_action]}
|
||||
expect(Task).to receive(:new).with(:some_task, [:some_action])
|
||||
allow(dsl).to receive(:actions) { [:some_action] }
|
||||
allow(dsl).to receive(:condition) { :some_condition }
|
||||
expect(Task)
|
||||
.to receive(:new).with(:some_task, [:some_action], :some_condition)
|
||||
Task::DSL.evaluate(name, env, &block)
|
||||
end
|
||||
|
||||
@ -53,6 +55,10 @@ module Producer::Core
|
||||
it 'assigns no action' do
|
||||
expect(dsl.actions).to be_empty
|
||||
end
|
||||
|
||||
it 'assigns true as the condition' do
|
||||
expect(dsl.instance_eval { @condition }).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#actions' do
|
||||
@ -89,27 +95,35 @@ module Producer::Core
|
||||
end
|
||||
end
|
||||
|
||||
describe '#condition' do
|
||||
context 'when met (block evals to true)' do
|
||||
let(:block) { proc {
|
||||
condition { true }
|
||||
throw :after_condition
|
||||
} }
|
||||
context 'DSL specific methods' do
|
||||
subject(:dsl) { Task::DSL.new(&block).evaluate(env) }
|
||||
|
||||
it 'evaluates all the block' do
|
||||
expect { dsl.evaluate(env) }
|
||||
.to throw_symbol :after_condition
|
||||
describe '#condition' do
|
||||
context 'when a block is given' do
|
||||
let(:block) { proc { condition { :some_value } } }
|
||||
|
||||
it 'builds a new evaluated condition' do
|
||||
expect(Condition)
|
||||
.to receive(:evaluate).with(env) do |&b|
|
||||
expect(b.call).to eq :some_value
|
||||
end
|
||||
dsl
|
||||
end
|
||||
|
||||
it 'assigns the new condition' do
|
||||
condition = double('condition').as_null_object
|
||||
allow(Condition).to receive(:evaluate) { condition }
|
||||
expect(dsl.condition).to be condition
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not met (block evals to false)' do
|
||||
let(:block) { proc {
|
||||
condition { false }
|
||||
throw :after_condition
|
||||
} }
|
||||
|
||||
it 'stops block evaluation' do
|
||||
expect { dsl.evaluate(env) }.not_to throw_symbol :after_condition
|
||||
describe '#condition' do
|
||||
context 'without block' do
|
||||
it 'returns the assigned condition' do
|
||||
dsl.instance_eval { @condition = :some_condition }
|
||||
expect(dsl.condition).to be :some_condition
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -4,7 +4,8 @@ module Producer::Core
|
||||
describe Task do
|
||||
let(:name) { :some_task }
|
||||
let(:action) { double('action') }
|
||||
subject(:task) { Task.new(name, [action]) }
|
||||
let(:condition) { double('condition') }
|
||||
subject(:task) { Task.new(name, [action], condition) }
|
||||
|
||||
describe '.evaluate' do
|
||||
let(:env) { double('env') }
|
||||
@ -34,12 +35,20 @@ module Producer::Core
|
||||
expect(task.instance_eval { @actions }).to eq [action]
|
||||
end
|
||||
|
||||
it 'assigns the condition' do
|
||||
expect(task.instance_eval { @condition }).to eq condition
|
||||
end
|
||||
|
||||
context 'when only the name is given as argument' do
|
||||
subject(:task) { Task.new(name) }
|
||||
|
||||
it 'assigns no action' do
|
||||
expect(task.actions).to be_empty
|
||||
end
|
||||
|
||||
it 'assigns a truthy condition' do
|
||||
expect(task.condition).to be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -54,5 +63,29 @@ module Producer::Core
|
||||
expect(task.actions).to eq [action]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#condition' do
|
||||
it 'returns the assigned condition' do
|
||||
expect(task.condition).to be condition
|
||||
end
|
||||
end
|
||||
|
||||
describe '#condition_met?' do
|
||||
context 'when condition is truthy' do
|
||||
let(:condition) { Condition.new(true) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(task.condition_met?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when condition is falsy' do
|
||||
let(:condition) { Condition.new(false) }
|
||||
|
||||
it 'returns false' do
|
||||
expect(task.condition_met?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user