Refactor and simplify recipe DSL evaluation usages:
Remove most of recipe evaluation code in Recipe class, and rely on Recipe::DSL to get evaluated recipes. * Remove Recipe#evaluate call from CLI, rely on Recipe.evaluate_from_file to get the evaluated recipe; * Implement Recipe.evaluate_from_file(filepath, env); * Implement Recipe::DSL.evaluate(code, env); * Remove code and filepath accessor on Recipe; * Remove Recipe.from_file and Recipe#evaluate methods; * Move task evaluations in Recipe::DSL#evaluate; * Modify Recipe constructor so that it accepts tasks as argument.
This commit is contained in:
		| @@ -12,7 +12,6 @@ module Producer | ||||
|  | ||||
|       def run! | ||||
|         check_arguments! | ||||
|         recipe.evaluate(env) | ||||
|         worker.process recipe.tasks | ||||
|       end | ||||
|  | ||||
| @@ -25,7 +24,7 @@ module Producer | ||||
|       end | ||||
|  | ||||
|       def recipe | ||||
|         @recipe ||= Recipe.from_file(@arguments.first) | ||||
|         @recipe ||= Recipe.evaluate_from_file(@arguments.first, env) | ||||
|       end | ||||
|  | ||||
|       def worker | ||||
|   | ||||
| @@ -1,22 +1,14 @@ | ||||
| module Producer | ||||
|   module Core | ||||
|     class Recipe | ||||
|       attr_reader :code, :filepath, :tasks | ||||
|       attr_accessor :tasks | ||||
|  | ||||
|       def self.from_file(filepath) | ||||
|         new(File.read(filepath), filepath) | ||||
|       def self.evaluate_from_file(filepath, env) | ||||
|         DSL.evaluate(File.read(filepath), env) | ||||
|       end | ||||
|  | ||||
|       def initialize(code, filepath = nil) | ||||
|         @code     = code | ||||
|         @filepath = filepath | ||||
|         @tasks    = [] | ||||
|       end | ||||
|  | ||||
|       def evaluate(env) | ||||
|         dsl = DSL.new(@code).evaluate(env) | ||||
|         dsl.tasks.map { |e| e.evaluate env } | ||||
|         @tasks = dsl.tasks | ||||
|       def initialize(tasks = []) | ||||
|         @tasks = tasks | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -4,6 +4,11 @@ module Producer | ||||
|       class DSL | ||||
|         attr_reader :tasks | ||||
|  | ||||
|         def self.evaluate(code, env) | ||||
|           dsl = new(code).evaluate(env) | ||||
|           Recipe.new(dsl.tasks) | ||||
|         end | ||||
|  | ||||
|         def initialize(code = nil, &block) | ||||
|           @code   = code | ||||
|           @block  = block | ||||
| @@ -17,6 +22,7 @@ module Producer | ||||
|           else | ||||
|             instance_eval &@block | ||||
|           end | ||||
|           @tasks.each { |e| e.evaluate env } | ||||
|           self | ||||
|         end | ||||
|  | ||||
|   | ||||
| @@ -27,11 +27,6 @@ module Producer::Core | ||||
|         cli.run! | ||||
|       end | ||||
|  | ||||
|       it 'evaluates the recipe with the environment' do | ||||
|         expect(cli.recipe).to receive(:evaluate).with(cli.env) | ||||
|         cli.run! | ||||
|       end | ||||
|  | ||||
|       it 'processes the tasks with the worker' do | ||||
|         allow(cli.recipe).to receive(:tasks) { [:some_task] } | ||||
|         expect(cli.worker).to receive(:process).with([:some_task]) | ||||
| @@ -80,12 +75,12 @@ module Producer::Core | ||||
|     describe '#recipe' do | ||||
|       it 'builds a recipe' do | ||||
|         expect(Recipe) | ||||
|           .to receive(:from_file).with(recipe_file) | ||||
|           .to receive(:evaluate_from_file).with(recipe_file, cli.env) | ||||
|         cli.recipe | ||||
|       end | ||||
|  | ||||
|       it 'returns the recipe' do | ||||
|         recipe = double('recipe') | ||||
|         recipe = double('recipe').as_null_object | ||||
|         allow(Recipe).to receive(:new) { recipe } | ||||
|         expect(cli.recipe).to be recipe | ||||
|       end | ||||
|   | ||||
| @@ -8,6 +8,35 @@ module Producer::Core | ||||
|     let(:env)     { double('env').as_null_object } | ||||
|     subject(:dsl) { Recipe::DSL.new &code } | ||||
|  | ||||
|     describe '.evaluate' do | ||||
|       let(:code) { 'nil' } | ||||
|  | ||||
|       it 'builds a new DSL sandbox with given code' do | ||||
|         expect(Recipe::DSL).to receive(:new).once.with(code).and_call_original | ||||
|         Recipe::DSL.evaluate(code, env) | ||||
|       end | ||||
|  | ||||
|       it 'evaluates the DSL sandbox code with given environment' do | ||||
|         dsl = double('dsl').as_null_object | ||||
|         allow(Recipe::DSL).to receive(:new) { dsl } | ||||
|         expect(dsl).to receive(:evaluate).with(env) | ||||
|         Recipe::DSL.evaluate(code, env) | ||||
|       end | ||||
|  | ||||
|       it 'builds a recipe with evaluated tasks' do | ||||
|         dsl = Recipe::DSL.new('task(:some_task) { }') | ||||
|         allow(Recipe::DSL).to receive(:new) { dsl } | ||||
|         expect(Recipe).to receive(:new).with(dsl.tasks) | ||||
|         Recipe::DSL.evaluate(code, env) | ||||
|       end | ||||
|  | ||||
|       it 'returns the recipe' do | ||||
|         recipe = double('recipe').as_null_object | ||||
|         allow(Recipe).to receive(:new) { recipe } | ||||
|         expect(Recipe::DSL.evaluate(code, env)).to be recipe | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     describe '#initialize' do | ||||
|       it 'assigns no task' do | ||||
|         expect(dsl.instance_eval { @tasks }).to be_empty | ||||
| @@ -30,7 +59,7 @@ module Producer::Core | ||||
|     end | ||||
|  | ||||
|     describe '#tasks' do | ||||
|       let(:code) { proc { task(:some_task) } } | ||||
|       let(:code) { proc { task(:some_task) { } } } | ||||
|  | ||||
|       it 'returns registered tasks' do | ||||
|         dsl.evaluate(env) | ||||
| @@ -44,6 +73,14 @@ module Producer::Core | ||||
|         expect { dsl.evaluate(env) }.to throw_symbol :recipe_code | ||||
|       end | ||||
|  | ||||
|       it 'evaluates the registered tasks' do | ||||
|         task = double('task') | ||||
|         allow(Task).to receive(:new) { task } | ||||
|         dsl = Recipe::DSL.new { task(:some_task) } | ||||
|         expect(task).to receive(:evaluate).with(env) | ||||
|         dsl.evaluate(env) | ||||
|       end | ||||
|  | ||||
|       it 'returns itself' do | ||||
|         expect(dsl.evaluate(env)).to eq dsl | ||||
|       end | ||||
| @@ -81,11 +118,11 @@ module Producer::Core | ||||
|       end | ||||
|  | ||||
|       describe '#task' do | ||||
|         let(:code) { proc { task(:first) { throw :first_task }; task(:last) } } | ||||
|         let(:code) { proc { task(:first) { :some_value }; task(:last) { } } } | ||||
|  | ||||
|         it 'register a task with its code' do | ||||
|           expect(dsl.tasks.first.name).to eq :first | ||||
|           expect { dsl.tasks.first.evaluate(env) }.to throw_symbol :first_task | ||||
|           expect(dsl.tasks.first.instance_eval { @block.call }) | ||||
|             .to eq :some_value | ||||
|         end | ||||
|  | ||||
|         it 'registers tasks in declaration order' do | ||||
|   | ||||
| @@ -4,76 +4,39 @@ module Producer::Core | ||||
|   describe Recipe do | ||||
|     include FixturesHelpers | ||||
|  | ||||
|     let(:code)        { 'nil' } | ||||
|     subject(:recipe)  { Recipe.new(code) } | ||||
|     subject(:recipe) { Recipe.new } | ||||
|  | ||||
|     describe '.from_file' do | ||||
|       let(:filepath)    { fixture_path_for 'recipes/empty.rb' } | ||||
|       subject(:recipe)  { Recipe.from_file(filepath) } | ||||
|     describe '.evaluate_from_file' do | ||||
|       let(:env)       { double('env') } | ||||
|       let(:filepath)  { fixture_path_for 'recipes/empty.rb' } | ||||
|  | ||||
|       it 'builds a recipe whose code is read from given file path' do | ||||
|         expect(recipe.code).to eq File.read(filepath) | ||||
|       it 'delegates to DSL.evaluate with the recipe file content' do | ||||
|         expect(Recipe::DSL) | ||||
|           .to receive(:evaluate).with(File.read(filepath), env) | ||||
|         Recipe.evaluate_from_file(filepath, env) | ||||
|       end | ||||
|  | ||||
|       it 'builds a recipe whose file path is set from given file path' do | ||||
|         expect(recipe.filepath).to eq filepath | ||||
|       it 'returns the evaluated recipe' do | ||||
|         recipe = double('recipe') | ||||
|         allow(Recipe::DSL).to receive(:evaluate) { recipe } | ||||
|         expect(Recipe.evaluate_from_file(filepath, env)).to be recipe | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     describe '#initialize' do | ||||
|       it 'assigns nil as a default filepath' do | ||||
|         expect(recipe.filepath).to be nil | ||||
|       context 'without arguments' do | ||||
|         it 'assigns no task' do | ||||
|           expect(recipe.tasks).to be_empty | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       it 'has no task' do | ||||
|         expect(recipe.tasks).to be_empty | ||||
|       end | ||||
|     end | ||||
|       context 'when tasks are given as argument' do | ||||
|         let(:tasks)   { [Task.new(:some_task)] } | ||||
|         let(:recipe)  { Recipe.new(tasks) } | ||||
|  | ||||
|     describe '#code' do | ||||
|       it 'returns the assigned code' do | ||||
|         expect(recipe.code).to be code | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     describe '#filepath' do | ||||
|       let(:filepath)  { 'some_file_path' } | ||||
|       let(:recipe)    { Recipe.new(code, filepath) } | ||||
|  | ||||
|       it 'returns the assigned file path' do | ||||
|         expect(recipe.filepath).to eq filepath | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     describe '#evaluate' do | ||||
|       let(:env) { double('env').as_null_object } | ||||
|  | ||||
|       it 'builds a recipe DSL sandbox' do | ||||
|         expect(Recipe::DSL).to receive(:new).once.with(code).and_call_original | ||||
|         recipe.evaluate(env) | ||||
|       end | ||||
|  | ||||
|       it 'evaluates the DSL sandbox with the environment given as argument' do | ||||
|         dsl = double('dsl').as_null_object | ||||
|         allow(Recipe::DSL).to receive(:new) { dsl } | ||||
|         expect(dsl).to receive(:evaluate) | ||||
|         recipe.evaluate(env) | ||||
|       end | ||||
|  | ||||
|       it 'evaluates the DSL sandbox tasks' do | ||||
|         task = double('task') | ||||
|         allow(Task).to receive(:new) { task } | ||||
|         dsl = Recipe::DSL.new { task(:some_task) } | ||||
|         allow(Recipe::DSL).to receive(:new) { dsl } | ||||
|         expect(task).to receive(:evaluate).with(env) | ||||
|         recipe.evaluate(env) | ||||
|       end | ||||
|  | ||||
|       it 'assigns the evaluated tasks' do | ||||
|         dsl = Recipe::DSL.new { task(:some_task) { } } | ||||
|         allow(Recipe::DSL).to receive(:new) { dsl } | ||||
|         recipe.evaluate(env) | ||||
|         expect(recipe.tasks.first.name).to eq :some_task | ||||
|         it 'assigns the tasks' do | ||||
|           expect(recipe.tasks).to eq tasks | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user