substation 0.0.10.beta2 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/.travis.yml +7 -3
  2. data/Changelog.md +99 -24
  3. data/Gemfile +8 -1
  4. data/Gemfile.devtools +37 -21
  5. data/Guardfile +1 -1
  6. data/README.md +118 -46
  7. data/TODO.md +1 -0
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/reek.yml +41 -16
  11. data/config/rubocop.yml +44 -0
  12. data/config/yardstick.yml +1 -1
  13. data/lib/substation.rb +41 -5
  14. data/lib/substation/chain.rb +73 -84
  15. data/lib/substation/chain/definition.rb +147 -0
  16. data/lib/substation/chain/dsl.rb +150 -112
  17. data/lib/substation/chain/dsl/config.rb +55 -0
  18. data/lib/substation/chain/dsl/module_builder.rb +84 -0
  19. data/lib/substation/dispatcher.rb +20 -229
  20. data/lib/substation/dsl/guard.rb +96 -0
  21. data/lib/substation/dsl/registry.rb +181 -0
  22. data/lib/substation/environment.rb +126 -23
  23. data/lib/substation/environment/dsl.rb +31 -12
  24. data/lib/substation/processor.rb +238 -7
  25. data/lib/substation/processor/builder.rb +26 -0
  26. data/lib/substation/processor/config.rb +24 -0
  27. data/lib/substation/processor/evaluator.rb +66 -42
  28. data/lib/substation/processor/evaluator/handler.rb +54 -0
  29. data/lib/substation/processor/evaluator/result.rb +24 -0
  30. data/lib/substation/processor/executor.rb +46 -0
  31. data/lib/substation/processor/nest.rb +40 -0
  32. data/lib/substation/processor/transformer.rb +46 -0
  33. data/lib/substation/processor/wrapper.rb +16 -5
  34. data/lib/substation/request.rb +29 -27
  35. data/lib/substation/response.rb +19 -34
  36. data/lib/substation/response/api.rb +37 -0
  37. data/lib/substation/response/exception.rb +20 -0
  38. data/lib/substation/response/exception/output.rb +59 -0
  39. data/lib/substation/response/failure.rb +11 -0
  40. data/lib/substation/response/success.rb +11 -0
  41. data/lib/substation/version.rb +3 -1
  42. data/spec/demo/core.rb +64 -0
  43. data/spec/demo/core/action.rb +49 -0
  44. data/spec/demo/core/action/create_person.rb +28 -0
  45. data/spec/demo/core/errors.rb +16 -0
  46. data/spec/demo/core/facade.rb +38 -0
  47. data/spec/demo/core/handler.rb +21 -0
  48. data/spec/demo/core/handler/acceptor.rb +47 -0
  49. data/spec/demo/core/handler/authenticator.rb +36 -0
  50. data/spec/demo/core/handler/authorizer.rb +38 -0
  51. data/spec/demo/core/input.rb +15 -0
  52. data/spec/demo/core/observers.rb +10 -0
  53. data/spec/demo/core/validator.rb +21 -0
  54. data/spec/demo/domain/actor.rb +29 -0
  55. data/spec/demo/domain/dto/person.rb +18 -0
  56. data/spec/demo/domain/environment.rb +55 -0
  57. data/spec/demo/domain/storage.rb +49 -0
  58. data/spec/demo/web.rb +26 -0
  59. data/spec/demo/web/errors.rb +9 -0
  60. data/spec/demo/web/facade.rb +60 -0
  61. data/spec/demo/web/handler/deserializer.rb +36 -0
  62. data/spec/demo/web/presenter.rb +38 -0
  63. data/spec/demo/web/presenter/person.rb +19 -0
  64. data/spec/demo/web/renderer.rb +45 -0
  65. data/spec/demo/web/sanitizer.rb +35 -0
  66. data/spec/demo/web/sanitizer/person.rb +20 -0
  67. data/spec/demo/web/views.rb +28 -0
  68. data/spec/integration/demo/core_spec.rb +97 -0
  69. data/spec/integration/demo/web_spec.rb +114 -0
  70. data/spec/shared/context/integration/demo.rb +33 -0
  71. data/spec/shared/context/unit/chain.rb +13 -0
  72. data/spec/shared/context/unit/processor.rb +58 -0
  73. data/spec/shared/context/unit/request.rb +8 -0
  74. data/spec/shared/examples/integration/demo.rb +35 -0
  75. data/spec/shared/examples/unit/processor.rb +72 -0
  76. data/spec/spec_helper.rb +52 -23
  77. data/spec/unit/substation/chain/definition_spec.rb +141 -0
  78. data/spec/unit/substation/chain/dsl/config/dsl_module_spec.rb +13 -0
  79. data/spec/unit/substation/chain/dsl/config/registry_spec.rb +13 -0
  80. data/spec/unit/substation/chain/dsl/config_spec.rb +18 -0
  81. data/spec/unit/substation/chain/dsl/module_builder_spec.rb +77 -0
  82. data/spec/unit/substation/chain/dsl_spec.rb +175 -0
  83. data/spec/unit/substation/chain_spec.rb +303 -0
  84. data/spec/unit/substation/dispatcher_spec.rb +68 -0
  85. data/spec/unit/substation/dsl/guard_spec.rb +72 -0
  86. data/spec/unit/substation/dsl/registry_spec.rb +181 -0
  87. data/spec/unit/substation/environment/dsl_spec.rb +156 -0
  88. data/spec/unit/substation/environment_spec.rb +259 -0
  89. data/spec/unit/substation/processor/builder_spec.rb +21 -0
  90. data/spec/unit/substation/processor/config_spec.rb +40 -0
  91. data/spec/unit/substation/processor/evaluator/handler_spec.rb +20 -0
  92. data/spec/unit/substation/processor/evaluator/pivot_spec.rb +42 -0
  93. data/spec/unit/substation/processor/evaluator/request_spec.rb +11 -0
  94. data/spec/unit/substation/processor/evaluator/result/failure_spec.rb +14 -0
  95. data/spec/unit/substation/processor/evaluator/result/success_spec.rb +14 -0
  96. data/spec/unit/substation/processor/evaluator/result_spec.rb +13 -0
  97. data/spec/unit/substation/processor/evaluator_spec.rb +18 -0
  98. data/spec/unit/substation/processor/executor/null_spec.rb +25 -0
  99. data/spec/unit/substation/processor/executor_spec.rb +32 -0
  100. data/spec/unit/substation/processor/fallible_spec.rb +24 -0
  101. data/spec/unit/substation/processor/incoming_spec.rb +17 -0
  102. data/spec/unit/substation/processor/nest/incoming_spec.rb +56 -0
  103. data/spec/unit/substation/processor/nest_spec.rb +6 -0
  104. data/spec/unit/substation/processor/outgoing_spec.rb +47 -0
  105. data/spec/unit/substation/processor/transformer/incoming_spec.rb +17 -0
  106. data/spec/unit/substation/processor/transformer/outgoing_spec.rb +17 -0
  107. data/spec/unit/substation/processor/wrapper/incoming_spec.rb +15 -0
  108. data/spec/unit/substation/processor/wrapper/outgoing_spec.rb +15 -0
  109. data/spec/unit/substation/processor/wrapper_spec.rb +24 -0
  110. data/spec/unit/substation/processor_spec.rb +68 -0
  111. data/spec/unit/substation/request_spec.rb +70 -0
  112. data/spec/unit/substation/response/api_spec.rb +22 -0
  113. data/spec/unit/substation/response/exception/output_spec.rb +46 -0
  114. data/spec/unit/substation/response/exception_spec.rb +25 -0
  115. data/spec/unit/substation/response/failure_spec.rb +25 -0
  116. data/spec/unit/substation/response/success_spec.rb +24 -0
  117. data/spec/unit/substation/response_spec.rb +73 -0
  118. data/substation.gemspec +7 -6
  119. metadata +157 -67
  120. checksums.yaml +0 -7
  121. data/TODO +0 -0
  122. data/lib/substation/observer.rb +0 -66
  123. data/lib/substation/processor/pivot.rb +0 -25
  124. data/lib/substation/utils.rb +0 -68
  125. data/spec/integration/substation/dispatcher/call_spec.rb +0 -260
  126. data/spec/unit/substation/chain/call_spec.rb +0 -63
  127. data/spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb +0 -19
  128. data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +0 -21
  129. data/spec/unit/substation/chain/dsl/builder/failure_chain_spec.rb +0 -30
  130. data/spec/unit/substation/chain/dsl/chain_spec.rb +0 -15
  131. data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +0 -24
  132. data/spec/unit/substation/chain/dsl/initialize_spec.rb +0 -19
  133. data/spec/unit/substation/chain/dsl/processors_spec.rb +0 -42
  134. data/spec/unit/substation/chain/dsl/use_spec.rb +0 -14
  135. data/spec/unit/substation/chain/each_spec.rb +0 -46
  136. data/spec/unit/substation/chain/incoming/result_spec.rb +0 -21
  137. data/spec/unit/substation/chain/outgoing/call_spec.rb +0 -25
  138. data/spec/unit/substation/chain/outgoing/result_spec.rb +0 -21
  139. data/spec/unit/substation/dispatcher/action/call_spec.rb +0 -23
  140. data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +0 -61
  141. data/spec/unit/substation/dispatcher/action_names_spec.rb +0 -14
  142. data/spec/unit/substation/dispatcher/call_spec.rb +0 -47
  143. data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +0 -20
  144. data/spec/unit/substation/environment/chain_spec.rb +0 -50
  145. data/spec/unit/substation/environment/class_methods/build_spec.rb +0 -11
  146. data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +0 -18
  147. data/spec/unit/substation/environment/dsl/register_spec.rb +0 -14
  148. data/spec/unit/substation/environment/dsl/registry_spec.rb +0 -19
  149. data/spec/unit/substation/observer/chain/call_spec.rb +0 -26
  150. data/spec/unit/substation/observer/class_methods/coerce_spec.rb +0 -33
  151. data/spec/unit/substation/observer/null/call_spec.rb +0 -12
  152. data/spec/unit/substation/processor/evaluator/call_spec.rb +0 -49
  153. data/spec/unit/substation/processor/pivot/call_spec.rb +0 -17
  154. data/spec/unit/substation/processor/wrapper/call_spec.rb +0 -20
  155. data/spec/unit/substation/request/env_spec.rb +0 -14
  156. data/spec/unit/substation/request/error_spec.rb +0 -15
  157. data/spec/unit/substation/request/input_spec.rb +0 -14
  158. data/spec/unit/substation/request/success_spec.rb +0 -15
  159. data/spec/unit/substation/response/env_spec.rb +0 -16
  160. data/spec/unit/substation/response/failure/success_predicate_spec.rb +0 -15
  161. data/spec/unit/substation/response/input_spec.rb +0 -16
  162. data/spec/unit/substation/response/output_spec.rb +0 -16
  163. data/spec/unit/substation/response/request_spec.rb +0 -16
  164. data/spec/unit/substation/response/success/success_predicate_spec.rb +0 -15
  165. data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +0 -46
  166. data/spec/unit/substation/utils/class_methods/const_get_spec.rb +0 -46
  167. data/spec/unit/substation/utils/class_methods/symbolize_keys_spec.rb +0 -20
@@ -1,6 +1,29 @@
1
- require 'devtools/spec_helper'
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/its'
4
+
5
+ if ENV['COVERAGE'] == 'true'
6
+ require 'simplecov'
7
+ require 'coveralls'
2
8
 
3
- require 'concord' # makes spec setup easier
9
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ Coveralls::SimpleCov::Formatter
12
+ ]
13
+
14
+ SimpleCov.start do
15
+ command_name 'spec:unit'
16
+ add_filter 'config'
17
+ add_filter 'spec'
18
+ minimum_coverage 99.6
19
+ end
20
+ end
21
+
22
+ require 'substation'
23
+
24
+ # MUST happen after ice_nine
25
+ # got required by substation
26
+ require 'devtools/spec_helper'
4
27
 
5
28
  module Spec
6
29
 
@@ -28,13 +51,25 @@ module Spec
28
51
  end
29
52
 
30
53
  class Processor
31
- include Concord::Public.new(:env, :handler)
54
+ include Substation::Processor::Incoming
55
+
56
+ attr_reader :name
57
+
58
+ def call(request)
59
+ request.success(execute(request))
60
+ end
32
61
  end
33
62
 
34
63
  class Presenter
35
64
  include Concord.new(:data)
36
65
  end
37
66
 
67
+ class Transformer
68
+ def self.call(response)
69
+ :transformed
70
+ end
71
+ end
72
+
38
73
  module Handler
39
74
 
40
75
  class Evaluator
@@ -76,32 +111,26 @@ module Spec
76
111
 
77
112
  end
78
113
 
79
- FAKE_HANDLER = Object.new
80
- FAKE_ENV = Object.new
81
- FAKE_PROCESSOR = Processor.new(FAKE_ENV, FAKE_HANDLER)
114
+ FAKE_ENV = Object.new
115
+ FAKE_HANDLER = Object.new
82
116
 
83
- end
117
+ FAKE_CONFIG = Substation::Processor::Config.new(
118
+ Substation::Processor::Executor::NULL,
119
+ Substation::Chain::EMPTY,
120
+ Substation::EMPTY_ARRAY
121
+ )
84
122
 
85
- if ENV['COVERAGE'] == 'true'
86
- require 'simplecov'
87
- require 'coveralls'
123
+ FAKE_PROCESSOR = Processor.new(:test, FAKE_HANDLER, FAKE_CONFIG)
88
124
 
89
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
90
- SimpleCov::Formatter::HTMLFormatter,
91
- Coveralls::SimpleCov::Formatter
92
- ]
93
-
94
- SimpleCov.start do
95
- command_name 'spec:unit'
96
- add_filter 'config'
97
- add_filter 'spec'
98
- minimum_coverage 100
99
- end
100
125
  end
101
126
 
102
- require 'substation'
103
-
104
127
  include Substation
105
128
 
106
129
  RSpec.configure do |config|
130
+ config.expect_with :rspec do |c|
131
+ c.syntax = :expect
132
+ end
133
+ config.mock_with :rspec do |c|
134
+ c.syntax = :expect
135
+ end
107
136
  end
@@ -0,0 +1,141 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::Definition do
6
+
7
+ subject { described_class.new(nil, []) }
8
+
9
+ it { should be_kind_of(Enumerable) }
10
+
11
+ let(:object) { described_class.new(chain_name, processors) }
12
+ let(:chain_name) { double('chain_name') }
13
+
14
+ describe '#initialize' do
15
+ let(:chain_name) { 'chain name' }
16
+ let(:processors) { [Object.new, Object.new] }
17
+
18
+ it 'assigns the name' do
19
+ expect(object.name).to eq('chain name')
20
+ end
21
+
22
+ it 'has given processors' do
23
+ expect(object.each.count).to be(2)
24
+ end
25
+ end
26
+
27
+ describe '#each' do
28
+ subject { object.each(&block) }
29
+
30
+ let(:processors) { [ processor ] }
31
+ let(:processor) { double('processor', :name => name) }
32
+ let(:name) { double('name') }
33
+ let(:block) { ->(_) { } }
34
+
35
+ it_should_behave_like 'an #each method'
36
+
37
+ it 'yields all processors' do
38
+ expect { |block| object.each(&block) }.to yield_successive_args(processor)
39
+ end
40
+ end
41
+
42
+ describe '#<<' do
43
+ subject { object << processor }
44
+
45
+ let(:processor) { double('processor', :name => name) }
46
+ let(:name) { double('name') }
47
+
48
+ context 'when the given processor is not currently present in object' do
49
+ let(:processors) { [] }
50
+
51
+ it 'registers the processor' do
52
+ expect(subject.each).to include(processor)
53
+ end
54
+
55
+ it_behaves_like 'a command method'
56
+ end
57
+
58
+ context 'when the given processor is already present in object' do
59
+ let(:processors) { [processor] }
60
+ let(:msg) { Chain::Definition::DUPLICATE_PROCESSOR_MSG % [processor].inspect }
61
+
62
+ it 'raises DuplicateProcessorError' do
63
+ expect { subject }.to raise_error(DuplicateProcessorError, msg)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#prepend' do
69
+ subject { object.prepend(other) }
70
+
71
+ let(:object) { described_class.new(name, [processor_1]) }
72
+ let(:name) { double('chain_name') }
73
+ let(:processor_1) { double('processor_1', :name => name_1) }
74
+ let(:name_1) { double('name_1') }
75
+ let(:other_name) { double('other_chain_name') }
76
+ let(:other) { described_class.new(other_name, [processor_2]) }
77
+ let(:name_2) { double('name_2') }
78
+
79
+ context 'and the processors are disjoint' do
80
+ let(:processor_2) { double('processor_2', :name => name_2) }
81
+
82
+ it { should eql(described_class.new(name, [processor_2, processor_1])) }
83
+ end
84
+
85
+ context 'and the processors contain duplicates' do
86
+ let(:processor_2) { processor_1 }
87
+ let(:msg) { Chain::Definition::DUPLICATE_PROCESSOR_MSG % [processor_2].inspect }
88
+
89
+ it 'raises DuplicateProcessorError' do
90
+ expect { subject }.to raise_error(DuplicateProcessorError, msg)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe '#replace_failure_chain' do
96
+ subject { object.replace_failure_chain(name, failure_chain) }
97
+
98
+ let(:processor) { double('processor', :name => name) }
99
+ let(:name) { double('name') }
100
+ let(:other_processor) { double('other_processor', :name => other_name) }
101
+ let(:other_name) { double('other_name') }
102
+ let(:failure_chain) { double('failure_chain') }
103
+ let(:replaced_processor) { double('replaced_processor') }
104
+
105
+ context 'when a processor is registered under the given name' do
106
+ before do
107
+ expect(processor).to receive(:with_failure_chain).with(failure_chain).and_return(replaced_processor)
108
+ end
109
+
110
+ context 'when one processor is registered under the given name' do
111
+ let(:processors) { [other_processor, processor] }
112
+
113
+ it 'replaces the processor with a new one' do
114
+ expect(subject.each).to include(replaced_processor)
115
+ end
116
+
117
+ it_behaves_like 'a command method'
118
+ end
119
+
120
+ context 'when more than one processor is registered under the given name' do
121
+ let(:processors) { [other_processor, processor, same_name_processor] }
122
+ let(:same_name_processor) { double('same_name_processor', :name => name) }
123
+
124
+ it 'replaces the first processor with a new one' do
125
+ expect(subject.each).to include(replaced_processor)
126
+ expect(subject.each).to include(same_name_processor)
127
+ end
128
+
129
+ it_behaves_like 'a command method'
130
+ end
131
+ end
132
+
133
+ context 'when no processor is registered under the given name' do
134
+ let(:processors) { [] }
135
+
136
+ it 'raises an UnknownProcessorError' do
137
+ expect { subject }.to raise_error(UnknownProcessor, "No processor named #{name.inspect} is registered")
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::Config, '#dsl_module' do
6
+ subject { object.dsl_module }
7
+
8
+ let(:object) { described_class.new(registry, dsl_module) }
9
+ let(:registry) { double('registry') }
10
+ let(:dsl_module) { double('dsl_module') }
11
+
12
+ it { should be(dsl_module) }
13
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::Config, '#registry' do
6
+ subject { object.registry }
7
+
8
+ let(:object) { described_class.new(registry, dsl_module) }
9
+ let(:registry) { double('registry') }
10
+ let(:dsl_module) { double('dsl_module') }
11
+
12
+ it { should be(registry) }
13
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::Config, '.build' do
6
+ subject { described_class.build(registry) }
7
+
8
+ let(:registry) { double('registry') }
9
+ let(:dsl_module) { double('dsl_module') }
10
+ let(:config) { double('config') }
11
+
12
+ before do
13
+ expect(Chain::DSL::ModuleBuilder).to receive(:call).with(registry).and_return(dsl_module)
14
+ expect(described_class).to receive(:new).with(registry, dsl_module).and_return(config)
15
+ end
16
+
17
+ it { should eql(config) }
18
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::ModuleBuilder do
6
+ describe '#dsl_module' do
7
+ subject { object.dsl_module }
8
+
9
+ let(:object) { described_class.new(registry) }
10
+ let(:registry) { { :test => processor_builder } }
11
+ let(:processor_builder) { double('processor_builder') }
12
+ let(:handler) { double('handler') }
13
+ let(:failure_chain) { double('failure_chain') }
14
+ let(:observers) { EMPTY_ARRAY }
15
+
16
+ let(:definition) { Chain::Definition.new(name, processors) }
17
+ let(:name) { double('chain_name') }
18
+ let(:processors) { [processor_1] }
19
+ let(:processor_1) { double('processor_1', :name => :processor_1) }
20
+ let(:processor_2) { double('processor_2', :name => :processor_2) }
21
+
22
+ before do
23
+ expect(processor_builder)
24
+ .to receive(:call)
25
+ .with(handler, failure_chain, observers)
26
+ .and_return(processor_2)
27
+ end
28
+
29
+ shared_examples_for 'Chain::DSL::ModuleBuilder#dsl_module' do
30
+ it 'compiles appropriate methods' do
31
+ config = Chain::DSL::Config.new(registry, subject)
32
+ dsl = Chain::DSL.new(config, definition)
33
+
34
+ dsl.test(*dsl_method_args)
35
+
36
+ expect(dsl.definition).to include(processor_1)
37
+ expect(dsl.definition).to include(processor_2)
38
+ end
39
+ end
40
+
41
+ context 'when a failure_chain and observers are given' do
42
+ let(:dsl_method_args) { [handler, failure_chain, observers] }
43
+
44
+ it_behaves_like 'Chain::DSL::ModuleBuilder#dsl_module'
45
+ end
46
+
47
+ context 'when a failure_chain and no observers given' do
48
+ let(:dsl_method_args) { [handler, failure_chain] }
49
+
50
+ it_behaves_like 'Chain::DSL::ModuleBuilder#dsl_module'
51
+ end
52
+
53
+ context 'when no failure_chain and no observers are given' do
54
+ let(:dsl_method_args) { [handler] }
55
+ let(:failure_chain) { Chain::EMPTY }
56
+
57
+ it_behaves_like 'Chain::DSL::ModuleBuilder#dsl_module'
58
+ end
59
+ end
60
+
61
+ describe '.call' do
62
+ subject { described_class.call(registry) }
63
+
64
+ let(:registry) { { :test => processor_builder } }
65
+ let(:processor_builder) { double('processor_builder') }
66
+
67
+ let(:instance) { double('module_builder', :dsl_module => dsl_module) }
68
+ let(:dsl_module) { double('dsl_module') }
69
+
70
+ before do
71
+ expect(described_class).to receive(:new).with(registry).and_return(instance)
72
+ expect(instance).to receive(:dsl_module).and_return(dsl_module)
73
+ end
74
+
75
+ it { should be(dsl_module) }
76
+ end
77
+ end
@@ -0,0 +1,175 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL do
6
+ describe '#name' do
7
+ subject { chain_dsl.name }
8
+
9
+ include_context 'Chain::DSL#initialize'
10
+
11
+ it { should eql(chain_name) }
12
+ end
13
+
14
+ describe '#build' do
15
+ include_context 'Chain::DSL#initialize'
16
+
17
+ let(:failure_chain) { Chain::EMPTY }
18
+ let(:block) { ->(_) { test(Spec::FAKE_HANDLER) } }
19
+ let(:expected_definition) { Chain::Definition.new(new_chain_name, expected_processors) }
20
+ let(:expected) { Chain.new(expected_definition, failure_chain) }
21
+
22
+ let(:new_processors) { [new_processor] }
23
+ let(:new_processor) { double('new_processor', :name => :new_processor) }
24
+
25
+ let(:new_chain_name) { double('new_chain_name') }
26
+
27
+ shared_examples_for 'duplicate processors' do
28
+ let(:new_processor) { processor }
29
+ let(:msg) { Chain::Definition::DUPLICATE_PROCESSOR_MSG % [processor].inspect }
30
+
31
+ it 'should raise DuplicateProcessorError' do
32
+ expect { subject }.to raise_error(DuplicateProcessorError, msg)
33
+ end
34
+ end
35
+
36
+ shared_examples_for 'disjoint processors' do
37
+ it { should eql(expected) }
38
+
39
+ it 'injects the proper registry' do
40
+ expect(chain_dsl.registry).to be(registry)
41
+ end
42
+ end
43
+
44
+ context 'when a block is given' do
45
+ subject { chain_dsl.build(new_chain_name, new_processors, failure_chain, &block) }
46
+
47
+ context 'and all processors are disjoint' do
48
+ let(:expected_processors) { [processor, new_processor, Spec::FAKE_PROCESSOR] }
49
+
50
+ it_behaves_like 'disjoint processors'
51
+ end
52
+
53
+ context 'and there are duplicate processors' do
54
+ it_behaves_like 'duplicate processors'
55
+ end
56
+ end
57
+
58
+ context 'when no block is given' do
59
+ subject { chain_dsl.build(new_chain_name, new_processors, failure_chain) }
60
+
61
+ context 'and all processors are disjoint' do
62
+ let(:expected_processors) { [processor, new_processor] }
63
+
64
+ it_behaves_like 'disjoint processors'
65
+ end
66
+
67
+ context 'and there are duplicate processors' do
68
+ it_behaves_like 'duplicate processors'
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#chain' do
74
+ include_context 'Chain::DSL#initialize'
75
+
76
+ let(:other_processor) { double('other_processor', :name => :other_processor) }
77
+ let(:expected_definition) { Chain::Definition.new(chain_name, expected_processors) }
78
+ let(:expected) { described_class.build(registry, expected_definition) }
79
+
80
+ context 'when no block is given' do
81
+ subject { chain_dsl.chain([other_processor]) }
82
+
83
+ let(:expected_processors) { [processor, other_processor] }
84
+
85
+ it { should eql(expected) }
86
+ end
87
+
88
+ context 'when block is given' do
89
+ subject { chain_dsl.chain([other_processor], &block) }
90
+
91
+ let(:block) { ->(_) { test(Spec::FAKE_HANDLER) } }
92
+
93
+ let(:expected_processors) { [processor, other_processor, Spec::FAKE_PROCESSOR] }
94
+
95
+ it { should eql(expected) }
96
+ end
97
+ end
98
+
99
+ describe '#nest' do
100
+ subject { object.nest(nested_name, chain_to_nest, executor) }
101
+
102
+ include_context 'Chain::DSL#initialize'
103
+
104
+ let(:object) { chain_dsl }
105
+
106
+ let(:chain_to_nest) { double('chain to nest') }
107
+ let(:nested_name) { double('nested name', :to_sym => 'neste name') }
108
+ let(:executor) { double }
109
+
110
+ let(:config) { Processor::Config.new(executor, EMPTY_ARRAY, EMPTY_ARRAY) }
111
+ let(:expected) { Processor::Nest::Incoming.new(nested_name, chain_to_nest, config) }
112
+
113
+ it { should eql(expected) }
114
+
115
+ it 'adds the chain to the definition' do
116
+ subject
117
+ expect(object.definition).to include(subject)
118
+ end
119
+ end
120
+
121
+ describe '#definition' do
122
+ subject { object.definition }
123
+
124
+ include_context 'Chain::DSL#initialize'
125
+
126
+ let(:object) { chain_dsl }
127
+
128
+ it { should eql(definition) }
129
+ end
130
+
131
+ describe '#failure_chain' do
132
+ subject { object.failure_chain(name, failure_chain) }
133
+
134
+ let(:object) { described_class.new(config, definition) }
135
+ let(:config) { Chain::DSL::Config.new(registry, dsl_module) }
136
+ let(:registry) { double('registry') }
137
+ let(:dsl_module) { Module.new }
138
+ let(:definition) { double('definition', :name => double('chain_name')) }
139
+ let(:name) { double('name') }
140
+ let(:failure_chain) { double('failure_chain') }
141
+
142
+ before do
143
+ expect(definition).to receive(:replace_failure_chain).with(name, failure_chain)
144
+ end
145
+
146
+ it_behaves_like 'a command method'
147
+ end
148
+
149
+ describe '.build' do
150
+
151
+ let(:registry) { double('registry') }
152
+ let(:dsl) { double('dsl') }
153
+ let(:config) { double('config') }
154
+ let(:definition) { double('definition') }
155
+
156
+ before do
157
+ expect(Chain::DSL::Config).to receive(:build).with(registry).and_return(config)
158
+ expect(described_class).to receive(:new).with(config, definition).and_return(dsl)
159
+ end
160
+
161
+ context 'when a definition is given' do
162
+ subject { described_class.build(registry, definition) }
163
+
164
+ it { should be(dsl) }
165
+ end
166
+
167
+ context 'when no definition is given' do
168
+ subject { described_class.build(registry) }
169
+
170
+ let(:definition) { Chain::Definition::EMPTY }
171
+
172
+ it { should be(dsl) }
173
+ end
174
+ end
175
+ end