From 3b2804534042eebc23125994f029eb313624950c Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Mon, 22 Sep 2014 19:42:14 +0000 Subject: [PATCH] Merge Condition::DSL into Condition --- lib/producer/core.rb | 3 +- lib/producer/core/condition.rb | 37 ++++++- lib/producer/core/condition/dsl.rb | 48 -------- lib/producer/core/recipe.rb | 2 +- spec/producer/core/condition/dsl_spec.rb | 116 -------------------- spec/producer/core/condition_spec.rb | 134 ++++++++++++++++++----- spec/producer/core/recipe_spec.rb | 2 +- 7 files changed, 145 insertions(+), 197 deletions(-) delete mode 100644 lib/producer/core/condition/dsl.rb delete mode 100644 spec/producer/core/condition/dsl_spec.rb diff --git a/lib/producer/core.rb b/lib/producer/core.rb index 10758ee..6eb8bee 100644 --- a/lib/producer/core.rb +++ b/lib/producer/core.rb @@ -14,7 +14,7 @@ require 'producer/core/actions/file_append' require 'producer/core/actions/file_replace_content' 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/tests/condition_test' require 'producer/core/tests/file_contains' @@ -27,7 +27,6 @@ require 'producer/core/tests/shell_command_status' require 'producer/core/cli' require 'producer/core/condition' -require 'producer/core/condition/dsl' require 'producer/core/env' require 'producer/core/errors' require 'producer/core/logger_formatter' diff --git a/lib/producer/core/condition.rb b/lib/producer/core/condition.rb index c77b522..0270b8b 100644 --- a/lib/producer/core/condition.rb +++ b/lib/producer/core/condition.rb @@ -2,16 +2,45 @@ module Producer module Core class Condition 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) - dsl = DSL.new(env, &block) - return_value = dsl.evaluate *args - Condition.new(dsl.tests, return_value) + new.tap do |o| + o.instance_eval { @env = env } + return_value = o.instance_exec *args, &block + o.instance_eval { @return_value = return_value } + 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 - def initialize(tests, return_value = nil) + def initialize(tests = [], return_value = nil) @tests = tests @return_value = return_value end diff --git a/lib/producer/core/condition/dsl.rb b/lib/producer/core/condition/dsl.rb deleted file mode 100644 index 19fb07c..0000000 --- a/lib/producer/core/condition/dsl.rb +++ /dev/null @@ -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 diff --git a/lib/producer/core/recipe.rb b/lib/producer/core/recipe.rb index 60704f8..f3a165f 100644 --- a/lib/producer/core/recipe.rb +++ b/lib/producer/core/recipe.rb @@ -32,7 +32,7 @@ module Producer end end - def test_macro(name, dsl: Condition::DSL, &block) + def test_macro(name, dsl: Condition, &block) dsl.define_test(name, block) end diff --git a/spec/producer/core/condition/dsl_spec.rb b/spec/producer/core/condition/dsl_spec.rb deleted file mode 100644 index 1866f13..0000000 --- a/spec/producer/core/condition/dsl_spec.rb +++ /dev/null @@ -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 diff --git a/spec/producer/core/condition_spec.rb b/spec/producer/core/condition_spec.rb index dc9713e..f39e3e2 100644 --- a/spec/producer/core/condition_spec.rb +++ b/spec/producer/core/condition_spec.rb @@ -2,45 +2,128 @@ require 'spec_helper' module Producer::Core describe Condition do - let(:test_ok) { double 'test', pass?: true } - let(:test_ko) { double 'test', pass?: false } - let(:tests) { [test_ok, test_ko] } - subject(:condition) { Condition.new(tests) } + subject(:condition) { described_class.new } - describe '.evaluate' do - let(:env) { double 'env' } - let(:block) { proc { some_test; :some_return_value } } - let(:some_test_class) { Class.new(Test) } - subject(:condition) { described_class.evaluate(env, &block) } - - before { Condition::DSL.define_test(:some_test, some_test_class) } - - it 'returns an evaluated condition' do - expect(condition.tests.first).to be_a Test - expect(condition.return_value).to eq :some_return_value + %w[ + ` + 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 '#initialize' do - it 'assigns the tests' do - expect(condition.tests).to eq tests + 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 'assigns nil as a default return value' do - expect(condition.return_value).to be nil + it 'defines the negated test' do + expect(condition).to respond_to :no_some_test 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) } + 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 'assigns the return value' do - expect(condition.return_value).to eq return_value + 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 + let(:env) { double 'env' } + let(:code) { proc { some_test; :some_return_value } } + let(:some_test) { Class.new(Test) } + let(:arguments) { [] } + subject(:condition) { described_class.evaluate(env, *arguments, &code) } + + before { described_class.define_test(:some_test, some_test) } + + 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 + end + + it 'evaluates the condition return value' do + expect(condition.return_value).to eq :some_return_value + 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 + + describe '#initialize' do + it 'assigns no tests' do + expect(condition.tests).to be_empty + end + + it 'assigns the return value as nil' do + expect(condition.return_value).to be nil + end + end + 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 let(:tests) { [test_ok, test_ok] } @@ -58,6 +141,7 @@ module Producer::Core end context 'when there are no test' do + let(:tests) { [] } subject(:condition) { described_class.new([], return_value) } context 'and return value is truthy' do diff --git a/spec/producer/core/recipe_spec.rb b/spec/producer/core/recipe_spec.rb index 2f086a9..c5c8901 100644 --- a/spec/producer/core/recipe_spec.rb +++ b/spec/producer/core/recipe_spec.rb @@ -74,7 +74,7 @@ module Producer::Core describe '#test_macro' do it 'defines the new test' do 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