substation 0.0.9 → 0.0.10.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +0 -1
- data/Changelog.md +24 -82
- data/Gemfile.devtools +17 -24
- data/README.md +46 -116
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/mutant.yml +0 -1
- data/config/reek.yml +5 -10
- data/lib/substation.rb +3 -8
- data/lib/substation/chain.rb +64 -108
- data/lib/substation/chain/dsl.rb +30 -57
- data/lib/substation/dispatcher.rb +1 -3
- data/lib/substation/environment.rb +23 -9
- data/lib/substation/environment/dsl.rb +3 -4
- data/lib/substation/observer.rb +2 -4
- data/lib/substation/processor.rb +7 -106
- data/lib/substation/processor/evaluator.rb +42 -83
- data/lib/substation/processor/pivot.rb +25 -0
- data/lib/substation/processor/wrapper.rb +2 -4
- data/lib/substation/request.rb +1 -10
- data/lib/substation/response.rb +0 -11
- data/lib/substation/utils.rb +1 -3
- data/lib/substation/version.rb +1 -3
- data/spec/integration/substation/dispatcher/call_spec.rb +12 -12
- data/spec/spec_helper.rb +21 -30
- data/spec/unit/substation/chain/call_spec.rb +32 -202
- data/spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb +2 -2
- data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +6 -8
- data/spec/unit/substation/chain/dsl/builder/failure_chain_spec.rb +30 -0
- data/spec/unit/substation/chain/dsl/chain_spec.rb +2 -1
- data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +24 -0
- data/spec/unit/substation/chain/dsl/initialize_spec.rb +19 -0
- data/spec/unit/substation/chain/dsl/processors_spec.rb +21 -9
- data/spec/unit/substation/chain/dsl/use_spec.rb +3 -2
- data/spec/unit/substation/chain/each_spec.rb +9 -5
- data/spec/unit/substation/chain/incoming/result_spec.rb +21 -0
- data/spec/unit/substation/chain/outgoing/call_spec.rb +25 -0
- data/spec/unit/substation/{processor → chain/outgoing}/result_spec.rb +5 -6
- data/spec/unit/substation/dispatcher/action/call_spec.rb +6 -7
- data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +5 -7
- data/spec/unit/substation/dispatcher/action_names_spec.rb +1 -1
- data/spec/unit/substation/dispatcher/call_spec.rb +3 -3
- data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +7 -7
- data/spec/unit/substation/environment/chain_spec.rb +32 -22
- data/spec/unit/substation/environment/class_methods/build_spec.rb +4 -11
- data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +3 -5
- data/spec/unit/substation/environment/dsl/register_spec.rb +3 -8
- data/spec/unit/substation/environment/dsl/registry_spec.rb +3 -5
- data/spec/unit/substation/observer/chain/call_spec.rb +3 -5
- data/spec/unit/substation/observer/class_methods/coerce_spec.rb +2 -4
- data/spec/unit/substation/observer/null/call_spec.rb +1 -3
- data/spec/unit/substation/processor/evaluator/call_spec.rb +35 -21
- data/spec/unit/substation/processor/pivot/call_spec.rb +17 -0
- data/spec/unit/substation/processor/wrapper/call_spec.rb +7 -8
- data/spec/unit/substation/request/env_spec.rb +4 -5
- data/spec/unit/substation/request/error_spec.rb +4 -5
- data/spec/unit/substation/request/input_spec.rb +4 -5
- data/spec/unit/substation/request/success_spec.rb +4 -5
- data/spec/unit/substation/response/env_spec.rb +5 -6
- data/spec/unit/substation/response/failure/success_predicate_spec.rb +4 -5
- data/spec/unit/substation/response/input_spec.rb +5 -6
- data/spec/unit/substation/response/output_spec.rb +4 -5
- data/spec/unit/substation/response/request_spec.rb +5 -6
- data/spec/unit/substation/response/success/success_predicate_spec.rb +4 -5
- data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +13 -15
- 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
- data/substation.gemspec +1 -1
- metadata +18 -45
- data/config/rubocop.yml +0 -35
- data/lib/substation/processor/transformer.rb +0 -26
- data/spec/unit/substation/chain/class_methods/failure_response_spec.rb +0 -16
- data/spec/unit/substation/chain/dsl/class_methods/build_spec.rb +0 -24
- data/spec/unit/substation/chain/dsl/failure_chain_spec.rb +0 -35
- data/spec/unit/substation/chain/failure_data/equalizer_spec.rb +0 -46
- data/spec/unit/substation/chain/failure_data/hash_spec.rb +0 -13
- data/spec/unit/substation/environment/equalizer_spec.rb +0 -25
- data/spec/unit/substation/processor/evaluator/class_methods/new_spec.rb +0 -9
- data/spec/unit/substation/processor/evaluator/data/call_spec.rb +0 -34
- data/spec/unit/substation/processor/evaluator/pivot/call_spec.rb +0 -34
- data/spec/unit/substation/processor/evaluator/request/call_spec.rb +0 -34
- data/spec/unit/substation/processor/fallible/name_spec.rb +0 -15
- data/spec/unit/substation/processor/fallible/with_failure_chain_spec.rb +0 -18
- data/spec/unit/substation/processor/incoming/result_spec.rb +0 -25
- data/spec/unit/substation/processor/outgoing/call_spec.rb +0 -28
- data/spec/unit/substation/processor/outgoing/name_spec.rb +0 -14
- data/spec/unit/substation/processor/outgoing/success_predicate_spec.rb +0 -15
- data/spec/unit/substation/processor/success_predicate_spec.rb +0 -22
- data/spec/unit/substation/processor/transformer/call_spec.rb +0 -21
- data/spec/unit/substation/request/name_spec.rb +0 -15
- data/spec/unit/substation/response/to_request_spec.rb +0 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 674a347348ff4f36dbca255925b70c9ea794c95d
|
4
|
+
data.tar.gz: a28efb6f4038ee99e8f820f2dcaee74506e4182b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a9dcabb1d4a225cee6a4579587387c3829747fcaf77319ae2a0c2a2863eae6558c4d825e6c48f59ecc7d2a860831ae8dcadcda053d947f431b9b73bbaa0c593
|
7
|
+
data.tar.gz: bbd1fca2660e54697b3d1d8f5a69e4a527cf5a129a0995e589cf99966d7c54f9a10b30313e3f51b91a60b4ea38443dcb0a5f3e68253e028ffcda4804def5d107
|
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
@@ -1,98 +1,40 @@
|
|
1
|
-
# v0.0.
|
1
|
+
# v0.0.9 (not yet released)
|
2
2
|
|
3
|
-
*
|
3
|
+
* [feature] Support definining failure chains
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
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 }
|
5
|
+
env = Substation::Environment.build do
|
6
|
+
register :evaluate, Substation::Processor::Evaluator
|
7
|
+
register :wrap, Substation::Processor::Wrapper
|
8
|
+
end
|
42
9
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
10
|
+
class Error
|
11
|
+
attr_reader :data
|
12
|
+
def initialize(data)
|
13
|
+
@data = data
|
47
14
|
end
|
48
15
|
|
49
|
-
|
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
|
16
|
+
class ValidationError < self
|
67
17
|
end
|
68
18
|
end
|
69
19
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
module App
|
75
|
-
INTERNAL_ERROR = Demo::ENV.chain { wrap Error::InternalError }
|
20
|
+
chain = env.chain do
|
21
|
+
evaluate Vanguard::Validator do
|
22
|
+
wrap Errors::ValidationError
|
76
23
|
end
|
24
|
+
call Some::Action
|
25
|
+
wrap Some::Presenter
|
26
|
+
end
|
77
27
|
|
78
|
-
|
28
|
+
env = Object.new
|
29
|
+
invalid_request = Substation::Requet.new(env, :invalid)
|
30
|
+
response = chain.call(invalid_request)
|
79
31
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
32
|
+
response.data.instance_of?(Errors::ValidationError)
|
33
|
+
# => true
|
83
34
|
|
84
|
-
|
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
|
35
|
+
response.data.data # => the actual vanguard violation set
|
94
36
|
|
95
|
-
[Compare v0.0.8..
|
37
|
+
[Compare v0.0.8..master](https://github.com/snusnu/substation/compare/v0.0.8...master)
|
96
38
|
|
97
39
|
# v0.0.8 2013-06-19
|
98
40
|
|
data/Gemfile.devtools
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
group :development do
|
4
4
|
gem 'rake', '~> 10.1.0'
|
5
|
-
gem 'rspec', '~> 2.
|
6
|
-
gem 'yard', '~> 0.8.
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
6
|
+
gem 'yard', '~> 0.8.7'
|
7
7
|
end
|
8
8
|
|
9
9
|
group :yard do
|
10
|
-
gem 'kramdown', '~> 1.
|
10
|
+
gem 'kramdown', '~> 1.2.0'
|
11
11
|
end
|
12
12
|
|
13
13
|
group :guard do
|
@@ -15,40 +15,33 @@ group :guard do
|
|
15
15
|
gem 'guard-bundler', '~> 1.0.0'
|
16
16
|
gem 'guard-rspec', '~> 3.0.2'
|
17
17
|
gem 'guard-rubocop', '~> 0.2.0'
|
18
|
+
gem 'guard-mutant', '~> 0.0.1'
|
18
19
|
|
19
20
|
# file system change event handling
|
20
|
-
gem 'listen', '~> 1.
|
21
|
-
gem 'rb-fchange', '~> 0.0.6', :
|
22
|
-
gem 'rb-fsevent', '~> 0.9.3', :
|
23
|
-
gem 'rb-inotify', '~> 0.9.0', :
|
21
|
+
gem 'listen', '~> 1.3.0'
|
22
|
+
gem 'rb-fchange', '~> 0.0.6', require: false
|
23
|
+
gem 'rb-fsevent', '~> 0.9.3', require: false
|
24
|
+
gem 'rb-inotify', '~> 0.9.0', require: false
|
24
25
|
|
25
26
|
# notification handling
|
26
|
-
gem 'libnotify', '~> 0.8.0', :
|
27
|
-
gem 'rb-notifu', '~> 0.0.4', :
|
28
|
-
gem 'terminal-notifier-guard', '~> 1.5.3', :
|
27
|
+
gem 'libnotify', '~> 0.8.0', require: false
|
28
|
+
gem 'rb-notifu', '~> 0.0.4', require: false
|
29
|
+
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
29
30
|
end
|
30
31
|
|
31
32
|
group :metrics do
|
32
33
|
gem 'coveralls', '~> 0.6.7'
|
33
|
-
gem 'flay', '~> 2.
|
34
|
-
gem 'flog', '~> 4.1.
|
35
|
-
gem 'reek', '~> 1.3.
|
36
|
-
gem 'rubocop', '~> 0.
|
34
|
+
gem 'flay', '~> 2.4.0'
|
35
|
+
gem 'flog', '~> 4.1.1'
|
36
|
+
gem 'reek', '~> 1.3.2'
|
37
|
+
gem 'rubocop', '~> 0.13.0'
|
37
38
|
gem 'simplecov', '~> 0.7.1'
|
38
|
-
gem 'yardstick', '~> 0.9.
|
39
|
+
gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
|
39
40
|
|
40
41
|
platforms :ruby_19, :ruby_20 do
|
41
|
-
gem 'mutant',
|
42
|
+
gem 'mutant', git: 'https://github.com/mbj/mutant.git'
|
42
43
|
gem 'yard-spellcheck', '~> 0.1.5'
|
43
44
|
end
|
44
|
-
|
45
|
-
platforms :ruby_19 do
|
46
|
-
gem 'json', '~> 1.8.0'
|
47
|
-
end
|
48
|
-
|
49
|
-
platforms :rbx do
|
50
|
-
gem 'pelusa', '~> 0.2.2'
|
51
|
-
end
|
52
45
|
end
|
53
46
|
|
54
47
|
group :benchmarks do
|
data/README.md
CHANGED
@@ -22,8 +22,7 @@ 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.
|
26
|
-
name the `Substation::Dispatcher` used when dispatching to an action.
|
25
|
+
abstraction object.
|
27
26
|
|
28
27
|
The contract further specifies that every action must return an instance
|
29
28
|
of either `Substation::Response::Success` or
|
@@ -510,9 +509,9 @@ In a typical application scenario, a few things need to happen before an
|
|
510
509
|
actual use case (an action) can be invoked. These things will often
|
511
510
|
include the following steps (probably in that order).
|
512
511
|
|
513
|
-
* Input data sanitization
|
514
512
|
* Authentication
|
515
513
|
* Authorization
|
514
|
+
* Input data sanitization
|
516
515
|
* Input data validation
|
517
516
|
|
518
517
|
We only want to invoke our action if all those steps succeed. If any of
|
@@ -542,198 +541,129 @@ b) If you need to return JSON, you might just
|
|
542
541
|
* Pass the response data to some serializer object and dump it to JSON
|
543
542
|
|
544
543
|
To allow chaining all those steps in a declarative way, substation
|
545
|
-
provides an object called `Substation::Chain`.
|
546
|
-
|
547
|
-
|
544
|
+
provides an object called `Substation::Chain`. Its contract is dead
|
545
|
+
simple:
|
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:
|
548
560
|
|
549
561
|
1. `#call(<Substation::Request, Substation::Response>) => Substation::Response`
|
550
562
|
2. `#result(Substation::Response) => <Substation::Request, Substation::Response>`
|
551
|
-
3. `#success?(Substation::Response) => Boolean`
|
552
563
|
|
553
|
-
### Incoming
|
564
|
+
### Incoming handlers
|
554
565
|
|
555
566
|
All steps required *before* processing the action will potentially
|
556
567
|
produce a new, altered, `Substation::Request`. Therefore, the object
|
557
568
|
passed to `#call` must be an instance of `Substation::Request`.
|
558
569
|
|
559
570
|
Since `#call` must return a `Substation::Response` (because the chain
|
560
|
-
would halt and return that response in case calling
|
571
|
+
would halt and return that response in case calling its `#success?`
|
561
572
|
method would return `false`), we also need to implement `#result`
|
562
573
|
and have it return a `Substation::Request` instance that can be passed
|
563
574
|
on to the next handler.
|
564
575
|
|
565
|
-
The contract for incoming
|
576
|
+
The contract for incoming handlers therefore is:
|
566
577
|
|
567
578
|
1. `#call(Substation::Request) => Substation::Response`
|
568
579
|
2. `#result(Substation::Response) => Substation::Request`
|
569
|
-
3. `#success?(Substation::Response) => Boolean`
|
570
580
|
|
571
|
-
By including the `Substation::
|
572
|
-
|
581
|
+
By including the `Substation::Chain::Incoming` module into your handler
|
582
|
+
class, you'll get the following for free:
|
573
583
|
|
574
584
|
```ruby
|
575
|
-
def initialize(name, handler, failure_chain)
|
576
|
-
@name, @handler, @failure_chain = name, handler, failure_chain
|
577
|
-
end
|
578
|
-
|
579
585
|
def result(response)
|
580
|
-
response.
|
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)
|
586
|
+
Request.new(response.env, response.output)
|
589
587
|
end
|
590
588
|
```
|
591
589
|
|
592
|
-
This shows that an incoming
|
590
|
+
This shows that an incoming handler can alter the incoming request in any
|
593
591
|
way that it wants to, as long as it returns the new request input data in
|
594
592
|
`Substation::Response#output` returned from `#call`.
|
595
593
|
|
596
|
-
|
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
|
594
|
+
### The pivot handler
|
603
595
|
|
604
596
|
Pivot is just another fancy name for the action in the context of a
|
605
|
-
chain. It's also the point where all subsequent
|
597
|
+
chain. It's also the point where all subsequent handlers have to further
|
606
598
|
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.
|
609
599
|
|
610
|
-
The contract for the pivot
|
600
|
+
The contract for the pivot handler therefore is:
|
611
601
|
|
612
602
|
1. `#call(Substation::Request) => Substation::Response`
|
613
603
|
2. `#result(Substation::Response) => Substation::Response`
|
614
|
-
3. `#success?(Substation::Response) => Boolean`
|
615
604
|
|
616
|
-
By including the `Substation::
|
605
|
+
By including the `Substation::Chain::Pivot` module into your handler
|
617
606
|
class, you'll get the following for free:
|
618
607
|
|
619
608
|
```ruby
|
620
|
-
def initialize(name, handler, failure_chain)
|
621
|
-
@name, @handler, @failure_chain = name, handler, failure_chain
|
622
|
-
end
|
623
|
-
|
624
609
|
def result(response)
|
625
610
|
response
|
626
611
|
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
|
635
612
|
```
|
636
613
|
|
637
|
-
This reflects the fact that a pivot
|
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`.
|
614
|
+
This reflects the fact that a pivot handler (since it's the one actually
|
615
|
+
producing the "raw" response, returns it unaltered.
|
642
616
|
|
643
|
-
### Outgoing
|
617
|
+
### Outgoing handlers
|
644
618
|
|
645
619
|
All steps required *after* processing the action will potentially
|
646
620
|
produce a new, altered, `Substation::Response` instance to be returned.
|
647
621
|
Therefore the object passed to `#call` must be an instance of
|
648
|
-
`Substation::Response`. Since subsequent outgoing
|
622
|
+
`Substation::Response`. Since subsequent outgoing handlers might further
|
649
623
|
process the response, `#result` must be implemented so that it returns a
|
650
|
-
`Substation::Response` object that can be passed on to the next
|
651
|
-
processor.
|
624
|
+
`Substation::Response` object that can be passed on to the next handler.
|
652
625
|
|
653
|
-
The contract for outgoing
|
626
|
+
The contract for outgoing handlers therefore is:
|
654
627
|
|
655
628
|
1. `#call(Substation::Response) => Substation::Response`
|
656
629
|
2. `#result(Substation::Response) => Substation::Response`
|
657
|
-
3. `#success?(Substation::Response) => true`
|
658
630
|
|
659
|
-
By including the `Substation::
|
660
|
-
|
631
|
+
By including the `Substation::Chain::Outgoing` module into your handler
|
632
|
+
class, you'll get the following for free:
|
661
633
|
|
662
634
|
```ruby
|
663
|
-
def initialize(name, handler)
|
664
|
-
@name, @handler = name, handler
|
665
|
-
end
|
666
|
-
|
667
635
|
def result(response)
|
668
636
|
response
|
669
637
|
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
|
680
638
|
```
|
681
639
|
|
682
|
-
This shows that an outgoing
|
640
|
+
This shows that an outgoing handler's `#call` can do anything with
|
683
641
|
the `Substation::Response#output` it received, as long as it makes
|
684
642
|
sure to return a new response with the new output properly set.
|
685
643
|
|
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
|
-
|
720
644
|
### Example
|
721
645
|
|
722
646
|
[substation-demo](https://github.com/snusnu/substation-demo) implements a
|
723
647
|
simple web application using `Substation::Chain`.
|
724
648
|
|
725
|
-
The demo
|
649
|
+
The demo implements a few of the above mentioned *incoming handlers*
|
726
650
|
for
|
727
651
|
|
728
652
|
* [Sanitization](https://github.com/snusnu/substation-demo/blob/master/demo/web/sanitizers.rb) using [ducktrap](https://github.com/mbj/ducktrap)
|
729
653
|
* [Validation](https://github.com/snusnu/substation-demo/blob/master/demo/validators.rb) using [vanguard](https://github.com/mbj/vanguard)
|
730
654
|
|
731
|
-
and some simple *outgoing
|
655
|
+
and some simple *outgoing handlers* for
|
732
656
|
|
733
657
|
* Wrapping response output in a
|
734
658
|
[presenter](https://github.com/snusnu/substation-demo/blob/master/demo/web/presenters.rb)
|
735
659
|
* [Serializing](https://github.com/snusnu/substation-demo/blob/master/demo/web/serializers.rb) response output to JSON
|
736
660
|
|
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
|
+
|
737
667
|
Have a look at the base
|
738
668
|
[actions](https://github.com/snusnu/substation-demo/blob/master/demo/web/actions.rb)
|
739
669
|
that are then used to either produce
|