Merge Recipe::DSL into Recipe

This commit is contained in:
Thibault Jouan 2014-09-22 13:13:03 +00:00
parent 4c0077d14d
commit 166dae681c
8 changed files with 150 additions and 226 deletions

View File

@ -33,7 +33,7 @@ require 'producer/core/errors'
require 'producer/core/logger_formatter'
require 'producer/core/prompter'
require 'producer/core/recipe'
require 'producer/core/recipe/dsl'
require 'producer/core/recipe/file_evaluator'
require 'producer/core/remote'
require 'producer/core/remote/environment'
require 'producer/core/remote/fs'

View File

@ -58,7 +58,7 @@ module Producer
end
def recipe
@recipe ||= Recipe.evaluate_from_file(@arguments.first, env)
@recipe ||= Recipe::FileEvaluator.evaluate(@arguments.first, env)
end
end
end

View File

@ -2,16 +2,46 @@ module Producer
module Core
class Recipe
class << self
def evaluate_from_file(filepath, env)
dsl = DSL.new(env, File.read(filepath)).evaluate
Recipe.new(dsl.tasks)
def define_macro(name, block)
define_method(name) { |*args| task name, *args, &block }
end
end
attr_accessor :tasks
attr_reader :env, :tasks
def initialize(tasks = [])
@tasks = tasks
def initialize(env)
@env = env
@tasks = []
end
def source(filepath)
instance_eval File.read("./#{filepath}.rb"), "#{filepath}.rb"
end
def target(hostname)
env.target ||= hostname
end
def task(name, *args, &block)
@tasks << Task.evaluate(name, env, *args, &block)
end
def macro(name, &block)
define_singleton_method(name) do |*args|
task("#{name}", *args, &block)
end
end
def test_macro(name, dsl: Condition::DSL, &block)
dsl.define_test(name, block)
end
def set(key, value)
env[key] = value
end
def get(key)
env[key]
end
end
end

View File

@ -1,61 +0,0 @@
module Producer
module Core
class Recipe
class DSL
class << self
def define_macro(name, block)
define_method(name) { |*args| task name, *args, &block }
end
end
attr_reader :env, :code, :block, :tasks
def initialize(env, code = nil, &block)
@env = env
@code = code
@block = block
@tasks = []
end
def evaluate
if @code
instance_eval @code
else
instance_eval &@block
end
self
end
def source(filepath)
instance_eval File.read("./#{filepath}.rb"), "#{filepath}.rb"
end
def target(hostname)
env.target ||= hostname
end
def task(name, *args, &block)
@tasks << Task.evaluate(name, env, *args, &block)
end
def macro(name, &block)
define_singleton_method(name) do |*args|
task("#{name}", *args, &block)
end
end
def test_macro(name, dsl: Condition::DSL, &block)
dsl.define_test(name, block)
end
def set(key, value)
env[key] = value
end
def get(key)
env[key]
end
end
end
end
end

View File

@ -0,0 +1,14 @@
module Producer
module Core
class Recipe
class FileEvaluator
class << self
def evaluate(file_path, env)
content = File.read(file_path)
Recipe.new(env).tap { |o| o.instance_eval content, file_path }
end
end
end
end
end
end

View File

@ -1,140 +0,0 @@
require 'spec_helper'
module Producer::Core
class Recipe
describe DSL do
include FixturesHelpers
let(:code) { proc { :some_recipe_code } }
let(:env) { Env.new }
subject(:dsl) { DSL.new(env, &code) }
describe '#initialize' do
it 'assigns the given env' do
expect(dsl.env).to be env
end
it 'assigns no task' do
expect(dsl.tasks).to be_empty
end
context 'when a string of code is given as argument' do
let(:code) { 'some_code' }
subject(:dsl) { described_class.new(env, code) }
it 'assigns the string of code' do
expect(dsl.code).to eq code
end
end
context 'when a code block is given as argument' do
it 'assigns the code block' do
expect(dsl.block).to be code
end
end
end
describe '#tasks' do
let(:code) { proc { task(:some_task) {} } }
it 'returns registered tasks' do
dsl.evaluate
expect(dsl.tasks[0].name).to eq :some_task
end
end
describe '#evaluate' do
it 'evaluates its code' do
dsl = described_class.new(env) { throw :recipe_code }
expect { dsl.evaluate }.to throw_symbol :recipe_code
end
it 'returns itself' do
expect(dsl.evaluate).to eq dsl
end
end
describe '#source' do
let(:filepath) { fixture_path_for 'recipes/throw' }
it 'sources the recipe given as argument' do
expect { dsl.source filepath }.to throw_symbol :recipe_code
end
end
describe '#target' do
let(:host) { 'some_host.example' }
context 'when env has no assigned target' do
it 'registers the target host in the env' do
dsl.target host
expect(env.target).to eq host
end
end
context 'when env has an assigned target' do
before { env.target = 'already_assigned_host.example' }
it 'does not change env target' do
expect { dsl.target host }.not_to change { env.target }
end
end
end
describe '#task' do
it 'registers a new evaluated task' do
expect { dsl.task(:some_task) { :some_task_code } }
.to change { dsl.tasks.count }.by 1
end
end
describe '#macro' do
it 'defines the new recipe keyword' do
dsl.macro :hello
expect(dsl).to respond_to(:hello)
end
context 'when a defined macro is called' do
before { dsl.macro(:hello) { :some_macro_code } }
it 'registers the new task' do
expect { dsl.hello }.to change { dsl.tasks.count }.by 1
end
end
context 'when a defined macro is called with arguments' do
before { dsl.macro(:hello) { |a, b| echo a, b } }
it 'evaluates task code with arguments' do
dsl.hello :some, :args
expect(dsl.tasks.first.actions.first.arguments).to eq [:some, :args]
end
end
end
describe '#test_macro' do
it 'defines the new test' do
condition_dsl = double 'condition dsl'
test_block = proc {}
expect(condition_dsl)
.to receive(:define_test).with(:some_test, test_block)
dsl.test_macro(:some_test, dsl: condition_dsl, &test_block)
end
end
describe '#set' do
it 'registers a key/value pair in env registry' do
dsl.set :some_key, :some_value
expect(env[:some_key]).to eq :some_value
end
end
describe '#get' do
it 'fetches a value from the registry at given index' do
dsl.set :some_key, :some_value
expect(dsl.get :some_key).to eq :some_value
end
end
end
end
end

View File

@ -0,0 +1,22 @@
require 'spec_helper'
module Producer::Core
class Recipe
describe FileEvaluator do
include FixturesHelpers
describe '.evaluate' do
let(:env) { Env.new }
let(:file_path) { fixture_path_for 'recipes/some_recipe.rb' }
subject(:recipe) { described_class.evaluate(file_path, env) }
it 'returns an evaluated recipe' do
expect(recipe.tasks).to match [
an_object_having_attributes(name: :some_task),
an_object_having_attributes(name: :another_task)
]
end
end
end
end
end

View File

@ -4,33 +4,92 @@ module Producer::Core
describe Recipe do
include FixturesHelpers
subject(:recipe) { Recipe.new }
let(:env) { Env.new }
subject(:recipe) { described_class.new(env) }
describe '.evaluate_from_file' do
let(:env) { double 'env' }
let(:filepath) { fixture_path_for 'recipes/some_recipe.rb' }
subject(:recipe) { Recipe.evaluate_from_file(filepath, env) }
it 'returns an evaluated recipe' do
expect(recipe.tasks.map(&:name)).to eq [:some_task, :another_task]
describe '#initialize' do
it 'assigns no task' do
expect(recipe.tasks).to be_empty
end
end
describe '#initialize' do
context 'without arguments' do
it 'assigns no task' do
expect(recipe.tasks).to be_empty
describe '#source' do
let(:filepath) { fixture_path_for 'recipes/throw' }
it 'sources the recipe given as argument' do
expect { recipe.source filepath }.to throw_symbol :recipe_code
end
end
describe '#target' do
let(:host) { 'some_host.example' }
context 'when env has no assigned target' do
it 'registers the target host in the env' do
recipe.target host
expect(env.target).to eq host
end
end
context 'when tasks are given as argument' do
let(:tasks) { [double('task')] }
subject(:recipe) { Recipe.new(tasks) }
context 'when env has an assigned target' do
before { env.target = 'already_assigned_host.example' }
it 'assigns the tasks' do
expect(recipe.tasks).to eq tasks
it 'does not change env target' do
expect { recipe.target host }.not_to change { env.target }
end
end
end
describe '#task' do
it 'registers a new evaluated task' do
expect { recipe.task(:some_task) { :some_task_code } }
.to change { recipe.tasks.count }.by 1
end
end
describe '#macro' do
it 'defines the new recipe keyword' do
recipe.macro :hello
expect(recipe).to respond_to(:hello)
end
context 'when a defined macro is called' do
before { recipe.macro(:hello) { :some_macro_code } }
it 'registers the new task' do
expect { recipe.hello }.to change { recipe.tasks.count }.by 1
end
end
context 'when a defined macro is called with arguments' do
before { recipe.macro(:hello) { |a, b| echo a, b } }
it 'evaluates task code with given arguments' do
recipe.hello :foo, :bar
expect(recipe.tasks.first.actions.first.arguments).to eq %i[foo bar]
end
end
end
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
end
end
describe '#set' do
it 'registers a key/value pair in env registry' do
recipe.set :some_key, :some_value
expect(env[:some_key]).to eq :some_value
end
end
describe '#get' do
it 'fetches a value from the registry at given index' do
recipe.set :some_key, :some_value
expect(recipe.get :some_key).to eq :some_value
end
end
end
end