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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +0 -1
  3. data/Changelog.md +24 -82
  4. data/Gemfile.devtools +17 -24
  5. data/README.md +46 -116
  6. data/config/flay.yml +2 -2
  7. data/config/flog.yml +1 -1
  8. data/config/mutant.yml +0 -1
  9. data/config/reek.yml +5 -10
  10. data/lib/substation.rb +3 -8
  11. data/lib/substation/chain.rb +64 -108
  12. data/lib/substation/chain/dsl.rb +30 -57
  13. data/lib/substation/dispatcher.rb +1 -3
  14. data/lib/substation/environment.rb +23 -9
  15. data/lib/substation/environment/dsl.rb +3 -4
  16. data/lib/substation/observer.rb +2 -4
  17. data/lib/substation/processor.rb +7 -106
  18. data/lib/substation/processor/evaluator.rb +42 -83
  19. data/lib/substation/processor/pivot.rb +25 -0
  20. data/lib/substation/processor/wrapper.rb +2 -4
  21. data/lib/substation/request.rb +1 -10
  22. data/lib/substation/response.rb +0 -11
  23. data/lib/substation/utils.rb +1 -3
  24. data/lib/substation/version.rb +1 -3
  25. data/spec/integration/substation/dispatcher/call_spec.rb +12 -12
  26. data/spec/spec_helper.rb +21 -30
  27. data/spec/unit/substation/chain/call_spec.rb +32 -202
  28. data/spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb +2 -2
  29. data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +6 -8
  30. data/spec/unit/substation/chain/dsl/builder/failure_chain_spec.rb +30 -0
  31. data/spec/unit/substation/chain/dsl/chain_spec.rb +2 -1
  32. data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +24 -0
  33. data/spec/unit/substation/chain/dsl/initialize_spec.rb +19 -0
  34. data/spec/unit/substation/chain/dsl/processors_spec.rb +21 -9
  35. data/spec/unit/substation/chain/dsl/use_spec.rb +3 -2
  36. data/spec/unit/substation/chain/each_spec.rb +9 -5
  37. data/spec/unit/substation/chain/incoming/result_spec.rb +21 -0
  38. data/spec/unit/substation/chain/outgoing/call_spec.rb +25 -0
  39. data/spec/unit/substation/{processor → chain/outgoing}/result_spec.rb +5 -6
  40. data/spec/unit/substation/dispatcher/action/call_spec.rb +6 -7
  41. data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +5 -7
  42. data/spec/unit/substation/dispatcher/action_names_spec.rb +1 -1
  43. data/spec/unit/substation/dispatcher/call_spec.rb +3 -3
  44. data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +7 -7
  45. data/spec/unit/substation/environment/chain_spec.rb +32 -22
  46. data/spec/unit/substation/environment/class_methods/build_spec.rb +4 -11
  47. data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +3 -5
  48. data/spec/unit/substation/environment/dsl/register_spec.rb +3 -8
  49. data/spec/unit/substation/environment/dsl/registry_spec.rb +3 -5
  50. data/spec/unit/substation/observer/chain/call_spec.rb +3 -5
  51. data/spec/unit/substation/observer/class_methods/coerce_spec.rb +2 -4
  52. data/spec/unit/substation/observer/null/call_spec.rb +1 -3
  53. data/spec/unit/substation/processor/evaluator/call_spec.rb +35 -21
  54. data/spec/unit/substation/processor/pivot/call_spec.rb +17 -0
  55. data/spec/unit/substation/processor/wrapper/call_spec.rb +7 -8
  56. data/spec/unit/substation/request/env_spec.rb +4 -5
  57. data/spec/unit/substation/request/error_spec.rb +4 -5
  58. data/spec/unit/substation/request/input_spec.rb +4 -5
  59. data/spec/unit/substation/request/success_spec.rb +4 -5
  60. data/spec/unit/substation/response/env_spec.rb +5 -6
  61. data/spec/unit/substation/response/failure/success_predicate_spec.rb +4 -5
  62. data/spec/unit/substation/response/input_spec.rb +5 -6
  63. data/spec/unit/substation/response/output_spec.rb +4 -5
  64. data/spec/unit/substation/response/request_spec.rb +5 -6
  65. data/spec/unit/substation/response/success/success_predicate_spec.rb +4 -5
  66. data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +13 -15
  67. data/spec/unit/substation/utils/class_methods/const_get_spec.rb +6 -6
  68. data/spec/unit/substation/utils/class_methods/symbolize_keys_spec.rb +4 -4
  69. data/substation.gemspec +1 -1
  70. metadata +18 -45
  71. data/config/rubocop.yml +0 -35
  72. data/lib/substation/processor/transformer.rb +0 -26
  73. data/spec/unit/substation/chain/class_methods/failure_response_spec.rb +0 -16
  74. data/spec/unit/substation/chain/dsl/class_methods/build_spec.rb +0 -24
  75. data/spec/unit/substation/chain/dsl/failure_chain_spec.rb +0 -35
  76. data/spec/unit/substation/chain/failure_data/equalizer_spec.rb +0 -46
  77. data/spec/unit/substation/chain/failure_data/hash_spec.rb +0 -13
  78. data/spec/unit/substation/environment/equalizer_spec.rb +0 -25
  79. data/spec/unit/substation/processor/evaluator/class_methods/new_spec.rb +0 -9
  80. data/spec/unit/substation/processor/evaluator/data/call_spec.rb +0 -34
  81. data/spec/unit/substation/processor/evaluator/pivot/call_spec.rb +0 -34
  82. data/spec/unit/substation/processor/evaluator/request/call_spec.rb +0 -34
  83. data/spec/unit/substation/processor/fallible/name_spec.rb +0 -15
  84. data/spec/unit/substation/processor/fallible/with_failure_chain_spec.rb +0 -18
  85. data/spec/unit/substation/processor/incoming/result_spec.rb +0 -25
  86. data/spec/unit/substation/processor/outgoing/call_spec.rb +0 -28
  87. data/spec/unit/substation/processor/outgoing/name_spec.rb +0 -14
  88. data/spec/unit/substation/processor/outgoing/success_predicate_spec.rb +0 -15
  89. data/spec/unit/substation/processor/success_predicate_spec.rb +0 -22
  90. data/spec/unit/substation/processor/transformer/call_spec.rb +0 -21
  91. data/spec/unit/substation/request/name_spec.rb +0 -15
  92. data/spec/unit/substation/response/to_request_spec.rb +0 -19
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
 
5
3
  # Encapsulates all registered actions and their observers
@@ -251,7 +249,7 @@ module Substation
251
249
  #
252
250
  # @api public
253
251
  def call(name, input)
254
- fetch(name).call(Request.new(name, env, input))
252
+ fetch(name).call(Request.new(env, input))
255
253
  end
256
254
 
257
255
  # The names of all registered actions
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
 
5
3
  # The environment holding all registered {Chain} processors
@@ -17,9 +15,7 @@ module Substation
17
15
  #
18
16
  # @api private
19
17
  def self.build(&block)
20
- registry = DSL.registry(&block)
21
- chain_dsl = Chain::DSL::Builder.call(registry)
22
- new(registry, chain_dsl)
18
+ new(DSL.registry(&block))
23
19
  end
24
20
 
25
21
  # Initialize a new instance
@@ -30,8 +26,9 @@ module Substation
30
26
  # @return [undefined]
31
27
  #
32
28
  # @api private
33
- def initialize(registry, chain_dsl)
34
- @registry, @chain_dsl = registry, chain_dsl
29
+ def initialize(registry)
30
+ @registry = registry
31
+ @chain_dsl = Chain::DSL::Builder.call(@registry)
35
32
  end
36
33
 
37
34
  # Build a new {Chain} instance
@@ -45,8 +42,8 @@ module Substation
45
42
  # @return [Chain]
46
43
  #
47
44
  # @api private
48
- def chain(other = Chain::EMPTY, failure_chain = Chain::EMPTY, &block)
49
- @chain_dsl.build(other, failure_chain, &block)
45
+ def chain(other = Chain::EMPTY, &block)
46
+ Chain.new(processors(other, &block))
50
47
  end
51
48
 
52
49
  protected
@@ -58,5 +55,22 @@ module Substation
58
55
  # @api private
59
56
  attr_reader :registry
60
57
 
58
+ private
59
+
60
+ # The processors collected via the chain dsl instance
61
+ #
62
+ # @param [Chain] other
63
+ # another chain to build upon
64
+ #
65
+ # @param [Proc] block
66
+ # the block to pass to {Chain::DSL#processors}
67
+ #
68
+ # @return [Hash<Symbol, #call>]
69
+ #
70
+ # @api private
71
+ def processors(other, &block)
72
+ @chain_dsl.processors(self, other, &block)
73
+ end
74
+
61
75
  end # class Environment
62
76
  end # module Substation
@@ -1,9 +1,7 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
  class Environment
5
3
 
6
- # The DSL class used to register processors
4
+ # The DSL class used to define register processors
7
5
  class DSL
8
6
 
9
7
  # The registry of processors
@@ -13,6 +11,7 @@ module Substation
13
11
  # @api private
14
12
  attr_reader :registry
15
13
 
14
+
16
15
  # The registry of processors
17
16
  #
18
17
  # @param [Proc] block
@@ -50,7 +49,7 @@ module Substation
50
49
  #
51
50
  # @api private
52
51
  def register(name, processor)
53
- @registry[name.to_sym] = processor
52
+ @registry[name] = processor
54
53
  self
55
54
  end
56
55
 
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
 
5
3
  # Abstract observer base class
@@ -22,7 +20,7 @@ module Substation
22
20
 
23
21
  # Coerce +input+ to an instance of {Observer}
24
22
  #
25
- # @param [NilClass, String, Array<String>] input
23
+ # @param [nil, String, Array<String>] input
26
24
  # 0..n observer class names
27
25
  #
28
26
  # @return [Observer::NULL, Object, Observer::Chain]
@@ -31,7 +29,7 @@ module Substation
31
29
  # @api private
32
30
  def self.coerce(input)
33
31
  case input
34
- when NilClass
32
+ when nil
35
33
  NULL
36
34
  when Array
37
35
  Chain.new(input.map { |item| coerce(item) })
@@ -1,122 +1,23 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
 
5
3
  # Namespace for chain processors
6
4
  module Processor
7
5
 
8
- # Test wether chain processing should continue
9
- #
10
- # @param [Response] response
11
- # the response returned from invoking the processor
12
- #
13
- # @return [true] for a successful response
14
- # @return [false] otherwise
15
- #
16
- # @api private
17
- def success?(response)
18
- response.success?
19
- end
20
-
21
- # The response passed on to the next processor in a {Chain}
22
- #
23
- # @param [Response] response
24
- # the response returned from invoking the processor
25
- #
26
- # @return [Response]
27
- # the response passed on to the next processor in a {Chain}
28
- #
29
- # @api private
30
- def result(response)
31
- response
32
- end
33
-
34
- module Fallible
35
- include Concord.new(:name, :handler, :failure_chain)
36
-
37
- # This processor's name
38
- #
39
- # @return [Symbol]
40
- #
41
- # @api private
42
- attr_reader :name
6
+ include AbstractType
7
+ include Adamantium::Flat
43
8
 
44
- # Return a new processor with +chain+ as failure_chain
45
- #
46
- # @param [#call] chain
47
- # the failure chain to use for the new processor
48
- #
49
- # @return [#call]
50
- #
51
- # @api private
52
- def with_failure_chain(chain)
53
- self.class.new(name, handler, chain)
54
- end
55
- end
9
+ abstract_method :call
10
+ abstract_method :result
56
11
 
57
12
  module Incoming
58
13
  include Processor
59
- include Fallible
60
-
61
- # The request passed on to the next processor in a {Chain}
62
- #
63
- # @param [Response] _response
64
- # the response returned from invoking this processor
65
- #
66
- # @return [Request]
67
- # the request passed on to the next processor in a {Chain}
68
- #
69
- # @api private
70
- def result(_response)
71
- super.to_request
72
- end
73
- end
74
-
75
- module Pivot
76
- include Processor
77
- include Fallible
14
+ include Chain::Incoming
78
15
  end
79
16
 
80
17
  module Outgoing
81
- include Concord.new(:name, :handler)
82
18
  include Processor
19
+ include Chain::Outgoing
20
+ end
83
21
 
84
- # This processor's name
85
- #
86
- # @return [Symbol]
87
- #
88
- # @api private
89
- attr_reader :name
90
-
91
- # Test wether chain processing should continue
92
- #
93
- # @param [Response] _response
94
- # the response returned from invoking the processor
95
- #
96
- # @return [false]
97
- #
98
- # @api private
99
- def success?(_response)
100
- true
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
119
-
120
- end # module Outgoing
121
22
  end # module Processor
122
23
  end # module Substation
@@ -1,61 +1,30 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
  module Processor
5
3
 
6
- # Abstract processor to evaluate a request coming into a chain
4
+ # A processor to evaluate a chain's request input data
7
5
  class Evaluator
8
6
 
9
- # Processor to evaluate request input data
10
- class Data < self
11
- include Incoming
12
-
13
- private
14
-
15
- # Invoke the handler
16
- #
17
- # @param [Request] request
18
- # the request to evaluate
19
- #
20
- # @return [Response]
21
- #
22
- # @api private
23
- def invoke(request)
24
- handler.call(request.input)
25
- end
26
-
27
- end
28
-
29
- # Processor to evaluate an incoming request
30
- class Request < self
31
- include Incoming
32
- end
33
-
34
- # Processor to evaluate a pivot chain handler
35
- class Pivot < self
36
- include Processor::Pivot
37
-
38
- private
7
+ include Incoming
39
8
 
40
- # Return a successful response
41
- #
42
- # @param [Request] _request
43
- # the evaluated request
44
- #
45
- # @param [#output] result
46
- # the evaluation result
47
- #
48
- # @return [Response::Success]
49
- #
50
- # @api private
51
- def on_success(_request, response)
52
- response
53
- end
9
+ # Initialize a new instance
10
+ #
11
+ # @param [Environment] env
12
+ # the substation environment used to build chains
13
+ #
14
+ # @param [#call] handler
15
+ # the handler to perform evaluation
16
+ #
17
+ # @param [Proc] block
18
+ # a block to construct a failure chain
19
+ #
20
+ # @return [undefined]
21
+ #
22
+ # @api private
23
+ def initialize(env, handler, &block)
24
+ @env, @handler = env, handler
25
+ @failure_chain = block ? @env.chain(&block) : Undefined
54
26
  end
55
27
 
56
- include Adamantium::Flat
57
- include AbstractType
58
-
59
28
  # Evaluate a chain's request input data
60
29
  #
61
30
  # @param [Request] request
@@ -65,56 +34,46 @@ module Substation
65
34
  #
66
35
  # @api private
67
36
  def call(request)
68
- result = invoke(request)
37
+ result = handler.call(request.input)
38
+ output = result.output
69
39
  if result.success?
70
- on_success(request, result)
40
+ request.success(output)
71
41
  else
72
- on_failure(request, result)
42
+ response = request.error(output)
43
+ if fail_safe?
44
+ failure_chain.call(response)
45
+ else
46
+ response
47
+ end
73
48
  end
74
49
  end
75
50
 
76
- private
51
+ protected
77
52
 
78
- # Invoke the handler
79
- #
80
- # @param [Request] request
81
- # the request to evaluate
53
+ # The handler used to perform evaluation
82
54
  #
83
- # @return [Response]
55
+ # @return [#call]
84
56
  #
85
57
  # @api private
86
- def invoke(request)
87
- handler.call(request)
88
- end
58
+ attr_reader :handler
89
59
 
90
- # Return a successful response
91
- #
92
- # @param [Request] request
93
- # the evaluated request
94
- #
95
- # @param [#output] result
96
- # the evaluation result
60
+ private
61
+
62
+ # The chain to invoke if evaluation returned an error
97
63
  #
98
- # @return [Response::Success]
64
+ # @return [Chain]
99
65
  #
100
66
  # @api private
101
- def on_success(request, result)
102
- request.success(result.output)
103
- end
67
+ attr_reader :failure_chain
104
68
 
105
- # Return a failure response by invoking a failure chain
106
- #
107
- # @param [Request] request
108
- # the evaluated request
109
- #
110
- # @param [#output] result
111
- # the evaluation result
69
+ # Test wether this evaluator has a failure chain
112
70
  #
113
- # @return [Response::Failure]
71
+ # @return [TrueClass] if a failure chain is registered
72
+ # @return [FalseClass] otherwise
114
73
  #
115
74
  # @api private
116
- def on_failure(request, result)
117
- failure_chain.call(request.error(result.output))
75
+ def fail_safe?
76
+ !@failure_chain.equal?(Undefined)
118
77
  end
119
78
  end # class Evaluator
120
79
  end # module Processor
@@ -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(:env, :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
@@ -1,13 +1,11 @@
1
- # encoding: utf-8
2
-
3
1
  module Substation
4
2
  module Processor
5
3
 
6
4
  # A processor that wraps output data in a new handler instance
7
5
  class Wrapper
8
6
 
9
- include Processor::Outgoing
10
- include Adamantium::Flat
7
+ include Outgoing
8
+ include Concord.new(:env, :handler)
11
9
 
12
10
  # Wrap response data in an instance of {#handler}
13
11
  #