producer-core 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
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