substation 0.0.8 → 0.0.9

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 (85) hide show
  1. data/.travis.yml +4 -0
  2. data/Changelog.md +92 -2
  3. data/Gemfile.devtools +19 -17
  4. data/README.md +116 -46
  5. data/config/flay.yml +2 -2
  6. data/config/mutant.yml +1 -0
  7. data/config/reek.yml +11 -5
  8. data/config/rubocop.yml +35 -0
  9. data/lib/substation.rb +10 -1
  10. data/lib/substation/chain.rb +108 -64
  11. data/lib/substation/chain/dsl.rb +62 -37
  12. data/lib/substation/dispatcher.rb +3 -1
  13. data/lib/substation/environment.rb +9 -6
  14. data/lib/substation/environment/dsl.rb +4 -3
  15. data/lib/substation/observer.rb +2 -0
  16. data/lib/substation/processor.rb +106 -7
  17. data/lib/substation/processor/evaluator.rb +98 -7
  18. data/lib/substation/processor/transformer.rb +26 -0
  19. data/lib/substation/processor/wrapper.rb +5 -3
  20. data/lib/substation/request.rb +12 -1
  21. data/lib/substation/response.rb +13 -0
  22. data/lib/substation/utils.rb +3 -1
  23. data/lib/substation/version.rb +3 -1
  24. data/spec/integration/substation/dispatcher/call_spec.rb +12 -12
  25. data/spec/spec_helper.rb +39 -32
  26. data/spec/unit/substation/chain/call_spec.rb +205 -29
  27. data/spec/unit/substation/chain/class_methods/failure_response_spec.rb +16 -0
  28. data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +7 -4
  29. data/spec/unit/substation/chain/dsl/class_methods/build_spec.rb +24 -0
  30. data/spec/unit/substation/chain/dsl/failure_chain_spec.rb +35 -0
  31. data/spec/unit/substation/chain/dsl/processors_spec.rb +8 -6
  32. data/spec/unit/substation/chain/dsl/use_spec.rb +1 -1
  33. data/spec/unit/substation/chain/each_spec.rb +5 -9
  34. data/spec/unit/substation/chain/failure_data/equalizer_spec.rb +46 -0
  35. data/spec/unit/substation/chain/failure_data/hash_spec.rb +13 -0
  36. data/spec/unit/substation/dispatcher/action/call_spec.rb +2 -1
  37. data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +7 -5
  38. data/spec/unit/substation/dispatcher/call_spec.rb +2 -2
  39. data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +6 -6
  40. data/spec/unit/substation/environment/chain_spec.rb +22 -27
  41. data/spec/unit/substation/environment/class_methods/build_spec.rb +11 -4
  42. data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +5 -3
  43. data/spec/unit/substation/environment/dsl/register_spec.rb +8 -3
  44. data/spec/unit/substation/environment/dsl/registry_spec.rb +5 -3
  45. data/spec/unit/substation/environment/equalizer_spec.rb +25 -0
  46. data/spec/unit/substation/observer/chain/call_spec.rb +2 -0
  47. data/spec/unit/substation/observer/class_methods/coerce_spec.rb +2 -0
  48. data/spec/unit/substation/observer/null/call_spec.rb +2 -0
  49. data/spec/unit/substation/processor/evaluator/call_spec.rb +20 -10
  50. data/spec/unit/substation/processor/evaluator/class_methods/new_spec.rb +9 -0
  51. data/spec/unit/substation/processor/evaluator/data/call_spec.rb +34 -0
  52. data/spec/unit/substation/processor/evaluator/pivot/call_spec.rb +34 -0
  53. data/spec/unit/substation/processor/evaluator/request/call_spec.rb +34 -0
  54. data/spec/unit/substation/processor/fallible/name_spec.rb +15 -0
  55. data/spec/unit/substation/processor/fallible/with_failure_chain_spec.rb +18 -0
  56. data/spec/unit/substation/processor/incoming/result_spec.rb +25 -0
  57. data/spec/unit/substation/processor/outgoing/call_spec.rb +28 -0
  58. data/spec/unit/substation/processor/outgoing/name_spec.rb +14 -0
  59. data/spec/unit/substation/processor/outgoing/success_predicate_spec.rb +15 -0
  60. data/spec/unit/substation/{chain/outgoing → processor}/result_spec.rb +4 -3
  61. data/spec/unit/substation/processor/success_predicate_spec.rb +22 -0
  62. data/spec/unit/substation/processor/transformer/call_spec.rb +21 -0
  63. data/spec/unit/substation/processor/wrapper/call_spec.rb +9 -7
  64. data/spec/unit/substation/request/env_spec.rb +3 -2
  65. data/spec/unit/substation/request/error_spec.rb +2 -1
  66. data/spec/unit/substation/request/input_spec.rb +3 -2
  67. data/spec/unit/substation/request/name_spec.rb +15 -0
  68. data/spec/unit/substation/request/success_spec.rb +2 -1
  69. data/spec/unit/substation/response/env_spec.rb +3 -2
  70. data/spec/unit/substation/response/failure/success_predicate_spec.rb +2 -1
  71. data/spec/unit/substation/response/input_spec.rb +3 -2
  72. data/spec/unit/substation/response/output_spec.rb +2 -1
  73. data/spec/unit/substation/response/request_spec.rb +3 -2
  74. data/spec/unit/substation/response/success/success_predicate_spec.rb +2 -1
  75. data/spec/unit/substation/response/to_request_spec.rb +19 -0
  76. data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +14 -12
  77. data/spec/unit/substation/utils/class_methods/const_get_spec.rb +6 -6
  78. data/spec/unit/substation/utils/class_methods/symbolize_keys_spec.rb +4 -4
  79. metadata +25 -9
  80. data/lib/substation/processor/pivot.rb +0 -25
  81. data/spec/unit/substation/chain/class_methods/build_spec.rb +0 -31
  82. data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +0 -23
  83. data/spec/unit/substation/chain/incoming/result_spec.rb +0 -21
  84. data/spec/unit/substation/chain/outgoing/call_spec.rb +0 -25
  85. data/spec/unit/substation/processor/pivot/call_spec.rb +0 -16
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain, '.failure_response' do
6
+ subject { described_class.failure_response(request, data, exception) }
7
+
8
+ let(:request) { mock(:env => mock, :input => mock) }
9
+ let(:data) { mock }
10
+ let(:exception) { mock }
11
+
12
+ let(:expected) { Response::Failure.new(request, failure_data) }
13
+ let(:failure_data) { described_class::FailureData.new(data, exception) }
14
+
15
+ it { should eql(expected) }
16
+ end
@@ -9,12 +9,15 @@ describe Chain::DSL::Builder, '#dsl' do
9
9
  let(:builder) { described_class.new(registry) }
10
10
  let(:registry) { { :test => Spec::Processor } }
11
11
  let(:processors) { [] }
12
- let(:block) { lambda { |_| test(Spec::FAKE_HANDLER) } }
12
+ let(:block) { ->(_) { test(Spec::FAKE_HANDLER, EMPTY_ARRAY) } }
13
+
13
14
  let(:processor) { Spec::FAKE_PROCESSOR }
14
15
 
15
- its(:processors) { should include(processor) }
16
+ it 'should register instantiated processors' do
17
+ expect(subject.processors).to include(processor)
18
+ end
16
19
 
17
- it "should create a subclass of Chain::DSL" do
18
- subject.class.should be < Chain::DSL
20
+ it 'should create a subclass of Chain::DSL' do
21
+ expect(subject.class).to be < Chain::DSL
19
22
  end
20
23
  end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '.build' do
6
+
7
+ let(:chain) { EMPTY_ARRAY }
8
+ let(:failure_chain) { Chain::EMPTY }
9
+
10
+ context 'and a block is given' do
11
+ subject { described_class.build(chain, failure_chain, &block) }
12
+
13
+ let(:block) { ->(_) { use(Spec::FAKE_PROCESSOR) } }
14
+ let(:processor) { Spec::FAKE_PROCESSOR }
15
+
16
+ it { should include(processor) }
17
+ end
18
+
19
+ context 'and no block is given' do
20
+ subject { described_class.build(chain, failure_chain) }
21
+
22
+ its(:processors) { should be_empty }
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '#failure_chain' do
6
+ subject { object.failure_chain(name, failure_chain) }
7
+
8
+ let(:object) { dsl.new([ Spec::FAKE_PROCESSOR ]) }
9
+ let(:dsl) { described_class::Builder.call(registry) }
10
+ let(:registry) { Environment::DSL.registry(&block) }
11
+ let(:block) { ->(_) { register(:test, Spec::Processor) } }
12
+
13
+ let(:processor) { Spec::FAKE_PROCESSOR.with_failure_chain(failure_chain) }
14
+ let(:failure_chain) { mock }
15
+
16
+ context 'when the processor to alter is registered' do
17
+ let(:name) { :test }
18
+
19
+ its(:processors) { should include(processor) }
20
+
21
+ it 'should replace the processor' do
22
+ expect(subject.processors.length).to be(1)
23
+ end
24
+ end
25
+
26
+ context 'when the processor to alter is not registered' do
27
+ let(:name) { :unknown }
28
+
29
+ specify {
30
+ expect {
31
+ subject
32
+ }.to raise_error(UnknownProcessor, 'No processor named :unknown is registered')
33
+ }
34
+ end
35
+ end
@@ -6,20 +6,22 @@ describe Chain::DSL, '#processors' do
6
6
  subject { object.processors }
7
7
 
8
8
  let(:processor) { Spec::FAKE_PROCESSOR }
9
+ let(:name) { mock }
9
10
 
10
- context "and a block is given" do
11
- let(:object) { described_class.new(chain, &block) }
12
- let(:chain) { Chain::EMPTY }
13
- let(:block) { lambda { |_| use(Spec::FAKE_PROCESSOR) } }
11
+ context 'and a block is given' do
12
+ let(:object) { described_class.new(chain, &block) }
13
+ let(:chain) { EMPTY_ARRAY }
14
+ let(:block) { ->(_) { use(Spec::FAKE_PROCESSOR) } }
14
15
 
15
16
  it { should include(processor) }
16
17
 
17
18
  its(:length) { should == 1 }
18
19
  end
19
20
 
20
- context "and no block is given" do
21
+ context 'and no block is given' do
21
22
  let(:object) { described_class.new(chain) }
22
- let(:chain) { Chain.new([ processor ]) }
23
+ let(:chain) { Chain.new([ processor ], failure_chain) }
24
+ let(:failure_chain) { mock }
23
25
 
24
26
  it { should include(processor) }
25
27
 
@@ -6,7 +6,7 @@ describe Chain::DSL, '#use' do
6
6
  subject { object.use(processor) }
7
7
 
8
8
  let(:object) { described_class.new(chain) }
9
- let(:chain) { Chain::EMPTY }
9
+ let(:chain) { EMPTY_ARRAY }
10
10
  let(:processor) { Spec::FAKE_PROCESSOR }
11
11
 
12
12
  its(:processors) { should include(processor) }
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  describe Chain, '#each' do
6
6
  subject { object.each { |tuple| yields << processor } }
7
7
 
8
- let(:object) { described_class.new(processors) }
8
+ let(:object) { described_class.new(processors, described_class::EMPTY) }
9
9
  let(:processors) { [ processor ] }
10
10
  let(:processor) { Spec::FAKE_PROCESSOR }
11
11
  let(:yields) { [] }
@@ -22,14 +22,14 @@ describe Chain, '#each' do
22
22
  end
23
23
 
24
24
  it 'yields only processors with the expected handler' do
25
- expect { subject }.to change { yields.dup }.
26
- from([]).
27
- to([ processor ])
25
+ expect { subject }.to change { yields.dup }
26
+ .from([])
27
+ .to([ processor ])
28
28
  end
29
29
  end
30
30
 
31
31
  describe Chain do
32
- subject { described_class.new(processors) }
32
+ subject { described_class.new(processors, described_class::EMPTY) }
33
33
 
34
34
  let(:processors) { [ processor ] }
35
35
  let(:processor) { Spec::FAKE_PROCESSOR }
@@ -39,8 +39,4 @@ describe Chain do
39
39
  end
40
40
 
41
41
  it { should be_kind_of(Enumerable) }
42
-
43
- it 'case matches Enumerable' do
44
- (Enumerable === subject).should be(true)
45
- end
46
42
  end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::FailureData, 'equalizer behavior' do
6
+ subject { object == other }
7
+
8
+ let(:object) { described_class.new(data, exception) }
9
+ let(:data) { mock }
10
+ let(:exception) { RuntimeError.new }
11
+
12
+ let(:other) { described_class.new(other_data, other_exception) }
13
+
14
+ context 'with equal data associated' do
15
+
16
+ let(:other_data) { data }
17
+
18
+ context 'and equal exception classes' do
19
+ let(:other_exception) { RuntimeError.new }
20
+
21
+ it { should be(true) }
22
+ end
23
+
24
+ context 'and different exception classes' do
25
+ let(:other_exception) { StandardError.new }
26
+
27
+ it { should be(false) }
28
+ end
29
+ end
30
+
31
+ context 'with different data associated' do
32
+ let(:other_data) { mock }
33
+
34
+ context 'and equal exception classes' do
35
+ let(:other_exception) { RuntimeError.new }
36
+
37
+ it { should be(false) }
38
+ end
39
+
40
+ context 'and different exception classes' do
41
+ let(:other_exception) { StandardError.new }
42
+
43
+ it { should be(false) }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::FailureData, '#hash' do
6
+ subject { object.hash }
7
+
8
+ let(:object) { described_class.new(data, exception) }
9
+ let(:data) { mock }
10
+ let(:exception) { mock }
11
+
12
+ it { should eql(described_class.hash ^ data.hash ^ exception.class.hash) }
13
+ end
@@ -9,7 +9,8 @@ describe Dispatcher::Action, '#call' do
9
9
  let(:object) { described_class.new(klass, observer) }
10
10
  let(:klass) { mock }
11
11
  let(:observer) { mock }
12
- let(:request) { Request.new(env, input) }
12
+ let(:request) { Request.new(name, env, input) }
13
+ let(:name) { mock }
13
14
  let(:env) { mock }
14
15
  let(:input) { mock }
15
16
  let(:response) { mock }
@@ -9,13 +9,15 @@ describe Dispatcher::Action, '.coerce' do
9
9
  let(:action) { Spec::Action::Success }
10
10
  let(:coerced) { Dispatcher::Action.new(action, observer) }
11
11
 
12
- context "when config is a hash" do
13
- context "and coercion is possible" do
12
+ context 'when config is a hash' do
13
+ context 'and coercion is possible' do
14
14
 
15
- let(:config) {{
15
+ let(:config) {
16
+ {
16
17
  :action => action,
17
18
  :observer => observer_value
18
- }}
19
+ }
20
+ }
19
21
 
20
22
  before do
21
23
  Observer.should_receive(:coerce).with(observer_value).and_return(observer)
@@ -46,7 +48,7 @@ describe Dispatcher::Action, '.coerce' do
46
48
  end
47
49
  end
48
50
 
49
- context "when config is no hash" do
51
+ context 'when config is no hash' do
50
52
  let(:config) { action }
51
53
  let(:observer_value) { nil }
52
54
  let(:observer) { Observer::NULL }
@@ -8,9 +8,9 @@ describe Dispatcher, '#call' do
8
8
 
9
9
  let(:object) { described_class.coerce(config, env) }
10
10
  let(:config) { { 'test' => { 'action' => 'Spec::Action::Success' } } }
11
- let(:request) { Request.new(env, input) }
12
- let(:input) { mock }
11
+ let(:request) { Request.new(action_name, env, input) }
13
12
  let(:env) { mock }
13
+ let(:input) { mock }
14
14
 
15
15
  let(:expected_response) do
16
16
  Spec::Action::Success.call(request)
@@ -6,15 +6,15 @@ describe Dispatcher, '.coerce' do
6
6
 
7
7
  subject { described_class.coerce(config, env) }
8
8
 
9
- let(:config) {{
10
- 'test' => { 'action' => 'Spec::Action::Success' }
11
- }}
9
+ let(:config) {
10
+ { 'test' => { 'action' => 'Spec::Action::Success' } }
11
+ }
12
12
 
13
13
  let(:env) { mock }
14
14
 
15
- let(:coerced) {{
16
- :test => described_class::Action.coerce(:action => 'Spec::Action::Success')
17
- }}
15
+ let(:coerced) {
16
+ { :test => described_class::Action.coerce(:action => 'Spec::Action::Success') }
17
+ }
18
18
 
19
19
  it { should eql(described_class.new(coerced, env)) }
20
20
  end
@@ -1,45 +1,40 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Substation::Environment, '#chain' do
4
6
 
5
- let(:object) { described_class.build(&block) }
7
+ let(:object) { described_class.new(registry, dsl) }
6
8
 
7
- let(:expected) { Chain.build(dsl, other, &chain) }
8
- let(:other) { Chain::EMPTY }
9
- let(:chain) { lambda { |_| test Spec::FAKE_HANDLER } }
10
9
  let(:dsl) { Chain::DSL::Builder.call(registry) }
11
- let(:registry) { described_class::DSL.registry(&block) }
12
- let(:block) { lambda { |_| register(:test, Spec::Processor) } }
10
+ let(:registry) { described_class::DSL.registry(&r_block) }
11
+ let(:r_block) { ->(_) { register(:test, Spec::Processor) } }
13
12
 
14
- context "when other is not given" do
15
- context "and a block is given" do
16
- subject { object.chain(&chain) }
13
+ let(:other) { mock('other', :each => EMPTY_ARRAY) }
14
+ let(:failure_chain) { mock('failure_chain') }
15
+ let(:block) { ->(_) { test Spec::FAKE_HANDLER, Chain::EMPTY } }
17
16
 
18
- it { should eql(expected) }
19
- end
17
+ context 'when other, failure_chain and block are given' do
18
+ subject { object.chain(other, failure_chain, &block) }
20
19
 
21
- context "and no block is given" do
22
- subject { object.chain }
20
+ it { should eql(dsl.build(other, failure_chain, &block)) }
21
+ end
23
22
 
24
- let(:expected) { Chain.build(dsl, other) }
23
+ context 'when other, failure_chain and no block are given' do
24
+ subject { object.chain(other, failure_chain) }
25
25
 
26
- it { should eql(expected) }
27
- end
26
+ it { should eql(dsl.build(other, failure_chain)) }
28
27
  end
29
28
 
30
- context "when other is given" do
31
- context "and a block is given" do
32
- subject { object.chain(other, &chain) }
29
+ context 'when other, no failure_chain and no block are given' do
30
+ subject { object.chain(other) }
33
31
 
34
- it { should eql(expected) }
35
- end
36
-
37
- context "and no block is given" do
38
- subject { object.chain(other) }
32
+ it { should eql(dsl.build(other, Chain::EMPTY)) }
33
+ end
39
34
 
40
- let(:expected) { Chain.build(dsl, other) }
35
+ context 'when no parameters are given' do
36
+ subject { object.chain }
41
37
 
42
- it { should eql(expected) }
43
- end
38
+ it { should eql(dsl.build(Chain::EMPTY, Chain::EMPTY)) }
44
39
  end
45
40
  end
@@ -1,11 +1,18 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe Substation::Environment, '.build' do
5
+ describe Environment, '.build' do
4
6
  subject { described_class.build(&block) }
5
7
 
6
- let(:block) { lambda { |_| register(:test, Substation) } }
7
- let(:expected) { described_class.new(registry) }
8
- let(:registry) { described_class::DSL.registry(&block) }
8
+ let(:expected) { Environment.new(registry, chain_dsl) }
9
+ let(:chain_dsl) { Chain::DSL::Builder.call(registry) }
10
+ let(:registry) { described_class::DSL.new(&block).registry }
11
+ let(:block) { ->(_) { register(:test, Substation) } }
9
12
 
10
13
  it { should eql(expected) }
14
+
15
+ it 'uses the compiled dsl' do
16
+ expect(subject.chain).to eql(chain_dsl.build(Chain::EMPTY, Chain::EMPTY))
17
+ end
11
18
  end
@@ -1,16 +1,18 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Substation::Environment::DSL, '.registry' do
4
- context "when a block is given" do
6
+ context 'when a block is given' do
5
7
  subject { described_class.registry(&block) }
6
8
 
7
- let(:block) { lambda { |_| register :test, Spec::Processor } }
9
+ let(:block) { ->(_) { register :test, Spec::Processor } }
8
10
  let(:expected) { { :test => Spec::Processor } }
9
11
 
10
12
  it { should eql(expected) }
11
13
  end
12
14
 
13
- context "when no block is given" do
15
+ context 'when no block is given' do
14
16
  subject { described_class.registry }
15
17
 
16
18
  it { should eql({}) }
@@ -1,6 +1,8 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe Substation::Environment::DSL, '#register' do
5
+ describe Environment::DSL, '#register' do
4
6
  subject { object.register(name, processor) }
5
7
 
6
8
  let(:object) { described_class.new }
@@ -8,7 +10,10 @@ describe Substation::Environment::DSL, '#register' do
8
10
  let(:processor) { Spec::Processor }
9
11
 
10
12
  let(:expected) { { :test => Spec::Processor } }
11
- let(:block) { lambda { |_| register :test, Spec::Processor } }
12
13
 
13
- its(:registry) { should eql(expected) }
14
+ it_behaves_like 'a command method'
15
+
16
+ it 'registers the given processor' do
17
+ expect(subject.registry).to eql(expected)
18
+ end
14
19
  end