producer-core 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/features/recipes/ask.feature +22 -0
  3. data/features/steps/recipe_steps.rb +4 -0
  4. data/lib/producer/core.rb +1 -0
  5. data/lib/producer/core/action.rb +2 -2
  6. data/lib/producer/core/cli.rb +1 -2
  7. data/lib/producer/core/condition.rb +2 -0
  8. data/lib/producer/core/condition/dsl.rb +1 -1
  9. data/lib/producer/core/env.rb +4 -2
  10. data/lib/producer/core/prompter.rb +21 -0
  11. data/lib/producer/core/recipe/dsl.rb +1 -3
  12. data/lib/producer/core/remote.rb +1 -1
  13. data/lib/producer/core/remote/environment.rb +3 -1
  14. data/lib/producer/core/remote/fs.rb +2 -0
  15. data/lib/producer/core/task/dsl.rb +5 -1
  16. data/lib/producer/core/test.rb +6 -0
  17. data/lib/producer/core/tests/has_env.rb +1 -1
  18. data/lib/producer/core/tests/has_file.rb +1 -1
  19. data/lib/producer/core/version.rb +1 -1
  20. data/spec/producer/core/action_spec.rb +8 -1
  21. data/spec/producer/core/cli_spec.rb +3 -9
  22. data/spec/producer/core/condition/dsl_spec.rb +32 -40
  23. data/spec/producer/core/condition_spec.rb +15 -31
  24. data/spec/producer/core/env_spec.rb +16 -11
  25. data/spec/producer/core/prompter_spec.rb +41 -0
  26. data/spec/producer/core/recipe/dsl_spec.rb +34 -60
  27. data/spec/producer/core/remote/environment_spec.rb +20 -17
  28. data/spec/producer/core/remote/fs_spec.rb +1 -1
  29. data/spec/producer/core/remote_spec.rb +7 -19
  30. data/spec/producer/core/task/dsl_spec.rb +48 -54
  31. data/spec/producer/core/task_spec.rb +23 -51
  32. data/spec/producer/core/test_spec.rb +14 -14
  33. data/spec/spec_helper.rb +0 -1
  34. metadata +6 -3
  35. data/spec/support/tests_helpers.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c778784a6586dca4a73ef7c76bbb345ed990d3d4
4
- data.tar.gz: 05ae1a88da59938098403eb45a4e98457ef6c68b
3
+ metadata.gz: e6a27039a047e17f8490bd070f3906b435939441
4
+ data.tar.gz: 7f1c4c346f1258e97f59454a6bcf3a20c6e02288
5
5
  SHA512:
6
- metadata.gz: 22156c33ab610cebd1ee5f82c3f6cf60f50f3a3b2c5c7d0a6194d30fcb958635201e34b86af415b3d6885a1d0b3cbeb3c38e52a752f7457626164d37c463d379
7
- data.tar.gz: 8669e86c30cb7a8be71420f85f4280c0a8b67ef61520e5c8c7f37c849a0eedaed3c1184d385ff039c3920aabef6c08f17981f199dfe22c19b133bb21545b0bda
6
+ metadata.gz: 1b84f00106289af7baa8f57ab9aa336eaf2f4a9114a5a7553d5431e83ec8a04b8512ed37657c1599367bd75f41f8f99fabb241eada0c3bf4c9c88c2c5a88bc80
7
+ data.tar.gz: c3ed29fc5633c033e6f35f83d990325d0cdbce10a8a753cbc9f1e7f063795633ad9c465bc322327963ddeb096ec3e0e6c16f6919d2ffef6b753108a52016c7e9
@@ -0,0 +1,22 @@
1
+ Feature: `ask' recipe keyword
2
+
3
+ Scenario: prompts user with a list of choices on standard output
4
+ Given a recipe with:
5
+ """
6
+ task :ask_letter do
7
+ letter = ask 'Which letter?', [[:a, ?A], [:b, ?B]]
8
+
9
+ echo letter.inspect
10
+ end
11
+ """
12
+ When I execute the recipe interactively
13
+ And I type "1"
14
+ Then the output must contain:
15
+ """
16
+ Which letter?
17
+ 0: A
18
+ 1: B
19
+ Choice:
20
+ :b
21
+ """
22
+ And the exit status must be 0
@@ -10,3 +10,7 @@ When(/^I successfully execute the recipe$/) do
10
10
  step 'I execute the recipe'
11
11
  assert_exit_status(0)
12
12
  end
13
+
14
+ When(/^I execute the recipe interactively$/) do
15
+ run_interactive('producer recipe.rb')
16
+ end
data/lib/producer/core.rb CHANGED
@@ -14,6 +14,7 @@ require 'producer/core/condition'
14
14
  require 'producer/core/condition/dsl'
15
15
  require 'producer/core/env'
16
16
  require 'producer/core/errors'
17
+ require 'producer/core/prompter'
17
18
  require 'producer/core/recipe'
18
19
  require 'producer/core/recipe/dsl'
19
20
  require 'producer/core/remote'
@@ -4,10 +4,10 @@ module Producer
4
4
  require 'forwardable'
5
5
 
6
6
  extend Forwardable
7
- def_delegators :@env, :output, :remote
7
+ def_delegators :@env, :input, :output, :remote
8
8
  def_delegators :remote, :fs
9
9
 
10
- attr_accessor :env, :arguments
10
+ attr_reader :env, :arguments
11
11
 
12
12
  def initialize(env, *args)
13
13
  @env = env
@@ -19,8 +19,7 @@ module Producer
19
19
  end
20
20
  end
21
21
 
22
- attr_reader :arguments, :stdout
23
- attr_accessor :recipe
22
+ attr_reader :arguments, :stdout, :recipe
24
23
 
25
24
  def initialize(arguments, stdout: $stdout)
26
25
  raise ArgumentError unless arguments.any?
@@ -9,6 +9,8 @@ module Producer
9
9
  end
10
10
  end
11
11
 
12
+ attr_reader :tests, :return_value
13
+
12
14
  def initialize(tests, return_value = nil)
13
15
  @tests = tests
14
16
  @return_value = return_value
@@ -16,7 +16,7 @@ module Producer
16
16
  define_test :has_env, Tests::HasEnv
17
17
  define_test :has_file, Tests::HasFile
18
18
 
19
- attr_accessor :tests
19
+ attr_reader :block, :env, :tests
20
20
 
21
21
  def initialize(env, &block)
22
22
  @env = env
@@ -1,9 +1,11 @@
1
1
  module Producer
2
2
  module Core
3
3
  class Env
4
- attr_accessor :output, :target
4
+ attr_reader :input, :output
5
+ attr_accessor :target
5
6
 
6
- def initialize(output: $stdout)
7
+ def initialize(input: $stdin, output: $stdout)
8
+ @input = input
7
9
  @output = output
8
10
  @target = nil
9
11
  end
@@ -0,0 +1,21 @@
1
+ module Producer
2
+ module Core
3
+ class Prompter
4
+ attr_reader :input, :output
5
+
6
+ def initialize(input, output)
7
+ @input = input
8
+ @output = output
9
+ end
10
+
11
+ def prompt(question, choices)
12
+ cs = choices.each_with_index.inject('') do |m, (c, i)|
13
+ m += "#{i}: #{c.last}\n"
14
+ end
15
+ output.puts "#{question}\n#{cs}Choice:"
16
+ choice = input.gets
17
+ choices[choice.to_i].first
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,7 +2,7 @@ module Producer
2
2
  module Core
3
3
  class Recipe
4
4
  class DSL
5
- attr_reader :env, :tasks
5
+ attr_reader :env, :code, :block, :tasks
6
6
 
7
7
  def initialize(env, code = nil, &block)
8
8
  @env = env
@@ -20,8 +20,6 @@ module Producer
20
20
  self
21
21
  end
22
22
 
23
- private
24
-
25
23
  def source(filepath)
26
24
  instance_eval File.read("./#{filepath}.rb"), "#{filepath}.rb"
27
25
  end
@@ -4,7 +4,7 @@ module Producer
4
4
  require 'etc'
5
5
  require 'net/ssh'
6
6
 
7
- attr_accessor :hostname
7
+ attr_reader :hostname
8
8
 
9
9
  def initialize(hostname)
10
10
  @hostname = hostname
@@ -15,7 +15,9 @@ module Producer
15
15
  require 'forwardable'
16
16
 
17
17
  extend Forwardable
18
- def_delegator :@variables, :key?
18
+ def_delegators :@variables, :[], :key?
19
+
20
+ attr_reader :variables
19
21
 
20
22
  def initialize(variables)
21
23
  @variables = variables
@@ -4,6 +4,8 @@ module Producer
4
4
  class FS
5
5
  require 'net/sftp'
6
6
 
7
+ attr_reader :remote
8
+
7
9
  def initialize(remote)
8
10
  @remote = remote
9
11
  end
@@ -15,7 +15,7 @@ module Producer
15
15
 
16
16
  define_action :file_write, Actions::FileWriter
17
17
 
18
- attr_accessor :env, :actions
18
+ attr_reader :env, :block, :actions
19
19
 
20
20
  def initialize(env, &block)
21
21
  @env = env
@@ -32,6 +32,10 @@ module Producer
32
32
  @condition = Condition.evaluate(@env, &block) if block
33
33
  @condition
34
34
  end
35
+
36
+ def ask(question, choices, prompter: Prompter)
37
+ prompter.new(env.input, env.output).prompt(question, choices)
38
+ end
35
39
  end
36
40
  end
37
41
  end
@@ -1,6 +1,12 @@
1
1
  module Producer
2
2
  module Core
3
3
  class Test
4
+ require 'forwardable'
5
+
6
+ extend Forwardable
7
+ def_delegators :@env, :remote
8
+ def_delegators :remote, :fs
9
+
4
10
  attr_reader :env, :arguments
5
11
 
6
12
  def initialize(env, *arguments, negated: false)
@@ -3,7 +3,7 @@ module Producer
3
3
  module Tests
4
4
  class HasEnv < Test
5
5
  def verify
6
- env.remote.environment.key? arguments.first.to_s.upcase
6
+ remote.environment.key? arguments.first.to_s.upcase
7
7
  end
8
8
  end
9
9
  end
@@ -3,7 +3,7 @@ module Producer
3
3
  module Tests
4
4
  class HasFile < Test
5
5
  def verify
6
- env.remote.fs.file? arguments.first
6
+ fs.file? arguments.first
7
7
  end
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  module Producer
2
2
  module Core
3
- VERSION = '0.1.10'
3
+ VERSION = '0.1.11'
4
4
  end
5
5
  end
@@ -2,8 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  module Producer::Core
4
4
  describe Action do
5
+ let(:input) { StringIO.new }
5
6
  let(:output) { StringIO.new }
6
- let(:env) { Env.new(output: output) }
7
+ let(:env) { Env.new(input: input, output: output) }
7
8
  let(:arguments) { [:some, :arguments] }
8
9
  subject(:action) { Action.new(env, *arguments) }
9
10
 
@@ -19,6 +20,12 @@ module Producer::Core
19
20
  end
20
21
  end
21
22
 
23
+ describe '#input' do
24
+ it 'returns env input' do
25
+ expect(action.input).to be input
26
+ end
27
+ end
28
+
22
29
  describe '#output' do
23
30
  it 'delegates to env output' do
24
31
  action.output.puts 'some content'
@@ -53,7 +53,9 @@ module Producer::Core
53
53
  context 'without arguments' do
54
54
  let(:arguments) { [] }
55
55
 
56
- specify { expect { cli }.to raise_error described_class::ArgumentError }
56
+ it 'raises our ArgumentError exception' do
57
+ expect { cli }.to raise_error described_class::ArgumentError
58
+ end
57
59
  end
58
60
  end
59
61
 
@@ -69,14 +71,6 @@ module Producer::Core
69
71
  end
70
72
  end
71
73
 
72
- describe '#recipe' do
73
- it 'returns the assigned recipe' do
74
- recipe = double 'recipe'
75
- cli.recipe = recipe
76
- expect(cli.recipe).to be recipe
77
- end
78
- end
79
-
80
74
  describe '#run' do
81
75
  it 'loads the recipe' do
82
76
  cli.run
@@ -13,7 +13,7 @@ module Producer::Core
13
13
  end
14
14
 
15
15
  describe '.define_test' do
16
- let(:some_test_class) { double 'SomeTest class' }
16
+ let(:some_test_class) { Test }
17
17
 
18
18
  before { Condition::DSL.define_test(:some_test, some_test_class) }
19
19
 
@@ -24,15 +24,38 @@ module Producer::Core
24
24
  it 'defines the negated test' do
25
25
  expect(dsl).to respond_to :no_some_test
26
26
  end
27
+
28
+ context 'when a test keyword is called' do
29
+ it 'registers the test' do
30
+ expect { dsl.some_test }.to change { dsl.tests.count }.by 1
31
+ end
32
+
33
+ it 'registers the test with current env' do
34
+ dsl.some_test
35
+ expect(dsl.tests.first.env).to be env
36
+ end
37
+
38
+ it 'registers the test with given arguments' do
39
+ dsl.some_test :some, :args
40
+ expect(dsl.tests.first.arguments).to eq [:some, :args]
41
+ end
42
+ end
43
+
44
+ context 'when a negated test keyword is called' do
45
+ it 'registers a negated test' do
46
+ dsl.no_some_test
47
+ expect(dsl.tests.first).to be_negated
48
+ end
49
+ end
27
50
  end
28
51
 
29
52
  describe '#initialize' do
30
- it 'assigns the code' do
31
- expect(dsl.instance_eval { @block }).to be block
53
+ it 'assigns the env' do
54
+ expect(dsl.env).to be env
32
55
  end
33
56
 
34
- it 'assigns the env' do
35
- expect(dsl.instance_eval { @env }).to be env
57
+ it 'assigns the code' do
58
+ expect(dsl.block).to be block
36
59
  end
37
60
 
38
61
  it 'assigns no test' do
@@ -40,46 +63,15 @@ module Producer::Core
40
63
  end
41
64
  end
42
65
 
43
- describe '#tests' do
44
- it 'returns the assigned tests' do
45
- dsl.instance_eval { @tests = [:some_test] }
46
- expect(dsl.tests).to eq [:some_test]
66
+ describe '#evaluate' do
67
+ it 'evaluates its code' do
68
+ dsl = described_class.new(env) { throw :condition_code }
69
+ expect { dsl.evaluate }.to throw_symbol :condition_code
47
70
  end
48
- end
49
71
 
50
- describe '#evaluate' do
51
72
  it 'returns the value returned by the assigned block' do
52
73
  expect(dsl.evaluate).to eq block.call
53
74
  end
54
-
55
- context 'when a defined test keyword is called' do
56
- let(:some_test_class) { double 'SomeTest class' }
57
- let(:block) { proc { some_test :some, :args } }
58
-
59
- before { Condition::DSL.define_test(:some_test, some_test_class) }
60
-
61
- it 'builds a new test with the env and given arguments' do
62
- expect(some_test_class).to receive(:new).with(env, :some, :args)
63
- dsl.evaluate
64
- end
65
-
66
- it 'registers the new test' do
67
- some_test = double 'SomeTest instance'
68
- allow(some_test_class).to receive(:new) { some_test }
69
- dsl.evaluate
70
- expect(dsl.tests).to include(some_test)
71
- end
72
-
73
- context 'when keyword is prefixed with "no_"' do
74
- let(:block) { proc { no_some_test :some, :args } }
75
-
76
- it 'builds a negated test' do
77
- expect(some_test_class)
78
- .to receive(:new).with(env, :some, :args, negated: true)
79
- dsl.evaluate
80
- end
81
- end
82
- end
83
75
  end
84
76
  end
85
77
  end
@@ -2,56 +2,40 @@ require 'spec_helper'
2
2
 
3
3
  module Producer::Core
4
4
  describe Condition do
5
- include TestsHelpers
6
-
5
+ let(:test_ok) { double 'test', pass?: true }
6
+ let(:test_ko) { double 'test', pass?: false }
7
7
  let(:tests) { [test_ok, test_ko] }
8
8
  subject(:condition) { Condition.new(tests) }
9
9
 
10
10
  describe '.evaluate' do
11
- let(:env) { double 'env' }
12
- let(:block) { proc { :some_condition_code } }
13
-
14
- it 'builds a new DSL sandbox with given env and code' do
15
- expect(Condition::DSL)
16
- .to receive(:new).with(env, &block).and_call_original
17
- Condition.evaluate(env, &block)
18
- end
11
+ let(:env) { double 'env' }
12
+ let(:block) { proc { some_test; :some_return_value } }
13
+ let(:some_test_class) { Class.new(Test) }
14
+ subject(:condition) { described_class.evaluate(env, &block) }
19
15
 
20
- it 'evaluates the DSL sandbox code' do
21
- dsl = double('dsl').as_null_object
22
- allow(Condition::DSL).to receive(:new) { dsl }
23
- expect(dsl).to receive :evaluate
24
- Condition.evaluate(env, &block)
25
- end
26
-
27
- it 'builds a condition with its test and block return value' do
28
- expect(Condition)
29
- .to receive(:new).with([], :some_condition_code)
30
- Condition.evaluate(env, &block)
31
- end
16
+ before { Condition::DSL.define_test(:some_test, some_test_class) }
32
17
 
33
- it 'returns the condition' do
34
- condition = double 'task'
35
- allow(Condition).to receive(:new) { condition }
36
- expect(Condition.evaluate(env, &block)).to be condition
18
+ it 'returns an evaluated condition' do
19
+ expect(condition.tests.first).to be_a Test
20
+ expect(condition.return_value).to eq :some_return_value
37
21
  end
38
22
  end
39
23
 
40
24
  describe '#initialize' do
41
25
  it 'assigns the tests' do
42
- expect(condition.instance_eval { @tests }).to eq tests
26
+ expect(condition.tests).to eq tests
43
27
  end
44
28
 
45
29
  it 'assigns nil as a default return value' do
46
- expect(condition.instance_eval { @return_value }).to be nil
30
+ expect(condition.return_value).to be nil
47
31
  end
48
32
 
49
33
  context 'when a return value is given as argument' do
50
34
  let(:return_value) { :some_return_value }
51
- subject(:condition) { Condition.new(tests, return_value) }
35
+ subject(:condition) { described_class.new(tests, return_value) }
52
36
 
53
37
  it 'assigns the return value' do
54
- expect(condition.instance_eval { @return_value }).to eq return_value
38
+ expect(condition.return_value).to eq return_value
55
39
  end
56
40
  end
57
41
  end
@@ -74,7 +58,7 @@ module Producer::Core
74
58
  end
75
59
 
76
60
  context 'when there are no test' do
77
- subject(:condition) { Condition.new([], return_value) }
61
+ subject(:condition) { described_class.new([], return_value) }
78
62
 
79
63
  context 'and return value is truthy' do
80
64
  let(:return_value) { :some_truthy_value }
@@ -2,32 +2,37 @@ require 'spec_helper'
2
2
 
3
3
  module Producer::Core
4
4
  describe Env do
5
- let(:output) { double 'output' }
6
5
  subject(:env) { Env.new }
7
6
 
8
7
  describe '#initialize' do
8
+ it 'assigns $stdin as the default output' do
9
+ expect(env.input).to be $stdin
10
+ end
11
+
9
12
  it 'assigns $stdout as the default output' do
10
- expect(env.instance_eval { @output }).to eq $stdout
13
+ expect(env.output).to be $stdout
11
14
  end
12
15
 
13
16
  it 'assigns no default target' do
14
17
  expect(env.target).not_to be
15
18
  end
16
19
 
17
- context 'when output is given as argument' do
18
- subject(:env) { Env.new(output: output) }
20
+ context 'when input is given as argument' do
21
+ let(:input) { double 'input' }
22
+ subject(:env) { described_class.new(input: input) }
19
23
 
20
- it 'assigns the given output' do
21
- expect(env.instance_eval { @output }).to eq output
24
+ it 'assigns the given input' do
25
+ expect(env.input).to eq input
22
26
  end
23
27
  end
24
- end
25
28
 
26
- describe '#output' do
27
- subject(:env) { Env.new(output: output) }
29
+ context 'when output is given as argument' do
30
+ let(:output) { double 'output' }
31
+ subject(:env) { described_class.new(output: output) }
28
32
 
29
- it 'returns the assigned output' do
30
- expect(env.output).to eq output
33
+ it 'assigns the given output' do
34
+ expect(env.output).to eq output
35
+ end
31
36
  end
32
37
  end
33
38
 
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ module Producer::Core
4
+ describe Prompter do
5
+ let(:input) { StringIO.new }
6
+ let(:output) { StringIO.new }
7
+ let(:env) { Env.new(input: input, output: output) }
8
+ subject(:prompter) { Prompter.new(input, output) }
9
+
10
+ describe '#initialize' do
11
+ it 'assigns the given input' do
12
+ expect(prompter.input).to be input
13
+ end
14
+
15
+ it 'assigns the given output' do
16
+ expect(prompter.output).to be output
17
+ end
18
+ end
19
+
20
+ describe '#prompt' do
21
+ let(:question) { 'Which letter?' }
22
+ let(:choices) { [[:a, ?A], [:b, ?B]] }
23
+
24
+ it 'prompts choices' do
25
+ prompter.prompt question, choices
26
+ expect(output.string).to eq <<-eoh.gsub /^\s+\|/, ''
27
+ |#{question}
28
+ |0: A
29
+ |1: B
30
+ |Choice:
31
+ eoh
32
+ end
33
+
34
+ it 'returns value for entry chosen by user' do
35
+ input.puts '1'
36
+ input.rewind
37
+ expect(prompter.prompt question, choices).to eq :b
38
+ end
39
+ end
40
+ end
41
+ end
@@ -5,7 +5,7 @@ module Producer::Core
5
5
  include FixturesHelpers
6
6
 
7
7
  let(:code) { proc { :some_recipe_code } }
8
- let(:env) { double('env').as_null_object }
8
+ let(:env) { Env.new }
9
9
  subject(:dsl) { Recipe::DSL.new(env, &code) }
10
10
 
11
11
  describe '#initialize' do
@@ -19,16 +19,16 @@ module Producer::Core
19
19
 
20
20
  context 'when a string of code is given as argument' do
21
21
  let(:code) { 'some_code' }
22
- subject(:dsl) { Recipe::DSL.new(env, code) }
22
+ subject(:dsl) { described_class.new(env, code) }
23
23
 
24
24
  it 'assigns the string of code' do
25
- expect(dsl.instance_eval { @code }).to eq code
25
+ expect(dsl.code).to eq code
26
26
  end
27
27
  end
28
28
 
29
29
  context 'when a code block is given as argument' do
30
30
  it 'assigns the code block' do
31
- expect(dsl.instance_eval { @block }).to be code
31
+ expect(dsl.block).to be code
32
32
  end
33
33
  end
34
34
  end
@@ -44,7 +44,7 @@ module Producer::Core
44
44
 
45
45
  describe '#evaluate' do
46
46
  it 'evaluates its code' do
47
- dsl = Recipe::DSL.new(env) { throw :recipe_code }
47
+ dsl = described_class.new(env) { throw :recipe_code }
48
48
  expect { dsl.evaluate }.to throw_symbol :recipe_code
49
49
  end
50
50
 
@@ -53,76 +53,50 @@ module Producer::Core
53
53
  end
54
54
  end
55
55
 
56
- context 'DSL specific methods' do
57
- subject(:dsl) { Recipe::DSL.new(env, &code).evaluate }
56
+ describe '#source' do
57
+ let(:filepath) { fixture_path_for 'recipes/throw' }
58
58
 
59
- describe '#env' do
60
- let(:code) { proc { env.some_message } }
61
-
62
- it 'returns the current environment' do
63
- expect(env).to receive :some_message
64
- dsl.evaluate
65
- end
59
+ it 'sources the recipe given as argument' do
60
+ expect { dsl.source filepath }.to throw_symbol :recipe_code
66
61
  end
62
+ end
67
63
 
68
- describe '#source' do
69
- let(:filepath) { fixture_path_for 'recipes/throw' }
70
- let(:code) { "source '#{filepath}'" }
71
- subject(:dsl) { Recipe::DSL.new(env, code) }
64
+ describe '#target' do
65
+ let(:host) { 'some_host.example' }
72
66
 
73
- it 'sources the recipe given as argument' do
74
- expect { dsl.evaluate }.to throw_symbol :recipe_code
75
- end
67
+ it 'registers the target host in the env' do
68
+ dsl.target host
69
+ expect(env.target).to eq host
76
70
  end
71
+ end
77
72
 
78
- describe '#target' do
79
- let(:code) { proc { target 'some_host.example' } }
80
-
81
- it 'registers the target host in the env' do
82
- expect(env).to receive(:target=).with('some_host.example')
83
- dsl
84
- end
73
+ describe '#task' do
74
+ it 'registers a new evaluated task' do
75
+ expect { dsl.task(:some_task) { :some_task_code } }
76
+ .to change { dsl.tasks.count }.by 1
85
77
  end
78
+ end
86
79
 
87
- describe '#task' do
88
- let(:code) { proc { task(:some_task, :some, :arg) { :some_value } } }
80
+ describe '#macro' do
81
+ it 'defines the new recipe keyword' do
82
+ dsl.macro :hello
83
+ expect(dsl).to respond_to(:hello)
84
+ end
89
85
 
90
- it 'builds a new evaluated task' do
91
- expect(Task)
92
- .to receive(:evaluate).with(:some_task, env, :some, :arg) do |&b|
93
- expect(b.call).to eq :some_value
94
- end
95
- dsl
96
- end
86
+ context 'when a defined macro is called' do
87
+ before { dsl.macro(:hello) { :some_macro_code } }
97
88
 
98
89
  it 'registers the new task' do
99
- task = double('task').as_null_object
100
- allow(Task).to receive(:new) { task }
101
- expect(dsl.tasks).to include(task)
90
+ expect { dsl.hello }.to change { dsl.tasks.count }.by 1
102
91
  end
103
92
  end
104
93
 
105
- describe '#macro' do
106
- let(:code) { proc { macro(:hello) { echo 'hello' } } }
107
-
108
- it 'defines the new recipe keyword' do
109
- expect(dsl).to respond_to(:hello)
110
- end
111
-
112
- context 'when the new keyword is called' do
113
- let(:code) { proc { macro(:hello) { echo 'hello' }; hello } }
114
-
115
- it 'registers the new task' do
116
- expect(dsl.tasks.first.actions.first).to be_an Actions::Echo
117
- end
118
- end
119
-
120
- context 'when macro takes arguments' do
121
- let(:code) { proc { macro(:hello) { |e| echo e }; hello :arg } }
94
+ context 'when a defined macro is called with arguments' do
95
+ before { dsl.macro(:hello) { |a, b| echo a, b } }
122
96
 
123
- it 'evaluates task code with arguments' do
124
- expect(dsl.tasks.first.actions.first.arguments.first).to be :arg
125
- end
97
+ it 'evaluates task code with arguments' do
98
+ dsl.hello :some, :args
99
+ expect(dsl.tasks.first.actions.first.arguments).to eq [:some, :args]
126
100
  end
127
101
  end
128
102
  end
@@ -9,37 +9,40 @@ module Producer::Core
9
9
 
10
10
  describe '.string_to_hash' do
11
11
  it 'converts key=value pairs separated by new lines to a hash' do
12
- expect(Remote::Environment.string_to_hash(string))
13
- .to eq variables
12
+ expect(described_class.string_to_hash(string)).to eq variables
14
13
  end
15
14
  end
16
15
 
17
16
  describe '.new_from_string' do
18
- it 'builds a new instance after converting from string' do
19
- expect(Remote::Environment).to receive(:new).with(variables)
20
- Remote::Environment.new_from_string(string)
21
- end
22
-
23
- it 'returns the instance' do
24
- environment = double 'environment'
25
- allow(Remote::Environment).to receive(:new) { environment }
26
- expect(Remote::Environment.new_from_string(string)).to be environment
17
+ it 'returns a new instance with converted keys and values' do
18
+ environment = described_class.new_from_string string
19
+ expect(environment.variables).to eq variables
27
20
  end
28
21
  end
29
22
 
30
23
  describe '#initialize' do
31
24
  it 'assigns the key/value pairs' do
32
- expect(environment.instance_eval { @variables }).to eq variables
25
+ expect(environment.variables).to eq variables
33
26
  end
34
27
  end
35
28
 
36
29
  describe '#key?' do
37
- let(:key) { 'SOME_KEY' }
30
+ context 'when key is defined' do
31
+ it 'returns true' do
32
+ expect(environment.key? 'FOO').to be true
33
+ end
34
+ end
35
+
36
+ context 'when key is not defined' do
37
+ it 'returns false' do
38
+ expect(environment.key? 'INEXISTENT_KEY').to be false
39
+ end
40
+ end
41
+ end
38
42
 
39
- it 'forwards the message to @variables' do
40
- expect(environment.instance_eval { @variables })
41
- .to receive(:key?).with(key)
42
- environment.key? key
43
+ describe '#[]' do
44
+ it 'returns the value indexed by given key' do
45
+ expect(environment['FOO']).to eq 'bar'
43
46
  end
44
47
  end
45
48
  end
@@ -7,7 +7,7 @@ module Producer::Core
7
7
 
8
8
  describe '#new' do
9
9
  it 'assigns the remote given as argument' do
10
- expect(fs.instance_eval { @remote }).to be remote
10
+ expect(fs.remote).to be remote
11
11
  end
12
12
  end
13
13
 
@@ -5,8 +5,8 @@ module Producer::Core
5
5
  let(:hostname) { 'some_host.example' }
6
6
  subject(:remote) { Remote.new(hostname) }
7
7
 
8
- describe '#hostname' do
9
- it 'returns the assignated hostname' do
8
+ describe '#initialize' do
9
+ it 'assigns the given hostname' do
10
10
  expect(remote.hostname).to eq hostname
11
11
  end
12
12
  end
@@ -116,26 +116,14 @@ module Producer::Core
116
116
  end
117
117
  end
118
118
 
119
- describe '#environment', :ssh do
119
+ describe '#environment' do
120
120
  let(:command) { 'env' }
121
- let(:output) { "FOO=bar\nBAZ=qux" }
121
+ let(:output) { 'FOO=bar' }
122
122
 
123
- before do
124
- story_with_new_channel do |ch|
125
- ch.sends_exec command
126
- ch.gets_data output
127
- end
128
- end
129
-
130
- it 'builds a remote environment with the result of `env` command' do
131
- expect(Remote::Environment).to receive(:new_from_string).with(output)
132
- remote.environment
133
- end
123
+ before { allow(remote).to receive(:execute) { output } }
134
124
 
135
- it 'returns the environment' do
136
- environment = double 'environment'
137
- allow(Remote::Environment).to receive(:new_from_string) { environment }
138
- expect(remote.environment).to be environment
125
+ it 'returns a remote environment' do
126
+ expect(remote.environment['FOO']).to eq 'bar'
139
127
  end
140
128
  end
141
129
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module Producer::Core
4
4
  describe Task::DSL do
5
5
  let(:block) { proc {} }
6
- let(:env) { double 'env' }
6
+ let(:env) { Env.new }
7
7
  subject(:dsl) { Task::DSL.new(env, &block) }
8
8
 
9
9
  %w[echo sh file_write].each do |action|
@@ -13,10 +13,29 @@ module Producer::Core
13
13
  end
14
14
 
15
15
  describe '.define_action' do
16
+ let(:some_action_class) { Class.new(Action) }
17
+
18
+ before { described_class.define_action(:some_action, some_action_class) }
19
+
16
20
  it 'defines a new action keyword' do
17
- Task::DSL.define_action(:some_action, Object)
18
21
  expect(dsl).to respond_to :some_action
19
22
  end
23
+
24
+ context 'when an action keyword is called' do
25
+ it 'registers the action' do
26
+ expect { dsl.some_action }.to change { dsl.actions.count }.by 1
27
+ end
28
+
29
+ it 'registers the action with current env' do
30
+ dsl.some_action
31
+ expect(dsl.actions.first.env).to be env
32
+ end
33
+
34
+ it 'registers the action with given arguments' do
35
+ dsl.some_action :some, :args
36
+ expect(dsl.actions.first.arguments).to eq [:some, :args]
37
+ end
38
+ end
20
39
  end
21
40
 
22
41
  describe '#initialize' do
@@ -24,28 +43,16 @@ module Producer::Core
24
43
  expect(dsl.env).to be env
25
44
  end
26
45
 
46
+ it 'assigns the given block' do
47
+ expect(dsl.block).to be block
48
+ end
49
+
27
50
  it 'assigns no action' do
28
51
  expect(dsl.actions).to be_empty
29
52
  end
30
53
 
31
54
  it 'assigns true as the condition' do
32
- expect(dsl.instance_eval { @condition }).to be true
33
- end
34
- end
35
-
36
- describe '#actions' do
37
- it 'returns the assigned actions' do
38
- dsl.instance_eval { @actions = [:some_action] }
39
- expect(dsl.actions).to eq [:some_action]
40
- end
41
- end
42
-
43
- describe '#condition' do
44
- context 'without block' do
45
- it 'returns the assigned condition' do
46
- dsl.instance_eval { @condition = :some_condition }
47
- expect(dsl.condition).to be :some_condition
48
- end
55
+ expect(dsl.condition).to be true
49
56
  end
50
57
  end
51
58
 
@@ -65,47 +72,34 @@ module Producer::Core
65
72
  .to throw_symbol :some_argument
66
73
  end
67
74
  end
75
+ end
68
76
 
69
- context 'when a defined keyword action is called' do
70
- let(:some_action_class) { Class.new(Action) }
71
- let(:block) { proc { some_action } }
72
-
73
- before do
74
- Task::DSL.define_action(:some_action, some_action_class)
75
- dsl.evaluate
77
+ describe '#condition' do
78
+ context 'when a block is given' do
79
+ it 'assigns a new evaluated condition' do
80
+ dsl.condition { :some_return_value }
81
+ expect(dsl.condition.return_value).to eq :some_return_value
76
82
  end
83
+ end
84
+ end
77
85
 
78
- it 'registers the action' do
79
- expect(dsl.actions.first).to be_an Action
80
- end
86
+ describe '#ask' do
87
+ let(:question) { 'Which letter?' }
88
+ let(:choices) { [[:a, ?A], [:b, ?B]] }
89
+ let(:prompter_class) { double('prompter class').as_null_object }
90
+ subject(:ask) { dsl.ask question, choices,
91
+ prompter: prompter_class }
81
92
 
82
- it 'provides the env to the registered action' do
83
- expect(dsl.actions.first.env).to eq env
84
- end
93
+ it 'builds a prompter' do
94
+ expect(prompter_class).to receive(:new).with(env.input, env.output)
95
+ ask
85
96
  end
86
- end
87
97
 
88
- context 'DSL specific methods' do
89
- subject(:dsl) { Task::DSL.new(env, &block).evaluate }
90
-
91
- describe '#condition' do
92
- context 'when a block is given' do
93
- let(:block) { proc { condition { :some_value } } }
94
-
95
- it 'builds a new evaluated condition' do
96
- expect(Condition)
97
- .to receive :evaluate do |&b|
98
- expect(b.call).to eq :some_value
99
- end
100
- dsl
101
- end
102
-
103
- it 'assigns the new condition' do
104
- condition = double('condition').as_null_object
105
- allow(Condition).to receive(:evaluate) { condition }
106
- expect(dsl.condition).to be condition
107
- end
108
- end
98
+ it 'prompts and returns the choice' do
99
+ prompter = double 'prompter'
100
+ allow(prompter_class).to receive(:new) { prompter }
101
+ allow(prompter).to receive(:prompt) { :choice }
102
+ expect(ask).to eq :choice
109
103
  end
110
104
  end
111
105
  end
@@ -8,54 +8,44 @@ module Producer::Core
8
8
  subject(:task) { Task.new(name, [action], condition) }
9
9
 
10
10
  describe '.evaluate' do
11
- let(:env) { double 'env' }
12
- let(:args) { [:some, :arguments] }
13
- let(:block) { proc { :some_task_code } }
14
-
15
- it 'builds a new DSL sandbox with given env and code' do
16
- dsl = double('dsl').as_null_object
17
- expect(Task::DSL).to receive(:new).with(env) do |&b|
18
- expect(b).to be block
19
- dsl
20
- end
21
- Task.evaluate(name, env, *args, &block)
22
- end
11
+ let(:name) { :some_task }
12
+ let(:env) { double 'env' }
13
+ let(:block) { proc { condition { :condition }; some_action } }
14
+ let(:some_action_class) { Class.new(Action) }
15
+ subject(:task) { Task.evaluate(name, env, :some, :args, &block) }
23
16
 
24
- it 'evaluates the DSL sandbox code with given arguments' do
25
- dsl = double('dsl').as_null_object
26
- allow(Task::DSL).to receive(:new) { dsl }
27
- expect(dsl).to receive(:evaluate).with(*args)
28
- Task.evaluate(name, env, *args, &block)
29
- end
17
+ before { Task::DSL.define_action(:some_action, some_action_class) }
30
18
 
31
- it 'builds the task with its name, actions and condition' do
32
- dsl = double(
33
- 'dsl', actions: [:some_action], condition: :some_condition
34
- ).as_null_object
35
- allow(Task::DSL).to receive(:new) { dsl }
36
- expect(Task)
37
- .to receive(:new).with(:some_task, [:some_action], :some_condition)
38
- Task.evaluate(name, env, *args, &block)
19
+ it 'returns an evaluated task' do
20
+ expect(task).to be_kind_of Task
39
21
  end
40
22
 
41
- it 'returns the task' do
42
- task = double 'task'
43
- allow(Task).to receive(:new) { task }
44
- expect(Task.evaluate(name, env, *args, &block)).to be task
23
+ context 'evaluated task' do
24
+ it 'has the requested name' do
25
+ expect(task.name).to eq name
26
+ end
27
+
28
+ it 'has the requested actions' do
29
+ expect(task.actions.first).to be_kind_of some_action_class
30
+ end
31
+
32
+ it 'has the requested condition' do
33
+ expect(task.condition.return_value).to be :condition
34
+ end
45
35
  end
46
36
  end
47
37
 
48
38
  describe '#initialize' do
49
39
  it 'assigns the name' do
50
- expect(task.instance_eval { @name }).to eq name
40
+ expect(task.name).to eq name
51
41
  end
52
42
 
53
43
  it 'assigns the actions' do
54
- expect(task.instance_eval { @actions }).to eq [action]
44
+ expect(task.actions).to eq [action]
55
45
  end
56
46
 
57
47
  it 'assigns the condition' do
58
- expect(task.instance_eval { @condition }).to eq condition
48
+ expect(task.condition).to eq condition
59
49
  end
60
50
 
61
51
  context 'when only the name is given as argument' do
@@ -71,24 +61,6 @@ module Producer::Core
71
61
  end
72
62
  end
73
63
 
74
- describe '#name' do
75
- it 'returns its name' do
76
- expect(task.name).to eq name
77
- end
78
- end
79
-
80
- describe '#actions' do
81
- it 'returns the assigned actions' do
82
- expect(task.actions).to eq [action]
83
- end
84
- end
85
-
86
- describe '#condition' do
87
- it 'returns the assigned condition' do
88
- expect(task.condition).to be condition
89
- end
90
- end
91
-
92
64
  describe '#condition_met?' do
93
65
  context 'when condition is truthy' do
94
66
  let(:condition) { Condition.new([], true) }
@@ -2,41 +2,41 @@ require 'spec_helper'
2
2
 
3
3
  module Producer::Core
4
4
  describe Test do
5
- let(:env) { double 'env' }
5
+ let(:env) { Env.new }
6
6
  let(:arguments) { [:some, :arguments] }
7
7
  subject(:test) { Test.new(env, *arguments) }
8
8
 
9
9
  describe '#initialize' do
10
10
  it 'assigns the env' do
11
- expect(test.instance_eval { @env }).to be env
11
+ expect(test.env).to be env
12
12
  end
13
13
 
14
14
  it 'assigns the arguments' do
15
- expect(test.instance_eval { @arguments }).to eq arguments
15
+ expect(test.arguments).to eq arguments
16
16
  end
17
17
 
18
18
  it 'assigns negated as false by default' do
19
- expect(test.instance_eval { @negated }).to be false
19
+ expect(test).to_not be_negated
20
20
  end
21
21
 
22
22
  context 'when negated option is true' do
23
- subject(:test) { Test.new(env, *arguments, negated: true) }
23
+ subject(:test) { described_class.new(env, *arguments, negated: true) }
24
24
 
25
25
  it 'assigns negated as true' do
26
- expect(test.instance_eval { @negated }).to be true
26
+ expect(test).to be_negated
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
- describe '#env' do
32
- it 'returns the assigned env' do
33
- expect(test.env).to be env
31
+ describe '#remote' do
32
+ it 'returns env remote' do
33
+ expect(test.remote).to be test.env.remote
34
34
  end
35
35
  end
36
36
 
37
- describe '#arguments' do
38
- it 'returns the assigned arguments' do
39
- expect(test.arguments).to eq arguments
37
+ describe '#fs' do
38
+ it 'returns env remote fs' do
39
+ expect(test.fs).to be test.env.remote.fs
40
40
  end
41
41
  end
42
42
 
@@ -46,7 +46,7 @@ module Producer::Core
46
46
  end
47
47
 
48
48
  context 'when test is negated' do
49
- subject(:test) { Test.new(env, *arguments, negated: true) }
49
+ subject(:test) { described_class.new(env, *arguments, negated: true) }
50
50
 
51
51
  it 'returns true' do
52
52
  expect(test.negated?).to be true
@@ -66,7 +66,7 @@ module Producer::Core
66
66
  end
67
67
 
68
68
  context 'when test is negated' do
69
- subject(:test) { Test.new(env, *arguments, negated: true) }
69
+ subject(:test) { described_class.new(env, *arguments, negated: true) }
70
70
 
71
71
  it 'returns false when #verify is true' do
72
72
  allow(test).to receive(:verify) { true }
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,6 @@ require 'producer/core'
3
3
  require 'support/exit_helpers'
4
4
  require 'support/fixtures_helpers'
5
5
  require 'support/net_ssh_story_helpers'
6
- require 'support/tests_helpers'
7
6
 
8
7
 
9
8
  RSpec.configure do |c|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: producer-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thibault Jouan
@@ -112,6 +112,7 @@ files:
112
112
  - features/actions/file_write.feature
113
113
  - features/actions/sh.feature
114
114
  - features/cli/usage.feature
115
+ - features/recipes/ask.feature
115
116
  - features/recipes/env.feature
116
117
  - features/recipes/evaluation.feature
117
118
  - features/recipes/macro.feature
@@ -140,6 +141,7 @@ files:
140
141
  - lib/producer/core/condition/dsl.rb
141
142
  - lib/producer/core/env.rb
142
143
  - lib/producer/core/errors.rb
144
+ - lib/producer/core/prompter.rb
143
145
  - lib/producer/core/recipe.rb
144
146
  - lib/producer/core/recipe/dsl.rb
145
147
  - lib/producer/core/remote.rb
@@ -164,6 +166,7 @@ files:
164
166
  - spec/producer/core/condition/dsl_spec.rb
165
167
  - spec/producer/core/condition_spec.rb
166
168
  - spec/producer/core/env_spec.rb
169
+ - spec/producer/core/prompter_spec.rb
167
170
  - spec/producer/core/recipe/dsl_spec.rb
168
171
  - spec/producer/core/recipe_spec.rb
169
172
  - spec/producer/core/remote/environment_spec.rb
@@ -179,7 +182,6 @@ files:
179
182
  - spec/support/exit_helpers.rb
180
183
  - spec/support/fixtures_helpers.rb
181
184
  - spec/support/net_ssh_story_helpers.rb
182
- - spec/support/tests_helpers.rb
183
185
  homepage: https://rubygems.org/gems/producer-core
184
186
  licenses: []
185
187
  metadata: {}
@@ -208,6 +210,7 @@ test_files:
208
210
  - features/actions/file_write.feature
209
211
  - features/actions/sh.feature
210
212
  - features/cli/usage.feature
213
+ - features/recipes/ask.feature
211
214
  - features/recipes/env.feature
212
215
  - features/recipes/evaluation.feature
213
216
  - features/recipes/macro.feature
@@ -237,6 +240,7 @@ test_files:
237
240
  - spec/producer/core/condition/dsl_spec.rb
238
241
  - spec/producer/core/condition_spec.rb
239
242
  - spec/producer/core/env_spec.rb
243
+ - spec/producer/core/prompter_spec.rb
240
244
  - spec/producer/core/recipe/dsl_spec.rb
241
245
  - spec/producer/core/recipe_spec.rb
242
246
  - spec/producer/core/remote/environment_spec.rb
@@ -252,5 +256,4 @@ test_files:
252
256
  - spec/support/exit_helpers.rb
253
257
  - spec/support/fixtures_helpers.rb
254
258
  - spec/support/net_ssh_story_helpers.rb
255
- - spec/support/tests_helpers.rb
256
259
  has_rdoc:
@@ -1,9 +0,0 @@
1
- module TestsHelpers
2
- def test_ok
3
- double 'test', pass?: true
4
- end
5
-
6
- def test_ko
7
- double 'test', pass?: false
8
- end
9
- end