substation 0.0.7 → 0.0.8

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