substation 0.0.7 → 0.0.8

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 (38) hide show
  1. data/.ruby-gemset +1 -0
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +1 -6
  4. data/Changelog.md +47 -8
  5. data/config/flay.yml +1 -1
  6. data/config/flog.yml +1 -1
  7. data/config/reek.yml +7 -1
  8. data/lib/substation.rb +8 -1
  9. data/lib/substation/chain.rb +39 -2
  10. data/lib/substation/chain/dsl.rb +165 -0
  11. data/lib/substation/environment.rb +59 -0
  12. data/lib/substation/environment/dsl.rb +58 -0
  13. data/lib/substation/processor.rb +23 -0
  14. data/lib/substation/processor/evaluator.rb +30 -0
  15. data/lib/substation/processor/pivot.rb +25 -0
  16. data/lib/substation/processor/wrapper.rb +24 -0
  17. data/lib/substation/{support/utils.rb → utils.rb} +0 -0
  18. data/lib/substation/version.rb +1 -1
  19. data/spec/spec_helper.rb +57 -0
  20. data/spec/unit/substation/chain/class_methods/build_spec.rb +31 -0
  21. data/spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb +19 -0
  22. data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +20 -0
  23. data/spec/unit/substation/chain/dsl/chain_spec.rb +14 -0
  24. data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +23 -0
  25. data/spec/unit/substation/chain/dsl/processors_spec.rb +28 -0
  26. data/spec/unit/substation/chain/dsl/use_spec.rb +13 -0
  27. data/spec/unit/substation/chain/each_spec.rb +46 -0
  28. data/spec/unit/substation/chain/outgoing/call_spec.rb +25 -0
  29. data/spec/unit/substation/environment/chain_spec.rb +45 -0
  30. data/spec/unit/substation/environment/class_methods/build_spec.rb +11 -0
  31. data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +18 -0
  32. data/spec/unit/substation/environment/dsl/register_spec.rb +14 -0
  33. data/spec/unit/substation/environment/dsl/registry_spec.rb +19 -0
  34. data/spec/unit/substation/processor/evaluator/call_spec.rb +25 -0
  35. data/spec/unit/substation/processor/pivot/call_spec.rb +16 -0
  36. data/spec/unit/substation/processor/wrapper/call_spec.rb +19 -0
  37. metadata +29 -4
  38. data/.rvmrc +0 -1
@@ -0,0 +1 @@
1
+ substation
@@ -0,0 +1 @@
1
+ 1.9.3
@@ -4,13 +4,8 @@ bundler_args: --without yard guard benchmarks
4
4
  script: "bundle exec rake ci"
5
5
  rvm:
6
6
  - 1.9.3
7
- - 1.9.2
8
- - 1.8.7
9
- - ree
10
- - ruby-head
11
7
  - 2.0.0
8
+ - ruby-head
12
9
  - jruby-19mode
13
- - jruby-18mode
14
10
  - jruby-head
15
11
  - rbx-19mode
16
- - rbx-18mode
@@ -1,3 +1,43 @@
1
+ # v0.0.9 (not yet released)
2
+
3
+ *
4
+
5
+ [Compare v0.0.8..master](https://github.com/snusnu/substation/compare/v0.0.8...master)
6
+
7
+ # v0.0.8 2013-06-19
8
+
9
+ * [feature] Add the following chain processors
10
+ * `Substation::Processor::Evaluator`
11
+ * `Substation::Processor::Pivot`
12
+ * `Substation::Processor::Wrapper`
13
+
14
+ * [feature] Add `Substation::Environment` for registering processors by name
15
+
16
+ env = Substation::Environment.build do
17
+ register :authenticate, My::Authenticator # implemented by you
18
+ register :authorize, My::Authorizer # implemented by you
19
+ register :evaluate, Substation::Processor::Evaluator
20
+ register :call, Substation::Processor::Pivot
21
+ register :wrap, Substation::Processor::Wrapper
22
+ end
23
+
24
+ * [feature] Add a DSL for constructing `Substation::Chain` instances
25
+
26
+ AUTHENTICATED = env.chain { authenticate }
27
+ AUTHORIZED = env.chain(AUTHENTICATED) { authorize }
28
+
29
+ CREATE_PERSON = env.chain(AUTHORIZED) do
30
+ evaluate Sanitizers::NEW_PERSON
31
+ evaluate Validators::NEW_PERSON
32
+
33
+ call Actions::CreatePerson
34
+
35
+ wrap Presenters::Person
36
+ wrap Views::Person
37
+ end
38
+
39
+ [Compare v0.0.7..v0.0.8](https://github.com/snusnu/substation/compare/v0.0.7...v0.0.8)
40
+
1
41
  # v0.0.7 2013-06-14
2
42
 
3
43
  * [feature] Make `Substation::Response#request` part of the public API (snusnu)
@@ -17,15 +57,14 @@
17
57
 
18
58
  * [feature] Shorter action config when no observers are needed (snusnu)
19
59
 
20
- ```ruby
21
- dispatcher = Substation::Dispatcher.coerce({
22
- :some_use_case => App::SomeUseCase
23
- }, env)
60
+ dispatcher = Substation::Dispatcher.coerce({
61
+ :some_use_case => App::SomeUseCase
62
+ }, env)
63
+
64
+ dispatcher = Substation::Dispatcher.coerce({
65
+ :some_use_case => Proc.new { |request| request.success(:data) }
66
+ }, env)
24
67
 
25
- dispatcher = Substation::Dispatcher.coerce({
26
- :some_use_case => Proc.new { |request| request.success(:data) }
27
- }, env)
28
- ```
29
68
  [Compare v0.0.4..v0.0.5](https://github.com/snusnu/substation/compare/v0.0.4...v0.0.5)
30
69
 
31
70
  # v0.0.4 2013-05-15
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 6
3
- total_score: 69
3
+ total_score: 82
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 10.9
2
+ threshold: 13.3
@@ -26,6 +26,8 @@ FeatureEnvy:
26
26
  exclude:
27
27
  - Substation::Chain#call # loops over instance state
28
28
  - Substation::Chain::Incoming#result # defined in a module
29
+ - Substation::Chain::Outgoing#respond_with #defined in a module
30
+ - Substation::Processor::Evaluator#call # method object
29
31
  IrresponsibleModule:
30
32
  enabled: true
31
33
  exclude: []
@@ -33,6 +35,7 @@ LongParameterList:
33
35
  enabled: true
34
36
  exclude:
35
37
  - Substation::Dispatcher#call
38
+ - Substation::Chain::DSL::Builder#define_dsl_method
36
39
  max_params: 2
37
40
  LongYieldList:
38
41
  enabled: true
@@ -40,7 +43,8 @@ LongYieldList:
40
43
  max_params: 2
41
44
  NestedIterators:
42
45
  enabled: true
43
- exclude: []
46
+ exclude:
47
+ - Substation::Chain::DSL::Builder#define_dsl_method
44
48
  max_allowed_nesting: 1
45
49
  ignore_iterators: []
46
50
  NilCheck:
@@ -67,6 +71,7 @@ TooManyStatements:
67
71
  - Substation::Dispatcher::Action#self.coerce
68
72
  - Substation::Chain#call
69
73
  - Substation::Utils#self.coerce_callable
74
+ - Substation::Processor::Evaluator#call
70
75
  max_statements: 3
71
76
  UncommunicativeMethodName:
72
77
  enabled: true
@@ -106,4 +111,5 @@ UtilityFunction:
106
111
  enabled: true
107
112
  exclude:
108
113
  - Substation::Chain::Incoming#result # defined in a module
114
+ - Substation::Chain::Outgoing#respond_with # defined in a module
109
115
  max_helper_calls: 0
@@ -33,9 +33,16 @@ require 'concord'
33
33
  module Substation
34
34
  end
35
35
 
36
+ require 'substation/utils'
36
37
  require 'substation/request'
37
38
  require 'substation/response'
38
39
  require 'substation/observer'
39
40
  require 'substation/chain'
41
+ require 'substation/chain/dsl'
42
+ require 'substation/processor'
43
+ require 'substation/processor/evaluator'
44
+ require 'substation/processor/pivot'
45
+ require 'substation/processor/wrapper'
46
+ require 'substation/environment'
47
+ require 'substation/environment/dsl'
40
48
  require 'substation/dispatcher'
41
- require 'substation/support/utils'
@@ -72,8 +72,6 @@ module Substation
72
72
 
73
73
  # The request passed on to the next handler in a {Chain}
74
74
  #
75
- # @example
76
- #
77
75
  # @param [Response] response
78
76
  # the response returned from the previous handler in a {Chain}
79
77
  #
@@ -101,15 +99,36 @@ module Substation
101
99
  def result(response)
102
100
  response
103
101
  end
102
+
103
+ private
104
+
105
+ # Build a new {Response} based on +response+ and +output+
106
+ #
107
+ # @param [Response] response
108
+ # the original response
109
+ #
110
+ # @param [Object] output
111
+ # the data to be wrapped within the new {Response}
112
+ #
113
+ # @return [Response]
114
+ #
115
+ # @api private
116
+ def respond_with(response, output)
117
+ response.class.new(response.request, output)
118
+ end
104
119
  end
105
120
 
106
121
  # Supports chaining the {Pivot} handler
107
122
  Pivot = Outgoing
108
123
 
124
+ include Enumerable
109
125
  include Concord.new(:handlers)
110
126
  include Adamantium::Flat
111
127
  include Pivot # allow nesting of chains
112
128
 
129
+ # Empty chain
130
+ EMPTY = Class.new(self).new([])
131
+
113
132
  # Call the chain
114
133
  #
115
134
  # Invokes all handlers and returns either the first
@@ -160,5 +179,23 @@ module Substation
160
179
  }
161
180
  end
162
181
 
182
+ # Iterate over all processors
183
+ #
184
+ # @param [Proc] block
185
+ # a block passed to {#handlers} each method
186
+ #
187
+ # @yield [handler]
188
+ #
189
+ # @yieldparam [#call] handler
190
+ # each handler in the chain
191
+ #
192
+ # @return [self]
193
+ #
194
+ # @api private
195
+ def each(&block)
196
+ return to_enum unless block
197
+ handlers.each(&block)
198
+ self
199
+ end
163
200
  end # class Chain
164
201
  end # module Substation
@@ -0,0 +1,165 @@
1
+ module Substation
2
+
3
+ class Chain
4
+
5
+ # Build a new chain instance
6
+ #
7
+ # @param [DSL] dsl
8
+ # the dsl klass to use for defining the chain
9
+ #
10
+ # @param [Chain] other
11
+ # another chain to build on top of
12
+ #
13
+ # @param [Proc] block
14
+ # a block to instance_eval in the context of +dsl+
15
+ #
16
+ # @return [Chain]
17
+ #
18
+ # @api private
19
+ def self.build(dsl, other, &block)
20
+ new(dsl.processors(other, &block))
21
+ end
22
+
23
+ # The DSL class used to define chains in an {Environment}
24
+ class DSL
25
+
26
+ # The class that builds a DSL class suitable for an {Environment}
27
+ class Builder
28
+ include Adamantium::Flat
29
+
30
+ # Build a new {DSL} subclass targeted for an {Environment}
31
+ #
32
+ # @param [Hash<Symbol, #call>] registry
33
+ # the registry of processors used in an {Environment}
34
+ #
35
+ # @return [Class<DSL>]
36
+ #
37
+ # @api private
38
+ def self.call(registry)
39
+ new(registry).dsl
40
+ end
41
+
42
+ # The built DSL subclass
43
+ #
44
+ # @return [Class<DSL>]
45
+ #
46
+ # @api private
47
+ attr_reader :dsl
48
+
49
+ # Initialize a new instance
50
+ #
51
+ # @param [Hash<Symbol, #call>] registry
52
+ # the registry of processors used in an {Environment}
53
+ #
54
+ # @return [undefined]
55
+ #
56
+ # @api private
57
+ def initialize(registry)
58
+ @registry = registry
59
+ @dsl = compile_dsl
60
+ end
61
+
62
+ private
63
+
64
+ # Compile a new DSL class
65
+ #
66
+ # @return [Class<DSL>]
67
+ #
68
+ # @api private
69
+ def compile_dsl
70
+ @registry.each_with_object(Class.new(DSL)) { |(name, processor), dsl|
71
+ define_dsl_method(name, processor, dsl)
72
+ }
73
+ end
74
+
75
+
76
+ # Define a new instance method on the +dsl+ class
77
+ #
78
+ # @param [Symbol] name
79
+ # the name of the method
80
+ #
81
+ # @param [#call] processor
82
+ # the processor to use within the chain
83
+ #
84
+ # @param [Class<DSL>] dsl
85
+ # the {DSL} subclass to define the method on
86
+ #
87
+ # @return [undefined]
88
+ #
89
+ # @api private
90
+ def define_dsl_method(name, processor, dsl)
91
+ dsl.class_eval do
92
+ define_method(name) { |*args| use(processor.new(*args)) }
93
+ end
94
+ end
95
+
96
+ end # class Builder
97
+
98
+ # The processors to be used within a {Chain}
99
+ #
100
+ # @return [Array<#call>]
101
+ #
102
+ # @api private
103
+ attr_reader :processors
104
+
105
+ # The processors to be used within a {Chain}
106
+ #
107
+ # @param [Chain] chain
108
+ # the chain to build on top of
109
+ #
110
+ # @param [Proc] block
111
+ # a block to be instance_eval'ed
112
+ #
113
+ # @return [Array<#call>]
114
+ #
115
+ # @api private
116
+ def self.processors(chain, &block)
117
+ new(chain, &block).processors
118
+ end
119
+
120
+ # Initialize a new instance
121
+ #
122
+ # @param [#each<#call>] processors
123
+ # an enumerable of processors to build on top of
124
+ #
125
+ # @param [Proc] block
126
+ # a block to be instance_eval'ed
127
+ #
128
+ # @return [undefined]
129
+ #
130
+ # @api private
131
+ def initialize(processors, &block)
132
+ @processors = []
133
+ chain(processors)
134
+ instance_eval(&block) if block
135
+ end
136
+
137
+ # Use the given +processor+ within a chain
138
+ #
139
+ # @param [#call] processor
140
+ # a processor to use within a chain
141
+ #
142
+ # @return [self]
143
+ #
144
+ # @api private
145
+ def use(processor)
146
+ @processors << processor
147
+ self
148
+ end
149
+
150
+ # Nest the given chain within another one
151
+ #
152
+ # @param [#each<#call>] other
153
+ # another chain to be nested within a chain
154
+ #
155
+ # @return [self]
156
+ #
157
+ # @api private
158
+ def chain(other)
159
+ other.each { |handler| use(handler) }
160
+ self
161
+ end
162
+
163
+ end # class DSL
164
+ end # class Chain
165
+ end # module Substation
@@ -0,0 +1,59 @@
1
+ module Substation
2
+
3
+ # The environment holding all registered {Chain} processors
4
+ class Environment
5
+
6
+ include Equalizer.new(:registry)
7
+ include Adamantium::Flat
8
+
9
+ # Build a new {Environment} instance
10
+ #
11
+ # @param [Proc] block
12
+ # a block to be instance_eval'ed with {DSL}
13
+ #
14
+ # @return [Environment]
15
+ #
16
+ # @api private
17
+ def self.build(&block)
18
+ new(DSL.registry(&block))
19
+ end
20
+
21
+ # Initialize a new instance
22
+ #
23
+ # @param [Hash<Symbol, #call>] registry
24
+ # the registry of processors
25
+ #
26
+ # @return [undefined]
27
+ #
28
+ # @api private
29
+ def initialize(registry)
30
+ @registry = registry
31
+ @chain_dsl = Chain::DSL::Builder.call(@registry)
32
+ end
33
+
34
+ # Build a new {Chain} instance
35
+ #
36
+ # @param [Chain] other
37
+ # the optional chain to build on top of
38
+ #
39
+ # @param [Proc] block
40
+ # a block to be instance_eval'ed in {Chain::DSL}
41
+ #
42
+ # @return [Chain]
43
+ #
44
+ # @api private
45
+ def chain(other = Chain::EMPTY, &block)
46
+ Chain.build(@chain_dsl, other, &block)
47
+ end
48
+
49
+ protected
50
+
51
+ # The registry used by this {Environment}
52
+ #
53
+ # @return [Hash<Symbol, #call>]
54
+ #
55
+ # @api private
56
+ attr_reader :registry
57
+
58
+ end # class Environment
59
+ end # module Substation
@@ -0,0 +1,58 @@
1
+ module Substation
2
+ class Environment
3
+
4
+ # The DSL class used to define register processors
5
+ class DSL
6
+
7
+ # The registry of processors
8
+ #
9
+ # @return [Hash<Symbol, #call>]
10
+ #
11
+ # @api private
12
+ attr_reader :registry
13
+
14
+
15
+ # The registry of processors
16
+ #
17
+ # @param [Proc] block
18
+ # a block to be instance_eval'ed
19
+ #
20
+ # @return [Hash<Symbol, #call>]
21
+ #
22
+ # @api private
23
+ def self.registry(&block)
24
+ new(&block).registry
25
+ end
26
+
27
+ # Initialize a new instance
28
+ #
29
+ # @param [Proc] block
30
+ # a block to be instance_eval'ed
31
+ #
32
+ # @return [undefined]
33
+ #
34
+ # @api private
35
+ def initialize(&block)
36
+ @registry = {}
37
+ instance_eval(&block) if block
38
+ end
39
+
40
+ # Register a new +processor+ using the given +name+
41
+ #
42
+ # @param [#to_sym] name
43
+ # the name to register the +processor+ for
44
+ #
45
+ # @param [#call] processor
46
+ # the processor to register for +name+
47
+ #
48
+ # @return [self]
49
+ #
50
+ # @api private
51
+ def register(name, processor)
52
+ @registry[name] = processor
53
+ self
54
+ end
55
+
56
+ end # class DSL
57
+ end # class Environment
58
+ end # module Substation
@@ -0,0 +1,23 @@
1
+ module Substation
2
+
3
+ # Namespace for chain processors
4
+ module Processor
5
+
6
+ include AbstractType
7
+ include Adamantium::Flat
8
+
9
+ abstract_method :call
10
+ abstract_method :result
11
+
12
+ module Incoming
13
+ include Processor
14
+ include Chain::Incoming
15
+ end
16
+
17
+ module Outgoing
18
+ include Processor
19
+ include Chain::Outgoing
20
+ end
21
+
22
+ end # module Processor
23
+ end # module Substation
@@ -0,0 +1,30 @@
1
+ module Substation
2
+ module Processor
3
+
4
+ # A processor to evaluate a chain's request input data
5
+ class Evaluator
6
+
7
+ include Incoming
8
+ include Concord.new(:handler)
9
+
10
+ # Evaluate a chain's request input data
11
+ #
12
+ # @param [Request] request
13
+ # the request to process
14
+ #
15
+ # @return [Response]
16
+ #
17
+ # @api private
18
+ def call(request)
19
+ result = handler.call(request.input)
20
+ output = result.output
21
+ if result.success?
22
+ request.success(output)
23
+ else
24
+ request.error(output)
25
+ end
26
+ end
27
+
28
+ end # class Evaluator
29
+ end # module Processor
30
+ end # module Substation
@@ -0,0 +1,25 @@
1
+ module Substation
2
+ module Processor
3
+
4
+ # A processor to invoke a chain's pivot handler
5
+ class Pivot
6
+
7
+ include Processor
8
+ include Chain::Pivot
9
+ include Concord.new(:handler)
10
+
11
+ # Invoke a chain's pivot handler
12
+ #
13
+ # @param [Request] request
14
+ # the request to process
15
+ #
16
+ # @return [Response]
17
+ #
18
+ # @api private
19
+ def call(request)
20
+ handler.call(request)
21
+ end
22
+
23
+ end # class Caller
24
+ end # module Processor
25
+ end # module Substation
@@ -0,0 +1,24 @@
1
+ module Substation
2
+ module Processor
3
+
4
+ # A processor that wraps output data in a new handler instance
5
+ class Wrapper
6
+
7
+ include Outgoing
8
+ include Concord.new(:handler)
9
+
10
+ # Wrap response data in an instance of {#handler}
11
+ #
12
+ # @param [Response] response
13
+ # the response to process
14
+ #
15
+ # @return [Response]
16
+ #
17
+ # @api private
18
+ def call(response)
19
+ respond_with(response, handler.new(response.output))
20
+ end
21
+
22
+ end # class Wrapper
23
+ end # module Processor
24
+ end # module Substation
@@ -1,4 +1,4 @@
1
1
  module Substation
2
2
  # Gem version
3
- VERSION = '0.0.7'.freeze
3
+ VERSION = '0.0.8'.freeze
4
4
  end
@@ -1,5 +1,7 @@
1
1
  require 'devtools/spec_helper'
2
2
 
3
+ require 'concord' # makes spec setup easier
4
+
3
5
  module Spec
4
6
 
5
7
  def self.response_data
@@ -25,6 +27,61 @@ module Spec
25
27
  end
26
28
  end
27
29
 
30
+ class Processor
31
+ include Concord.new(:handler)
32
+ end
33
+
34
+ module Handler
35
+
36
+ class Evaluator
37
+ class Result
38
+
39
+ include Concord::Public.new(:output)
40
+
41
+ class Success < self
42
+ def success?
43
+ true
44
+ end
45
+ end
46
+
47
+ class Failure < self
48
+ def success?
49
+ false
50
+ end
51
+ end
52
+ end
53
+
54
+ def call(data)
55
+ if data == :success
56
+ Result::Success.new(data)
57
+ else
58
+ Result::Failure.new(:failure)
59
+ end
60
+ end
61
+ end
62
+
63
+ class Pivot
64
+ def call(request)
65
+ request.success(request.input)
66
+ end
67
+ end
68
+
69
+ class Wrapper
70
+ class Presenter
71
+ include Concord.new(:data)
72
+ end
73
+
74
+ include Concord.new(:data)
75
+
76
+ def call(data)
77
+ Presenter.new(data)
78
+ end
79
+ end
80
+ end
81
+
82
+ FAKE_HANDLER = Object.new
83
+ FAKE_PROCESSOR = Processor.new(FAKE_HANDLER)
84
+
28
85
  end
29
86
 
30
87
  if ENV['COVERAGE'] == 'true'
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chain, '.build' do
4
+
5
+ context "when a block is given" do
6
+ subject { described_class.build(dsl, other, &block) }
7
+
8
+ let(:dsl) { Chain::DSL::Builder.call(registry) }
9
+ let(:registry) { { :test => Spec::Processor } }
10
+ let(:other) { [ processor ] }
11
+ let(:processor) { Spec::FAKE_PROCESSOR }
12
+ let(:block) { lambda { |_| test(Spec::FAKE_HANDLER) } }
13
+
14
+ let(:expected) { Chain.new(dsl.processors(other, &block)) }
15
+
16
+ it { should eql(expected) }
17
+ end
18
+
19
+ context "when no block is given" do
20
+ subject { described_class.build(dsl, other) }
21
+
22
+ let(:dsl) { Chain::DSL::Builder.call(registry) }
23
+ let(:registry) { { :test => Spec::Processor } }
24
+ let(:other) { [ processor ] }
25
+ let(:processor) { Spec::FAKE_PROCESSOR }
26
+
27
+ let(:expected) { Chain.new(dsl.processors(other)) }
28
+
29
+ it { should eql(expected) }
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::Builder, '.call' do
6
+ subject { described_class.call(registry) }
7
+
8
+ let(:registry) { { :test => Spec::Processor } }
9
+
10
+ let(:builder) { mock(:dsl => dsl) }
11
+ let(:dsl) { mock }
12
+
13
+ before do
14
+ described_class.should_receive(:new).with(registry).and_return(builder)
15
+ builder.should_receive(:dsl).and_return(dsl)
16
+ end
17
+
18
+ it { should be(dsl) }
19
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL::Builder, '#dsl' do
6
+ subject { dsl.new(processors, &block) }
7
+
8
+ let(:dsl) { builder.dsl }
9
+ let(:builder) { described_class.new(registry) }
10
+ let(:registry) { { :test => Spec::Processor } }
11
+ let(:processors) { [] }
12
+ let(:block) { lambda { |_| test(Spec::FAKE_HANDLER) } }
13
+ let(:processor) { Spec::FAKE_PROCESSOR }
14
+
15
+ its(:processors) { should include(processor) }
16
+
17
+ it "should create a subclass of Chain::DSL" do
18
+ subject.class.should be < Chain::DSL
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '#chain' do
6
+ subject { object.chain(other) }
7
+
8
+ let(:object) { described_class.new(chain) }
9
+ let(:chain) { Chain::EMPTY }
10
+ let(:other) { [ processor ] }
11
+ let(:processor) { Spec::FAKE_PROCESSOR }
12
+
13
+ its(:processors) { should include(processor) }
14
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '.processors' do
6
+
7
+ let(:chain) { Chain::EMPTY }
8
+
9
+ context "and a block is given" do
10
+ subject { described_class.processors(chain, &block) }
11
+
12
+ let(:block) { lambda { |_| use(Spec::FAKE_PROCESSOR) } }
13
+ let(:processor) { Spec::FAKE_PROCESSOR }
14
+
15
+ it { should include(processor) }
16
+ end
17
+
18
+ context "and no block is given" do
19
+ subject { described_class.processors(chain) }
20
+
21
+ it { should be_empty }
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '#processors' do
6
+ subject { object.processors }
7
+
8
+ let(:processor) { Spec::FAKE_PROCESSOR }
9
+
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) } }
14
+
15
+ it { should include(processor) }
16
+
17
+ its(:length) { should == 1 }
18
+ end
19
+
20
+ context "and no block is given" do
21
+ let(:object) { described_class.new(chain) }
22
+ let(:chain) { Chain.new([ processor ]) }
23
+
24
+ it { should include(processor) }
25
+
26
+ its(:length) { should == 1 }
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::DSL, '#use' do
6
+ subject { object.use(processor) }
7
+
8
+ let(:object) { described_class.new(chain) }
9
+ let(:chain) { Chain::EMPTY }
10
+ let(:processor) { Spec::FAKE_PROCESSOR }
11
+
12
+ its(:processors) { should include(processor) }
13
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain, '#each' do
6
+ subject { object.each { |tuple| yields << processor } }
7
+
8
+ let(:object) { described_class.new(processors) }
9
+ let(:processors) { [ processor ] }
10
+ let(:processor) { Spec::FAKE_PROCESSOR }
11
+ let(:yields) { [] }
12
+
13
+ before do
14
+ object.should be_instance_of(described_class)
15
+ end
16
+
17
+ it_should_behave_like 'an #each method'
18
+
19
+ it 'yields only processors' do
20
+ subject
21
+ yields.each { |processor| processor.should be_instance_of(Spec::Processor) }
22
+ end
23
+
24
+ it 'yields only processors with the expected handler' do
25
+ expect { subject }.to change { yields.dup }.
26
+ from([]).
27
+ to([ processor ])
28
+ end
29
+ end
30
+
31
+ describe Chain do
32
+ subject { described_class.new(processors) }
33
+
34
+ let(:processors) { [ processor ] }
35
+ let(:processor) { Spec::FAKE_PROCESSOR }
36
+
37
+ before do
38
+ subject.should be_instance_of(described_class)
39
+ end
40
+
41
+ it { should be_kind_of(Enumerable) }
42
+
43
+ it 'case matches Enumerable' do
44
+ (Enumerable === subject).should be(true)
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Chain::Outgoing, '#call' do
6
+
7
+ subject { object.call(request) }
8
+
9
+ let(:object) {
10
+ Class.new {
11
+ include Substation::Chain::Outgoing
12
+ def call(request)
13
+ response = request.success(request.input)
14
+ respond_with(response, :altered)
15
+ end
16
+ }.new
17
+ }
18
+
19
+ let(:response) { Response::Success.new(request, :altered) }
20
+ let(:request) { Request.new(env, input) }
21
+ let(:env) { mock }
22
+ let(:input) { mock }
23
+
24
+ it { should eql(response) }
25
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Substation::Environment, '#chain' do
4
+
5
+ let(:object) { described_class.build(&block) }
6
+
7
+ let(:expected) { Chain.build(dsl, other, &chain) }
8
+ let(:other) { Chain::EMPTY }
9
+ let(:chain) { lambda { |_| test Spec::FAKE_HANDLER } }
10
+ let(:dsl) { Chain::DSL::Builder.call(registry) }
11
+ let(:registry) { described_class::DSL.registry(&block) }
12
+ let(:block) { lambda { |_| register(:test, Spec::Processor) } }
13
+
14
+ context "when other is not given" do
15
+ context "and a block is given" do
16
+ subject { object.chain(&chain) }
17
+
18
+ it { should eql(expected) }
19
+ end
20
+
21
+ context "and no block is given" do
22
+ subject { object.chain }
23
+
24
+ let(:expected) { Chain.build(dsl, other) }
25
+
26
+ it { should eql(expected) }
27
+ end
28
+ end
29
+
30
+ context "when other is given" do
31
+ context "and a block is given" do
32
+ subject { object.chain(other, &chain) }
33
+
34
+ it { should eql(expected) }
35
+ end
36
+
37
+ context "and no block is given" do
38
+ subject { object.chain(other) }
39
+
40
+ let(:expected) { Chain.build(dsl, other) }
41
+
42
+ it { should eql(expected) }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Substation::Environment, '.build' do
4
+ subject { described_class.build(&block) }
5
+
6
+ let(:block) { lambda { |_| register(:test, Substation) } }
7
+ let(:expected) { described_class.new(registry) }
8
+ let(:registry) { described_class::DSL.registry(&block) }
9
+
10
+ it { should eql(expected) }
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Substation::Environment::DSL, '.registry' do
4
+ context "when a block is given" do
5
+ subject { described_class.registry(&block) }
6
+
7
+ let(:block) { lambda { |_| register :test, Spec::Processor } }
8
+ let(:expected) { { :test => Spec::Processor } }
9
+
10
+ it { should eql(expected) }
11
+ end
12
+
13
+ context "when no block is given" do
14
+ subject { described_class.registry }
15
+
16
+ it { should eql({}) }
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Substation::Environment::DSL, '#register' do
4
+ subject { object.register(name, processor) }
5
+
6
+ let(:object) { described_class.new }
7
+ let(:name) { :test }
8
+ let(:processor) { Spec::Processor }
9
+
10
+ let(:expected) { { :test => Spec::Processor } }
11
+ let(:block) { lambda { |_| register :test, Spec::Processor } }
12
+
13
+ its(:registry) { should eql(expected) }
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Substation::Environment::DSL, '#registry' do
4
+ subject { object.registry }
5
+
6
+ context "when a block is given" do
7
+ let(:object) { described_class.new(&block) }
8
+ let(:block) { lambda { |_| register :test, Spec::Processor } }
9
+ let(:expected) { { :test => Spec::Processor } }
10
+
11
+ it { should eql(expected) }
12
+ end
13
+
14
+ context "when no block is given" do
15
+ let(:object) { described_class.new }
16
+
17
+ it { should eql({}) }
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Processor::Evaluator, '#call' do
6
+ subject { object.call(request) }
7
+
8
+ let(:object) { described_class.new(Spec::Handler::Evaluator.new) }
9
+ let(:request) { Request.new(env, input) }
10
+ let(:env) { mock }
11
+
12
+ context "when evaluation is successful" do
13
+ let(:input) { :success }
14
+ let(:response) { Response::Success.new(request, input) }
15
+
16
+ it { should eql(response) }
17
+ end
18
+
19
+ context "when evaluation is not successful" do
20
+ let(:input) { :invalid }
21
+ let(:response) { Response::Failure.new(request, :failure) }
22
+
23
+ it { should eql(response) }
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Processor::Pivot, '#call' do
6
+ subject { object.call(request) }
7
+
8
+ let(:object) { described_class.new(Spec::Handler::Pivot.new) }
9
+ let(:request) { Request.new(env, input) }
10
+ let(:env) { mock }
11
+ let(:input) { mock }
12
+
13
+ let(:response) { Response::Success.new(request, request.input) }
14
+
15
+ it { should eql(response) }
16
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Processor::Wrapper, '#call' do
6
+ subject { object.call(response) }
7
+
8
+ let(:object) { described_class.new(Spec::Handler::Wrapper::Presenter) }
9
+ let(:response) { Response::Success.new(request, output) }
10
+ let(:request) { Request.new(env, input) }
11
+ let(:env) { mock }
12
+ let(:input) { mock }
13
+ let(:output) { mock }
14
+
15
+ let(:wrapped) { Response::Success.new(request, data) }
16
+ let(:data) { Spec::Handler::Wrapper::Presenter.new(output) }
17
+
18
+ it { should eql(wrapped) }
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: substation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-14 00:00:00.000000000 Z
12
+ date: 2013-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: adamantium
@@ -103,7 +103,8 @@ extra_rdoc_files:
103
103
  files:
104
104
  - .gitignore
105
105
  - .rspec
106
- - .rvmrc
106
+ - .ruby-gemset
107
+ - .ruby-version
107
108
  - .travis.yml
108
109
  - CONTRIBUTING.md
109
110
  - Changelog.md
@@ -122,25 +123,49 @@ files:
122
123
  - config/yardstick.yml
123
124
  - lib/substation.rb
124
125
  - lib/substation/chain.rb
126
+ - lib/substation/chain/dsl.rb
125
127
  - lib/substation/dispatcher.rb
128
+ - lib/substation/environment.rb
129
+ - lib/substation/environment/dsl.rb
126
130
  - lib/substation/observer.rb
131
+ - lib/substation/processor.rb
132
+ - lib/substation/processor/evaluator.rb
133
+ - lib/substation/processor/pivot.rb
134
+ - lib/substation/processor/wrapper.rb
127
135
  - lib/substation/request.rb
128
136
  - lib/substation/response.rb
129
- - lib/substation/support/utils.rb
137
+ - lib/substation/utils.rb
130
138
  - lib/substation/version.rb
131
139
  - spec/integration/substation/dispatcher/call_spec.rb
132
140
  - spec/spec_helper.rb
133
141
  - spec/unit/substation/chain/call_spec.rb
142
+ - spec/unit/substation/chain/class_methods/build_spec.rb
143
+ - spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb
144
+ - spec/unit/substation/chain/dsl/builder/dsl_spec.rb
145
+ - spec/unit/substation/chain/dsl/chain_spec.rb
146
+ - spec/unit/substation/chain/dsl/class_methods/processors_spec.rb
147
+ - spec/unit/substation/chain/dsl/processors_spec.rb
148
+ - spec/unit/substation/chain/dsl/use_spec.rb
149
+ - spec/unit/substation/chain/each_spec.rb
134
150
  - spec/unit/substation/chain/incoming/result_spec.rb
151
+ - spec/unit/substation/chain/outgoing/call_spec.rb
135
152
  - spec/unit/substation/chain/outgoing/result_spec.rb
136
153
  - spec/unit/substation/dispatcher/action/call_spec.rb
137
154
  - spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb
138
155
  - spec/unit/substation/dispatcher/action_names_spec.rb
139
156
  - spec/unit/substation/dispatcher/call_spec.rb
140
157
  - spec/unit/substation/dispatcher/class_methods/coerce_spec.rb
158
+ - spec/unit/substation/environment/chain_spec.rb
159
+ - spec/unit/substation/environment/class_methods/build_spec.rb
160
+ - spec/unit/substation/environment/dsl/class_methods/registry_spec.rb
161
+ - spec/unit/substation/environment/dsl/register_spec.rb
162
+ - spec/unit/substation/environment/dsl/registry_spec.rb
141
163
  - spec/unit/substation/observer/chain/call_spec.rb
142
164
  - spec/unit/substation/observer/class_methods/coerce_spec.rb
143
165
  - spec/unit/substation/observer/null/call_spec.rb
166
+ - spec/unit/substation/processor/evaluator/call_spec.rb
167
+ - spec/unit/substation/processor/pivot/call_spec.rb
168
+ - spec/unit/substation/processor/wrapper/call_spec.rb
144
169
  - spec/unit/substation/request/env_spec.rb
145
170
  - spec/unit/substation/request/error_spec.rb
146
171
  - spec/unit/substation/request/input_spec.rb
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use @$(basename `pwd`) --create