substation 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/Changelog.md +92 -2
- data/Gemfile.devtools +19 -17
- data/README.md +116 -46
- data/config/flay.yml +2 -2
- data/config/mutant.yml +1 -0
- data/config/reek.yml +11 -5
- data/config/rubocop.yml +35 -0
- data/lib/substation.rb +10 -1
- data/lib/substation/chain.rb +108 -64
- data/lib/substation/chain/dsl.rb +62 -37
- data/lib/substation/dispatcher.rb +3 -1
- data/lib/substation/environment.rb +9 -6
- data/lib/substation/environment/dsl.rb +4 -3
- data/lib/substation/observer.rb +2 -0
- data/lib/substation/processor.rb +106 -7
- data/lib/substation/processor/evaluator.rb +98 -7
- data/lib/substation/processor/transformer.rb +26 -0
- data/lib/substation/processor/wrapper.rb +5 -3
- data/lib/substation/request.rb +12 -1
- data/lib/substation/response.rb +13 -0
- data/lib/substation/utils.rb +3 -1
- data/lib/substation/version.rb +3 -1
- data/spec/integration/substation/dispatcher/call_spec.rb +12 -12
- data/spec/spec_helper.rb +39 -32
- data/spec/unit/substation/chain/call_spec.rb +205 -29
- data/spec/unit/substation/chain/class_methods/failure_response_spec.rb +16 -0
- data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +7 -4
- data/spec/unit/substation/chain/dsl/class_methods/build_spec.rb +24 -0
- data/spec/unit/substation/chain/dsl/failure_chain_spec.rb +35 -0
- data/spec/unit/substation/chain/dsl/processors_spec.rb +8 -6
- data/spec/unit/substation/chain/dsl/use_spec.rb +1 -1
- data/spec/unit/substation/chain/each_spec.rb +5 -9
- data/spec/unit/substation/chain/failure_data/equalizer_spec.rb +46 -0
- data/spec/unit/substation/chain/failure_data/hash_spec.rb +13 -0
- data/spec/unit/substation/dispatcher/action/call_spec.rb +2 -1
- data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +7 -5
- data/spec/unit/substation/dispatcher/call_spec.rb +2 -2
- data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +6 -6
- data/spec/unit/substation/environment/chain_spec.rb +22 -27
- data/spec/unit/substation/environment/class_methods/build_spec.rb +11 -4
- data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +5 -3
- data/spec/unit/substation/environment/dsl/register_spec.rb +8 -3
- data/spec/unit/substation/environment/dsl/registry_spec.rb +5 -3
- data/spec/unit/substation/environment/equalizer_spec.rb +25 -0
- data/spec/unit/substation/observer/chain/call_spec.rb +2 -0
- data/spec/unit/substation/observer/class_methods/coerce_spec.rb +2 -0
- data/spec/unit/substation/observer/null/call_spec.rb +2 -0
- data/spec/unit/substation/processor/evaluator/call_spec.rb +20 -10
- data/spec/unit/substation/processor/evaluator/class_methods/new_spec.rb +9 -0
- data/spec/unit/substation/processor/evaluator/data/call_spec.rb +34 -0
- data/spec/unit/substation/processor/evaluator/pivot/call_spec.rb +34 -0
- data/spec/unit/substation/processor/evaluator/request/call_spec.rb +34 -0
- data/spec/unit/substation/processor/fallible/name_spec.rb +15 -0
- data/spec/unit/substation/processor/fallible/with_failure_chain_spec.rb +18 -0
- data/spec/unit/substation/processor/incoming/result_spec.rb +25 -0
- data/spec/unit/substation/processor/outgoing/call_spec.rb +28 -0
- data/spec/unit/substation/processor/outgoing/name_spec.rb +14 -0
- data/spec/unit/substation/processor/outgoing/success_predicate_spec.rb +15 -0
- data/spec/unit/substation/{chain/outgoing → processor}/result_spec.rb +4 -3
- data/spec/unit/substation/processor/success_predicate_spec.rb +22 -0
- data/spec/unit/substation/processor/transformer/call_spec.rb +21 -0
- data/spec/unit/substation/processor/wrapper/call_spec.rb +9 -7
- data/spec/unit/substation/request/env_spec.rb +3 -2
- data/spec/unit/substation/request/error_spec.rb +2 -1
- data/spec/unit/substation/request/input_spec.rb +3 -2
- data/spec/unit/substation/request/name_spec.rb +15 -0
- data/spec/unit/substation/request/success_spec.rb +2 -1
- data/spec/unit/substation/response/env_spec.rb +3 -2
- data/spec/unit/substation/response/failure/success_predicate_spec.rb +2 -1
- data/spec/unit/substation/response/input_spec.rb +3 -2
- data/spec/unit/substation/response/output_spec.rb +2 -1
- data/spec/unit/substation/response/request_spec.rb +3 -2
- data/spec/unit/substation/response/success/success_predicate_spec.rb +2 -1
- data/spec/unit/substation/response/to_request_spec.rb +19 -0
- data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +14 -12
- data/spec/unit/substation/utils/class_methods/const_get_spec.rb +6 -6
- data/spec/unit/substation/utils/class_methods/symbolize_keys_spec.rb +4 -4
- metadata +25 -9
- data/lib/substation/processor/pivot.rb +0 -25
- data/spec/unit/substation/chain/class_methods/build_spec.rb +0 -31
- data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +0 -23
- data/spec/unit/substation/chain/incoming/result_spec.rb +0 -21
- data/spec/unit/substation/chain/outgoing/call_spec.rb +0 -25
- data/spec/unit/substation/processor/pivot/call_spec.rb +0 -16
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
@@ -1,8 +1,98 @@
|
|
1
|
-
# v0.0.
|
1
|
+
# v0.0.10 (not yet released)
|
2
2
|
|
3
3
|
*
|
4
4
|
|
5
|
-
[Compare v0.0.
|
5
|
+
[Compare v0.0.9..master](https://github.com/snusnu/substation/compare/v0.0.9...master)
|
6
|
+
|
7
|
+
# v0.0.9 2013-07-10
|
8
|
+
|
9
|
+
* [BREAKING CHANGE] Refactor `Substation::Processor` classes.
|
10
|
+
|
11
|
+
* Renamed `Substation::Processor::Evaluator` to `Substation::Processor::Evaluator::Data`.
|
12
|
+
* Renamed `Substation::Processor::Pivot` to `Substation::Processor::Evaluator::Pivot`.
|
13
|
+
* Added `Substation::Processor::Evaluator::Request` which passes the complete `Request` instance on to the handler.
|
14
|
+
* Added `Substation::Processor::Transformer` to transform `Response#output` into any other object.
|
15
|
+
|
16
|
+
* [feature] Make the dispatched name available in `Request#name`.
|
17
|
+
|
18
|
+
* [feature] Support (re)definining failure chains for `Substation::Processor::Fallible` processors.
|
19
|
+
|
20
|
+
module Demo
|
21
|
+
ENV = Substation::Environment.build do
|
22
|
+
register :validate, Substation::Processor::Evaluator::Data
|
23
|
+
register :call, Substation::Processor::Evaluator::Pivot
|
24
|
+
register :wrap, Substation::Processor::Wrapper
|
25
|
+
register :render, Substation::Processor::Transformer
|
26
|
+
end
|
27
|
+
|
28
|
+
class Error
|
29
|
+
attr_reader :data
|
30
|
+
def initialize(data)
|
31
|
+
@data = data
|
32
|
+
end
|
33
|
+
|
34
|
+
ValidationError = Class.new(self)
|
35
|
+
ApplicationError = Class.new(self)
|
36
|
+
InternalError = Class.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
module App
|
40
|
+
VALIDATION_ERROR = Demo::ENV.chain { wrap Error::ValidationError }
|
41
|
+
APPLICATION_ERROR = Demo::ENV.chain { wrap Error::ApplicationError }
|
42
|
+
|
43
|
+
SOME_ACTION = Demo::ENV.chain do
|
44
|
+
validate Vanguard::Validator, VALIDATION_ERROR
|
45
|
+
call Some::Action, APPLICATION_ERROR
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Web
|
50
|
+
VALIDATION_ERROR = Demo::ENV.chain(App::VALIDATION_ERROR) do
|
51
|
+
render Renderer::ValidationError
|
52
|
+
end
|
53
|
+
|
54
|
+
APPLICATION_ERROR = Demo::ENV.chain(App::APPLICATION_ERROR) do
|
55
|
+
render Renderer::ApplicationError
|
56
|
+
end
|
57
|
+
|
58
|
+
# in case of success, returns an instance of Views::Person
|
59
|
+
# in case of validation failure, renders using Renderer::ValidationError
|
60
|
+
# in case of internal error, renders using Renderer::InternalError
|
61
|
+
SOME_ACTION = Demo::ENV.chain(App::SOME_ACTION) do
|
62
|
+
failure_chain :validate, VALIDATION_ERROR
|
63
|
+
failure_chain :call, INTERNAL_ERROR
|
64
|
+
wrap Presenters::Person
|
65
|
+
wrap Views::ShowPerson
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
* [feature] Support (re)defining chain specific failure chains in case of uncaught exceptions.
|
71
|
+
|
72
|
+
module Demo
|
73
|
+
|
74
|
+
module App
|
75
|
+
INTERNAL_ERROR = Demo::ENV.chain { wrap Error::InternalError }
|
76
|
+
end
|
77
|
+
|
78
|
+
module Web
|
79
|
+
|
80
|
+
INTERNAL_ERROR = Demo::ENV.chain(App::INTERNAL_ERROR) do
|
81
|
+
render Renderer::InternalError
|
82
|
+
end
|
83
|
+
|
84
|
+
# The INTERNAL_ERROR chain will be called if an exception
|
85
|
+
# isn't rescued by the responsible handler
|
86
|
+
SOME_ACTION = Demo::ENV.chain(App::SOME_ACTION, INTERNAL_ERROR) do
|
87
|
+
failure_chain :validate, VALIDATION_ERROR
|
88
|
+
failure_chain :call, INTERNAL_ERROR
|
89
|
+
wrap Presenters::Person
|
90
|
+
wrap Views::ShowPerson
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
[Compare v0.0.8..v0.0.9](https://github.com/snusnu/substation/compare/v0.0.8...v0.0.9)
|
6
96
|
|
7
97
|
# v0.0.8 2013-06-19
|
8
98
|
|
data/Gemfile.devtools
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
group :development do
|
4
|
-
gem 'rake', '~> 10.0
|
4
|
+
gem 'rake', '~> 10.1.0'
|
5
5
|
gem 'rspec', '~> 2.13.0'
|
6
|
-
gem 'yard', '~> 0.8.6.
|
6
|
+
gem 'yard', '~> 0.8.6.2'
|
7
7
|
end
|
8
8
|
|
9
9
|
group :yard do
|
10
|
-
gem 'kramdown', '~> 1.0
|
10
|
+
gem 'kramdown', '~> 1.1.0'
|
11
11
|
end
|
12
12
|
|
13
13
|
group :guard do
|
14
|
-
gem 'guard', '~> 1.8.
|
14
|
+
gem 'guard', '~> 1.8.1'
|
15
15
|
gem 'guard-bundler', '~> 1.0.0'
|
16
|
-
gem 'guard-rspec', '~>
|
16
|
+
gem 'guard-rspec', '~> 3.0.2'
|
17
|
+
gem 'guard-rubocop', '~> 0.2.0'
|
17
18
|
|
18
19
|
# file system change event handling
|
19
|
-
gem 'listen', '~> 1.
|
20
|
+
gem 'listen', '~> 1.2.2'
|
20
21
|
gem 'rb-fchange', '~> 0.0.6', :require => false
|
21
22
|
gem 'rb-fsevent', '~> 0.9.3', :require => false
|
22
23
|
gem 'rb-inotify', '~> 0.9.0', :require => false
|
@@ -28,20 +29,21 @@ group :guard do
|
|
28
29
|
end
|
29
30
|
|
30
31
|
group :metrics do
|
31
|
-
gem '
|
32
|
-
gem '
|
33
|
-
gem '
|
34
|
-
gem '
|
35
|
-
gem '
|
36
|
-
gem 'simplecov',
|
37
|
-
gem 'yardstick',
|
38
|
-
|
39
|
-
platforms :ruby_19 do
|
32
|
+
gem 'coveralls', '~> 0.6.7'
|
33
|
+
gem 'flay', '~> 2.3.0'
|
34
|
+
gem 'flog', '~> 4.1.0'
|
35
|
+
gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git'
|
36
|
+
gem 'rubocop', '~> 0.9.1'
|
37
|
+
gem 'simplecov', '~> 0.7.1'
|
38
|
+
gem 'yardstick', '~> 0.9.6'
|
39
|
+
|
40
|
+
platforms :ruby_19, :ruby_20 do
|
41
|
+
gem 'mutant', '~> 0.3.0.beta13'
|
40
42
|
gem 'yard-spellcheck', '~> 0.1.5'
|
41
43
|
end
|
42
44
|
|
43
|
-
platforms :
|
44
|
-
gem '
|
45
|
+
platforms :ruby_19 do
|
46
|
+
gem 'json', '~> 1.8.0'
|
45
47
|
end
|
46
48
|
|
47
49
|
platforms :rbx do
|
data/README.md
CHANGED
@@ -22,7 +22,8 @@ receive arbitrary input data which will be available in `request.input`.
|
|
22
22
|
Additionally, `request.env` contains an arbitrary object that
|
23
23
|
represents your application environment and will typically provide access
|
24
24
|
to useful things like a logger and probably some sort of storage engine
|
25
|
-
abstraction object.
|
25
|
+
abstraction object. Furthermore, `request.name` will contain the action
|
26
|
+
name the `Substation::Dispatcher` used when dispatching to an action.
|
26
27
|
|
27
28
|
The contract further specifies that every action must return an instance
|
28
29
|
of either `Substation::Response::Success` or
|
@@ -509,9 +510,9 @@ In a typical application scenario, a few things need to happen before an
|
|
509
510
|
actual use case (an action) can be invoked. These things will often
|
510
511
|
include the following steps (probably in that order).
|
511
512
|
|
513
|
+
* Input data sanitization
|
512
514
|
* Authentication
|
513
515
|
* Authorization
|
514
|
-
* Input data sanitization
|
515
516
|
* Input data validation
|
516
517
|
|
517
518
|
We only want to invoke our action if all those steps succeed. If any of
|
@@ -541,129 +542,198 @@ b) If you need to return JSON, you might just
|
|
541
542
|
* Pass the response data to some serializer object and dump it to JSON
|
542
543
|
|
543
544
|
To allow chaining all those steps in a declarative way, substation
|
544
|
-
provides an object called `Substation::Chain`.
|
545
|
-
|
546
|
-
|
547
|
-
1. `#call(Substation::Request) => Substation::Response`
|
548
|
-
2. `#result(Substation::Response) => Substation::Response`
|
549
|
-
|
550
|
-
You typically won't be calling `Substation::Chain#result` yourself, but
|
551
|
-
having it around, allows us to use chains in *incoming handlers*,
|
552
|
-
essentially nesting chains. This makes it possible to construct one
|
553
|
-
chain up until the pivot handler, and then reuse that same chain in one
|
554
|
-
usecase that takes the response and renders HTML, and in another that
|
555
|
-
renders JSON.
|
556
|
-
|
557
|
-
To construct a chain, you need to pass an enumerable of so called
|
558
|
-
handler objects to `Substation::Chain.new`. Handlers must support two
|
559
|
-
methods:
|
545
|
+
provides an object called `Substation::Chain`. To construct a chain, you
|
546
|
+
need to pass an enumerable of processors to `Substation::Chain#initialize`.
|
547
|
+
Processors must support three methods:
|
560
548
|
|
561
549
|
1. `#call(<Substation::Request, Substation::Response>) => Substation::Response`
|
562
550
|
2. `#result(Substation::Response) => <Substation::Request, Substation::Response>`
|
551
|
+
3. `#success?(Substation::Response) => Boolean`
|
563
552
|
|
564
|
-
### Incoming
|
553
|
+
### Incoming processors
|
565
554
|
|
566
555
|
All steps required *before* processing the action will potentially
|
567
556
|
produce a new, altered, `Substation::Request`. Therefore, the object
|
568
557
|
passed to `#call` must be an instance of `Substation::Request`.
|
569
558
|
|
570
559
|
Since `#call` must return a `Substation::Response` (because the chain
|
571
|
-
would halt and return that response in case calling
|
560
|
+
would halt and return that response in case calling `Processor#success?`
|
572
561
|
method would return `false`), we also need to implement `#result`
|
573
562
|
and have it return a `Substation::Request` instance that can be passed
|
574
563
|
on to the next handler.
|
575
564
|
|
576
|
-
The contract for incoming
|
565
|
+
The contract for incoming processors therefore is:
|
577
566
|
|
578
567
|
1. `#call(Substation::Request) => Substation::Response`
|
579
568
|
2. `#result(Substation::Response) => Substation::Request`
|
569
|
+
3. `#success?(Substation::Response) => Boolean`
|
580
570
|
|
581
|
-
By including the `Substation::
|
582
|
-
class, you'll get the following for free:
|
571
|
+
By including the `Substation::Processor::Incoming` module into your
|
572
|
+
processor class, you'll get the following for free:
|
583
573
|
|
584
574
|
```ruby
|
575
|
+
def initialize(name, handler, failure_chain)
|
576
|
+
@name, @handler, @failure_chain = name, handler, failure_chain
|
577
|
+
end
|
578
|
+
|
585
579
|
def result(response)
|
586
|
-
|
580
|
+
response.to_request
|
581
|
+
end
|
582
|
+
|
583
|
+
def success?(response)
|
584
|
+
response.success?
|
585
|
+
end
|
586
|
+
|
587
|
+
def with_failure_chain(chain)
|
588
|
+
self.class.new(name, handler, chain)
|
587
589
|
end
|
588
590
|
```
|
589
591
|
|
590
|
-
This shows that an incoming
|
592
|
+
This shows that an incoming processor can alter the incoming request in any
|
591
593
|
way that it wants to, as long as it returns the new request input data in
|
592
594
|
`Substation::Response#output` returned from `#call`.
|
593
595
|
|
594
|
-
|
596
|
+
Currently, `substation` provides the following incoming processors out
|
597
|
+
of the box:
|
598
|
+
|
599
|
+
* `Substation::Processor::Evaluator::Request` passes `request` to the handler
|
600
|
+
* `Substation::Processor::Evaluator::Data` passes `request.input` to the handler
|
601
|
+
|
602
|
+
### The pivot processor
|
595
603
|
|
596
604
|
Pivot is just another fancy name for the action in the context of a
|
597
|
-
chain. It's also the point where all subsequent
|
605
|
+
chain. It's also the point where all subsequent processors have to further
|
598
606
|
process the `Substation::Response` returned from invoking the action.
|
607
|
+
Therefore, the pivot processor is the last processor that expects a
|
608
|
+
`Substation::Request` as parameter to its `#call` method.
|
599
609
|
|
600
|
-
The contract for the pivot
|
610
|
+
The contract for the pivot processor therefore is:
|
601
611
|
|
602
612
|
1. `#call(Substation::Request) => Substation::Response`
|
603
613
|
2. `#result(Substation::Response) => Substation::Response`
|
614
|
+
3. `#success?(Substation::Response) => Boolean`
|
604
615
|
|
605
|
-
By including the `Substation::
|
616
|
+
By including the `Substation::Processor::Pivot` module into your handler
|
606
617
|
class, you'll get the following for free:
|
607
618
|
|
608
619
|
```ruby
|
620
|
+
def initialize(name, handler, failure_chain)
|
621
|
+
@name, @handler, @failure_chain = name, handler, failure_chain
|
622
|
+
end
|
623
|
+
|
609
624
|
def result(response)
|
610
625
|
response
|
611
626
|
end
|
627
|
+
|
628
|
+
def success?(response)
|
629
|
+
response.success?
|
630
|
+
end
|
631
|
+
|
632
|
+
def with_failure_chain(chain)
|
633
|
+
self.class.new(name, handler, chain)
|
634
|
+
end
|
612
635
|
```
|
613
636
|
|
614
|
-
This reflects the fact that a pivot
|
615
|
-
producing the "raw" response, returns it unaltered.
|
637
|
+
This reflects the fact that a pivot processor (since it's the one actually
|
638
|
+
producing the "raw" response, returns it unaltered).
|
639
|
+
|
640
|
+
The pivot processor is shipped with `substation` and is implemented by
|
641
|
+
`Substation::Processor::Evaluator::Pivot`.
|
616
642
|
|
617
|
-
### Outgoing
|
643
|
+
### Outgoing processors
|
618
644
|
|
619
645
|
All steps required *after* processing the action will potentially
|
620
646
|
produce a new, altered, `Substation::Response` instance to be returned.
|
621
647
|
Therefore the object passed to `#call` must be an instance of
|
622
|
-
`Substation::Response`. Since subsequent outgoing
|
648
|
+
`Substation::Response`. Since subsequent outgoing processors might further
|
623
649
|
process the response, `#result` must be implemented so that it returns a
|
624
|
-
`Substation::Response` object that can be passed on to the next
|
650
|
+
`Substation::Response` object that can be passed on to the next
|
651
|
+
processor.
|
625
652
|
|
626
|
-
The contract for outgoing
|
653
|
+
The contract for outgoing processors therefore is:
|
627
654
|
|
628
655
|
1. `#call(Substation::Response) => Substation::Response`
|
629
656
|
2. `#result(Substation::Response) => Substation::Response`
|
657
|
+
3. `#success?(Substation::Response) => true`
|
630
658
|
|
631
|
-
By including the `Substation::
|
632
|
-
class, you'll get the following for free:
|
659
|
+
By including the `Substation::Processor::Outgoing` module into your
|
660
|
+
processor class, you'll get the following for free:
|
633
661
|
|
634
662
|
```ruby
|
663
|
+
def initialize(name, handler)
|
664
|
+
@name, @handler = name, handler
|
665
|
+
end
|
666
|
+
|
635
667
|
def result(response)
|
636
668
|
response
|
637
669
|
end
|
670
|
+
|
671
|
+
def success?(response)
|
672
|
+
true
|
673
|
+
end
|
674
|
+
|
675
|
+
private
|
676
|
+
|
677
|
+
def respond_with(response, output)
|
678
|
+
response.class.new(response.request, output)
|
679
|
+
end
|
638
680
|
```
|
639
681
|
|
640
|
-
This shows that an outgoing
|
682
|
+
This shows that an outgoing processor's `#call` can do anything with
|
641
683
|
the `Substation::Response#output` it received, as long as it makes
|
642
684
|
sure to return a new response with the new output properly set.
|
643
685
|
|
686
|
+
Currently, `substation` provides the following outgoing processors out
|
687
|
+
of the box:
|
688
|
+
|
689
|
+
* `Substation::Processor::Wrapper` wraps `response.output` in a new handler instance
|
690
|
+
* `Substation::Processor::Transformer` transforms `response.output` using a new handler instance
|
691
|
+
|
692
|
+
### Handlers
|
693
|
+
|
694
|
+
You might have noticed the `handler` param passed to any processor's
|
695
|
+
`#initialize` method. Handlers are the actual objects performing your
|
696
|
+
application logic. Processors use these handlers to produce the data
|
697
|
+
they're supposed to "pipe through the chain".
|
698
|
+
|
699
|
+
The interface your handlers must implement should be familiar by now.
|
700
|
+
|
701
|
+
All handlers to be used with incoming processors must accept an instance
|
702
|
+
of `Substation::Request` as parameter to `#call`. Handlers to be used
|
703
|
+
with `Substation::Processor::Evaluator` subclasses must furthermore
|
704
|
+
return an object that responds to `#success?` and `#output`.
|
705
|
+
|
706
|
+
Note how the interface required for evaluator handler return values
|
707
|
+
matches the interface a `Substation::Response` exposes. This means that
|
708
|
+
the pivot processor can be (and is) implemented using the builtin
|
709
|
+
`Substation::Processor::Evaluator::Request` processor. The handler you
|
710
|
+
pass to the pivot processor is the object that actually implements your
|
711
|
+
application usecase, the action, and it's response gets evaluated.
|
712
|
+
|
713
|
+
All handlers to be used with outgoing processors must accept an instance
|
714
|
+
of `Substation::Response` as parameter to `#call`. They can do whatever
|
715
|
+
they want with the passed in response, but they must make sure to return
|
716
|
+
another instance of `Substation::Response`. To help with this, outgoing
|
717
|
+
processors provide the `#respond_with(response, data)` method that
|
718
|
+
you'll typically call to return the response value for `#call`.
|
719
|
+
|
644
720
|
### Example
|
645
721
|
|
646
722
|
[substation-demo](https://github.com/snusnu/substation-demo) implements a
|
647
723
|
simple web application using `Substation::Chain`.
|
648
724
|
|
649
|
-
The demo
|
725
|
+
The demo uses a few of the above mentioned *incoming processors*
|
650
726
|
for
|
651
727
|
|
652
728
|
* [Sanitization](https://github.com/snusnu/substation-demo/blob/master/demo/web/sanitizers.rb) using [ducktrap](https://github.com/mbj/ducktrap)
|
653
729
|
* [Validation](https://github.com/snusnu/substation-demo/blob/master/demo/validators.rb) using [vanguard](https://github.com/mbj/vanguard)
|
654
730
|
|
655
|
-
and some simple *outgoing
|
731
|
+
and some simple *outgoing processors* for
|
656
732
|
|
657
733
|
* Wrapping response output in a
|
658
734
|
[presenter](https://github.com/snusnu/substation-demo/blob/master/demo/web/presenters.rb)
|
659
735
|
* [Serializing](https://github.com/snusnu/substation-demo/blob/master/demo/web/serializers.rb) response output to JSON
|
660
736
|
|
661
|
-
The
|
662
|
-
[handlers](https://github.com/snusnu/substation-demo/blob/master/demo/web/processors.rb)
|
663
|
-
are called *processors* in that app, and encapsulate the actual handler
|
664
|
-
performing the job. That's a common pattern, because you typically will
|
665
|
-
have to adapt to the interface your actual handlers provide.
|
666
|
-
|
667
737
|
Have a look at the base
|
668
738
|
[actions](https://github.com/snusnu/substation-demo/blob/master/demo/web/actions.rb)
|
669
739
|
that are then used to either produce
|
data/config/flay.yml
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
---
|
2
|
-
threshold:
|
3
|
-
total_score:
|
2
|
+
threshold: 9
|
3
|
+
total_score: 134
|
data/config/mutant.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -25,9 +25,10 @@ FeatureEnvy:
|
|
25
25
|
enabled: true
|
26
26
|
exclude:
|
27
27
|
- Substation::Chain#call # loops over instance state
|
28
|
-
- Substation::
|
29
|
-
- Substation::Chain::Outgoing#respond_with #defined in a module
|
28
|
+
- Substation::Processor::Outgoing#respond_with #defined in a module
|
30
29
|
- Substation::Processor::Evaluator#call # method object
|
30
|
+
- Substation::Processor::Evaluator#on_success # method object
|
31
|
+
- Substation::Processor#success? # in a module to be included in a method object
|
31
32
|
IrresponsibleModule:
|
32
33
|
enabled: true
|
33
34
|
exclude: []
|
@@ -36,6 +37,8 @@ LongParameterList:
|
|
36
37
|
exclude:
|
37
38
|
- Substation::Dispatcher#call
|
38
39
|
- Substation::Chain::DSL::Builder#define_dsl_method
|
40
|
+
- Substation::Chain#self.failure_response
|
41
|
+
- Substation::Chain#on_failure
|
39
42
|
max_params: 2
|
40
43
|
LongYieldList:
|
41
44
|
enabled: true
|
@@ -58,10 +61,12 @@ TooManyInstanceVariables:
|
|
58
61
|
enabled: true
|
59
62
|
exclude:
|
60
63
|
- Substation::Response
|
64
|
+
- Substation::Processor::Evaluator
|
61
65
|
max_instance_variables: 3
|
62
66
|
TooManyMethods:
|
63
67
|
enabled: true
|
64
|
-
exclude:
|
68
|
+
exclude:
|
69
|
+
- Substation::Chain::DSL
|
65
70
|
max_methods: 4
|
66
71
|
TooManyStatements:
|
67
72
|
enabled: true
|
@@ -110,6 +115,7 @@ UnusedParameters:
|
|
110
115
|
UtilityFunction:
|
111
116
|
enabled: true
|
112
117
|
exclude:
|
113
|
-
- Substation::
|
114
|
-
- Substation::
|
118
|
+
- Substation::Processor::Outgoing#respond_with # defined in a module
|
119
|
+
- Substation::Processor::Evaluator#on_success # inside a method object
|
120
|
+
- Substation::Processor#success? # in a module to be included in a method object
|
115
121
|
max_helper_calls: 0
|