substation 0.0.8 → 0.0.9

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