Merge Condition::DSL into Condition

This commit is contained in:
Thibault Jouan 2014-09-22 19:42:14 +00:00
parent 2c335b2437
commit 3b28045340
7 changed files with 145 additions and 197 deletions

View File

@ -14,7 +14,7 @@ require 'producer/core/actions/file_append'
require 'producer/core/actions/file_replace_content' require 'producer/core/actions/file_replace_content'
require 'producer/core/actions/file_writer' require 'producer/core/actions/file_writer'
# condition tests (need to be defined before the condition DSL) # condition tests
require 'producer/core/test' require 'producer/core/test'
require 'producer/core/tests/condition_test' require 'producer/core/tests/condition_test'
require 'producer/core/tests/file_contains' require 'producer/core/tests/file_contains'
@ -27,7 +27,6 @@ require 'producer/core/tests/shell_command_status'
require 'producer/core/cli' require 'producer/core/cli'
require 'producer/core/condition' require 'producer/core/condition'
require 'producer/core/condition/dsl'
require 'producer/core/env' require 'producer/core/env'
require 'producer/core/errors' require 'producer/core/errors'
require 'producer/core/logger_formatter' require 'producer/core/logger_formatter'

View File

@ -2,16 +2,45 @@ module Producer
module Core module Core
class Condition class Condition
class << self class << self
def define_test(keyword, test)
{
keyword => false,
"no_#{keyword}" => true
}.each do |kw, negated|
define_method(kw) do |*args|
if test.respond_to? :call
args = [test, *args]
klass = Tests::ConditionTest
else
klass = test
end
t = klass.new(@env, *args, negated: negated)
@tests << t
end
end
end
def evaluate(env, *args, &block) def evaluate(env, *args, &block)
dsl = DSL.new(env, &block) new.tap do |o|
return_value = dsl.evaluate *args o.instance_eval { @env = env }
Condition.new(dsl.tests, return_value) return_value = o.instance_exec *args, &block
o.instance_eval { @return_value = return_value }
end end
end end
end
define_test :`, Tests::ShellCommandStatus
define_test :sh, Tests::ShellCommandStatus
define_test :file_contains, Tests::FileContains
define_test :file_eq, Tests::FileEq
define_test :env?, Tests::HasEnv
define_test :executable?, Tests::HasExecutable
define_test :dir?, Tests::HasDir
define_test :file?, Tests::HasFile
attr_reader :tests, :return_value attr_reader :tests, :return_value
def initialize(tests, return_value = nil) def initialize(tests = [], return_value = nil)
@tests = tests @tests = tests
@return_value = return_value @return_value = return_value
end end

View File

@ -1,48 +0,0 @@
module Producer
module Core
class Condition
class DSL
class << self
def define_test(keyword, test)
{
keyword => false,
"no_#{keyword}" => true
}.each do |kw, negated|
define_method(kw) do |*args|
if test.respond_to? :call
args = [test, *args]
klass = Tests::ConditionTest
else
klass = test
end
t = klass.new(@env, *args, negated: negated)
@tests << t
end
end
end
end
define_test :`, Tests::ShellCommandStatus
define_test :sh, Tests::ShellCommandStatus
define_test :file_contains, Tests::FileContains
define_test :file_eq, Tests::FileEq
define_test :env?, Tests::HasEnv
define_test :executable?, Tests::HasExecutable
define_test :dir?, Tests::HasDir
define_test :file?, Tests::HasFile
attr_reader :block, :env, :tests
def initialize(env, &block)
@env = env
@block = block
@tests = []
end
def evaluate(*args)
instance_exec *args, &@block
end
end
end
end
end

View File

@ -32,7 +32,7 @@ module Producer
end end
end end
def test_macro(name, dsl: Condition::DSL, &block) def test_macro(name, dsl: Condition, &block)
dsl.define_test(name, block) dsl.define_test(name, block)
end end

View File

@ -1,116 +0,0 @@
require 'spec_helper'
module Producer::Core
class Condition
describe DSL do
let(:block) { proc { :some_condition_code } }
let(:env) { double 'env' }
subject(:dsl) { DSL.new(env, &block) }
%w[
`
sh
file_contains
file_eq
dir?
env?
executable?
file?
].each do |test|
it "has `#{test}' test defined" do
expect(dsl).to respond_to test.to_sym
end
end
describe '.define_test' do
let(:some_test) { Test }
before { described_class.define_test(:some_test, some_test) }
it 'defines a new test keyword' do
expect(dsl).to respond_to :some_test
end
it 'defines the negated test' do
expect(dsl).to respond_to :no_some_test
end
context 'when a test keyword is called' do
it 'registers the test' do
expect { dsl.some_test }.to change { dsl.tests.count }.by 1
end
it 'registers the test with current env' do
dsl.some_test
expect(dsl.tests.last.env).to be env
end
it 'registers the test with given arguments' do
dsl.some_test :some, :args
expect(dsl.tests.last.arguments).to eq [:some, :args]
end
context 'when given test is callable' do
let(:some_test) { proc {} }
before { dsl.some_test }
it 'registers a condition test' do
expect(dsl.tests.last).to be_a Tests::ConditionTest
end
it 'registers the test with given block' do
expect(dsl.tests.last.condition_block).to be some_test
end
it 'registers the test with given arguments' do
dsl.some_test :some, :args
expect(dsl.tests.last.condition_args).to eq [:some, :args]
end
end
end
context 'when a negated test keyword is called' do
it 'registers a negated test' do
dsl.no_some_test
expect(dsl.tests.last).to be_negated
end
end
end
describe '#initialize' do
it 'assigns the env' do
expect(dsl.env).to be env
end
it 'assigns the code' do
expect(dsl.block).to be block
end
it 'assigns no test' do
expect(dsl.tests).to be_empty
end
end
describe '#evaluate' do
it 'evaluates its code' do
dsl = described_class.new(env) { throw :condition_code }
expect { dsl.evaluate }.to throw_symbol :condition_code
end
it 'returns the value returned by the assigned block' do
expect(dsl.evaluate).to eq block.call
end
context 'when arguments are given' do
let(:block) { proc { |e| throw e } }
it 'passes arguments as block parameters' do
expect { dsl.evaluate :some_argument }
.to throw_symbol :some_argument
end
end
end
end
end
end

View File

@ -2,45 +2,128 @@ require 'spec_helper'
module Producer::Core module Producer::Core
describe Condition do describe Condition do
let(:test_ok) { double 'test', pass?: true } subject(:condition) { described_class.new }
let(:test_ko) { double 'test', pass?: false }
let(:tests) { [test_ok, test_ko] } %w[
subject(:condition) { Condition.new(tests) } `
sh
file_contains
file_eq
dir?
env?
executable?
file?
].each do |test|
it "has `#{test}' test defined" do
expect(condition).to respond_to test.to_sym
end
end
describe '.define_test' do
let(:some_test) { Test }
before { described_class.define_test(:some_test, some_test) }
it 'defines a new test keyword' do
expect(condition).to respond_to :some_test
end
it 'defines the negated test' do
expect(condition).to respond_to :no_some_test
end
context 'when a test keyword is called' do
it 'registers the test' do
expect { condition.some_test }.to change { condition.tests.count }.by 1
end
it 'registers the test with assigned env' do
env = double 'env'
condition.instance_eval { @env = env }
condition.some_test
expect(condition.tests.last.env).to be env
end
it 'registers the test with given arguments' do
condition.some_test :foo, :bar
expect(condition.tests.last.arguments).to eq %i[foo bar]
end
context 'when given test is callable' do
let(:some_test) { proc { } }
before { condition.some_test }
it 'registers a condition test' do
expect(condition.tests.last).to be_a Tests::ConditionTest
end
it 'registers the test with given block' do
expect(condition.tests.last.condition_block).to be some_test
end
it 'registers the test with given arguments' do
condition.some_test :foo, :bar
expect(condition.tests.last.condition_args).to eq %i[foo bar]
end
end
end
context 'when a negated test keyword is called' do
it 'registers a negated test' do
condition.no_some_test
expect(condition.tests.last).to be_negated
end
end
end
describe '.evaluate' do describe '.evaluate' do
let(:env) { double 'env' } let(:env) { double 'env' }
let(:block) { proc { some_test; :some_return_value } } let(:code) { proc { some_test; :some_return_value } }
let(:some_test_class) { Class.new(Test) } let(:some_test) { Class.new(Test) }
subject(:condition) { described_class.evaluate(env, &block) } let(:arguments) { [] }
subject(:condition) { described_class.evaluate(env, *arguments, &code) }
before { Condition::DSL.define_test(:some_test, some_test_class) } before { described_class.define_test(:some_test, some_test) }
it 'returns an evaluated condition' do it 'returns an evaluated condition' do
expect(condition).to be_a Condition
end
it 'evaluates the condition tests' do
expect(condition.tests.first).to be_a Test expect(condition.tests.first).to be_a Test
end
it 'evaluates the condition return value' do
expect(condition.return_value).to eq :some_return_value expect(condition.return_value).to eq :some_return_value
end end
context 'when arguments are given' do
let(:code) { proc { |a, b| throw a } }
let(:arguments) { %i[foo bar] }
it 'passes arguments as block parameters' do
expect { condition }
.to throw_symbol :foo
end
end
end end
describe '#initialize' do describe '#initialize' do
it 'assigns the tests' do it 'assigns no tests' do
expect(condition.tests).to eq tests expect(condition.tests).to be_empty
end end
it 'assigns nil as a default return value' do it 'assigns the return value as nil' do
expect(condition.return_value).to be nil expect(condition.return_value).to be nil
end end
context 'when a return value is given as argument' do
let(:return_value) { :some_return_value }
subject(:condition) { described_class.new(tests, return_value) }
it 'assigns the return value' do
expect(condition.return_value).to eq return_value
end
end
end end
describe '#met?' do describe '#met?' do
let(:test_ok) { instance_spy Test, pass?: true }
let(:test_ko) { instance_spy Test, pass?: false }
subject(:condition) { described_class.new(tests) }
context 'when all tests are successful' do context 'when all tests are successful' do
let(:tests) { [test_ok, test_ok] } let(:tests) { [test_ok, test_ok] }
@ -58,6 +141,7 @@ module Producer::Core
end end
context 'when there are no test' do context 'when there are no test' do
let(:tests) { [] }
subject(:condition) { described_class.new([], return_value) } subject(:condition) { described_class.new([], return_value) }
context 'and return value is truthy' do context 'and return value is truthy' do

View File

@ -74,7 +74,7 @@ module Producer::Core
describe '#test_macro' do describe '#test_macro' do
it 'defines the new test' do it 'defines the new test' do
recipe.test_macro(:some_test) { } recipe.test_macro(:some_test) { }
expect(Condition::DSL.new(env)).to respond_to :some_test expect(Condition.new).to respond_to :some_test
end end
end end