substation 0.0.10.beta2 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/.travis.yml +7 -3
  2. data/Changelog.md +99 -24
  3. data/Gemfile +8 -1
  4. data/Gemfile.devtools +37 -21
  5. data/Guardfile +1 -1
  6. data/README.md +118 -46
  7. data/TODO.md +1 -0
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/reek.yml +41 -16
  11. data/config/rubocop.yml +44 -0
  12. data/config/yardstick.yml +1 -1
  13. data/lib/substation.rb +41 -5
  14. data/lib/substation/chain.rb +73 -84
  15. data/lib/substation/chain/definition.rb +147 -0
  16. data/lib/substation/chain/dsl.rb +150 -112
  17. data/lib/substation/chain/dsl/config.rb +55 -0
  18. data/lib/substation/chain/dsl/module_builder.rb +84 -0
  19. data/lib/substation/dispatcher.rb +20 -229
  20. data/lib/substation/dsl/guard.rb +96 -0
  21. data/lib/substation/dsl/registry.rb +181 -0
  22. data/lib/substation/environment.rb +126 -23
  23. data/lib/substation/environment/dsl.rb +31 -12
  24. data/lib/substation/processor.rb +238 -7
  25. data/lib/substation/processor/builder.rb +26 -0
  26. data/lib/substation/processor/config.rb +24 -0
  27. data/lib/substation/processor/evaluator.rb +66 -42
  28. data/lib/substation/processor/evaluator/handler.rb +54 -0
  29. data/lib/substation/processor/evaluator/result.rb +24 -0
  30. data/lib/substation/processor/executor.rb +46 -0
  31. data/lib/substation/processor/nest.rb +40 -0
  32. data/lib/substation/processor/transformer.rb +46 -0
  33. data/lib/substation/processor/wrapper.rb +16 -5
  34. data/lib/substation/request.rb +29 -27
  35. data/lib/substation/response.rb +19 -34
  36. data/lib/substation/response/api.rb +37 -0
  37. data/lib/substation/response/exception.rb +20 -0
  38. data/lib/substation/response/exception/output.rb +59 -0
  39. data/lib/substation/response/failure.rb +11 -0
  40. data/lib/substation/response/success.rb +11 -0
  41. data/lib/substation/version.rb +3 -1
  42. data/spec/demo/core.rb +64 -0
  43. data/spec/demo/core/action.rb +49 -0
  44. data/spec/demo/core/action/create_person.rb +28 -0
  45. data/spec/demo/core/errors.rb +16 -0
  46. data/spec/demo/core/facade.rb +38 -0
  47. data/spec/demo/core/handler.rb +21 -0
  48. data/spec/demo/core/handler/acceptor.rb +47 -0
  49. data/spec/demo/core/handler/authenticator.rb +36 -0
  50. data/spec/demo/core/handler/authorizer.rb +38 -0
  51. data/spec/demo/core/input.rb +15 -0
  52. data/spec/demo/core/observers.rb +10 -0
  53. data/spec/demo/core/validator.rb +21 -0
  54. data/spec/demo/domain/actor.rb +29 -0
  55. data/spec/demo/domain/dto/person.rb +18 -0
  56. data/spec/demo/domain/environment.rb +55 -0
  57. data/spec/demo/domain/storage.rb +49 -0
  58. data/spec/demo/web.rb +26 -0
  59. data/spec/demo/web/errors.rb +9 -0
  60. data/spec/demo/web/facade.rb +60 -0
  61. data/spec/demo/web/handler/deserializer.rb +36 -0
  62. data/spec/demo/web/presenter.rb +38 -0
  63. data/spec/demo/web/presenter/person.rb +19 -0
  64. data/spec/demo/web/renderer.rb +45 -0
  65. data/spec/demo/web/sanitizer.rb +35 -0
  66. data/spec/demo/web/sanitizer/person.rb +20 -0
  67. data/spec/demo/web/views.rb +28 -0
  68. data/spec/integration/demo/core_spec.rb +97 -0
  69. data/spec/integration/demo/web_spec.rb +114 -0
  70. data/spec/shared/context/integration/demo.rb +33 -0
  71. data/spec/shared/context/unit/chain.rb +13 -0
  72. data/spec/shared/context/unit/processor.rb +58 -0
  73. data/spec/shared/context/unit/request.rb +8 -0
  74. data/spec/shared/examples/integration/demo.rb +35 -0
  75. data/spec/shared/examples/unit/processor.rb +72 -0
  76. data/spec/spec_helper.rb +52 -23
  77. data/spec/unit/substation/chain/definition_spec.rb +141 -0
  78. data/spec/unit/substation/chain/dsl/config/dsl_module_spec.rb +13 -0
  79. data/spec/unit/substation/chain/dsl/config/registry_spec.rb +13 -0
  80. data/spec/unit/substation/chain/dsl/config_spec.rb +18 -0
  81. data/spec/unit/substation/chain/dsl/module_builder_spec.rb +77 -0
  82. data/spec/unit/substation/chain/dsl_spec.rb +175 -0
  83. data/spec/unit/substation/chain_spec.rb +303 -0
  84. data/spec/unit/substation/dispatcher_spec.rb +68 -0
  85. data/spec/unit/substation/dsl/guard_spec.rb +72 -0
  86. data/spec/unit/substation/dsl/registry_spec.rb +181 -0
  87. data/spec/unit/substation/environment/dsl_spec.rb +156 -0
  88. data/spec/unit/substation/environment_spec.rb +259 -0
  89. data/spec/unit/substation/processor/builder_spec.rb +21 -0
  90. data/spec/unit/substation/processor/config_spec.rb +40 -0
  91. data/spec/unit/substation/processor/evaluator/handler_spec.rb +20 -0
  92. data/spec/unit/substation/processor/evaluator/pivot_spec.rb +42 -0
  93. data/spec/unit/substation/processor/evaluator/request_spec.rb +11 -0
  94. data/spec/unit/substation/processor/evaluator/result/failure_spec.rb +14 -0
  95. data/spec/unit/substation/processor/evaluator/result/success_spec.rb +14 -0
  96. data/spec/unit/substation/processor/evaluator/result_spec.rb +13 -0
  97. data/spec/unit/substation/processor/evaluator_spec.rb +18 -0
  98. data/spec/unit/substation/processor/executor/null_spec.rb +25 -0
  99. data/spec/unit/substation/processor/executor_spec.rb +32 -0
  100. data/spec/unit/substation/processor/fallible_spec.rb +24 -0
  101. data/spec/unit/substation/processor/incoming_spec.rb +17 -0
  102. data/spec/unit/substation/processor/nest/incoming_spec.rb +56 -0
  103. data/spec/unit/substation/processor/nest_spec.rb +6 -0
  104. data/spec/unit/substation/processor/outgoing_spec.rb +47 -0
  105. data/spec/unit/substation/processor/transformer/incoming_spec.rb +17 -0
  106. data/spec/unit/substation/processor/transformer/outgoing_spec.rb +17 -0
  107. data/spec/unit/substation/processor/wrapper/incoming_spec.rb +15 -0
  108. data/spec/unit/substation/processor/wrapper/outgoing_spec.rb +15 -0
  109. data/spec/unit/substation/processor/wrapper_spec.rb +24 -0
  110. data/spec/unit/substation/processor_spec.rb +68 -0
  111. data/spec/unit/substation/request_spec.rb +70 -0
  112. data/spec/unit/substation/response/api_spec.rb +22 -0
  113. data/spec/unit/substation/response/exception/output_spec.rb +46 -0
  114. data/spec/unit/substation/response/exception_spec.rb +25 -0
  115. data/spec/unit/substation/response/failure_spec.rb +25 -0
  116. data/spec/unit/substation/response/success_spec.rb +24 -0
  117. data/spec/unit/substation/response_spec.rb +73 -0
  118. data/substation.gemspec +7 -6
  119. metadata +157 -67
  120. checksums.yaml +0 -7
  121. data/TODO +0 -0
  122. data/lib/substation/observer.rb +0 -66
  123. data/lib/substation/processor/pivot.rb +0 -25
  124. data/lib/substation/utils.rb +0 -68
  125. data/spec/integration/substation/dispatcher/call_spec.rb +0 -260
  126. data/spec/unit/substation/chain/call_spec.rb +0 -63
  127. data/spec/unit/substation/chain/dsl/builder/class_methods/call_spec.rb +0 -19
  128. data/spec/unit/substation/chain/dsl/builder/dsl_spec.rb +0 -21
  129. data/spec/unit/substation/chain/dsl/builder/failure_chain_spec.rb +0 -30
  130. data/spec/unit/substation/chain/dsl/chain_spec.rb +0 -15
  131. data/spec/unit/substation/chain/dsl/class_methods/processors_spec.rb +0 -24
  132. data/spec/unit/substation/chain/dsl/initialize_spec.rb +0 -19
  133. data/spec/unit/substation/chain/dsl/processors_spec.rb +0 -42
  134. data/spec/unit/substation/chain/dsl/use_spec.rb +0 -14
  135. data/spec/unit/substation/chain/each_spec.rb +0 -46
  136. data/spec/unit/substation/chain/incoming/result_spec.rb +0 -21
  137. data/spec/unit/substation/chain/outgoing/call_spec.rb +0 -25
  138. data/spec/unit/substation/chain/outgoing/result_spec.rb +0 -21
  139. data/spec/unit/substation/dispatcher/action/call_spec.rb +0 -23
  140. data/spec/unit/substation/dispatcher/action/class_methods/coerce_spec.rb +0 -61
  141. data/spec/unit/substation/dispatcher/action_names_spec.rb +0 -14
  142. data/spec/unit/substation/dispatcher/call_spec.rb +0 -47
  143. data/spec/unit/substation/dispatcher/class_methods/coerce_spec.rb +0 -20
  144. data/spec/unit/substation/environment/chain_spec.rb +0 -50
  145. data/spec/unit/substation/environment/class_methods/build_spec.rb +0 -11
  146. data/spec/unit/substation/environment/dsl/class_methods/registry_spec.rb +0 -18
  147. data/spec/unit/substation/environment/dsl/register_spec.rb +0 -14
  148. data/spec/unit/substation/environment/dsl/registry_spec.rb +0 -19
  149. data/spec/unit/substation/observer/chain/call_spec.rb +0 -26
  150. data/spec/unit/substation/observer/class_methods/coerce_spec.rb +0 -33
  151. data/spec/unit/substation/observer/null/call_spec.rb +0 -12
  152. data/spec/unit/substation/processor/evaluator/call_spec.rb +0 -49
  153. data/spec/unit/substation/processor/pivot/call_spec.rb +0 -17
  154. data/spec/unit/substation/processor/wrapper/call_spec.rb +0 -20
  155. data/spec/unit/substation/request/env_spec.rb +0 -14
  156. data/spec/unit/substation/request/error_spec.rb +0 -15
  157. data/spec/unit/substation/request/input_spec.rb +0 -14
  158. data/spec/unit/substation/request/success_spec.rb +0 -15
  159. data/spec/unit/substation/response/env_spec.rb +0 -16
  160. data/spec/unit/substation/response/failure/success_predicate_spec.rb +0 -15
  161. data/spec/unit/substation/response/input_spec.rb +0 -16
  162. data/spec/unit/substation/response/output_spec.rb +0 -16
  163. data/spec/unit/substation/response/request_spec.rb +0 -16
  164. data/spec/unit/substation/response/success/success_predicate_spec.rb +0 -15
  165. data/spec/unit/substation/utils/class_methods/coerce_callable_spec.rb +0 -46
  166. data/spec/unit/substation/utils/class_methods/const_get_spec.rb +0 -46
  167. data/spec/unit/substation/utils/class_methods/symbolize_keys_spec.rb +0 -20
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ class Chain
5
+ class DSL
6
+
7
+ # A configuration object used with a {DSL} instance
8
+ class Config
9
+
10
+ # Build a new config based on {registry} suitable for a {DSL} instance
11
+ #
12
+ # @param [Hash<Symbol, Processor::Builder>] registry
13
+ # the registry of processor builders used in an {Environment}
14
+ #
15
+ # @return [Config]
16
+ #
17
+ # @api private
18
+ def self.build(registry)
19
+ new(registry, ModuleBuilder.call(registry))
20
+ end
21
+
22
+ include Equalizer.new(:registry)
23
+
24
+ # The registry of processor builders
25
+ #
26
+ # @return [Hash<Symbol, Processor::Builder>]
27
+ #
28
+ # @api private
29
+ attr_reader :registry
30
+
31
+ # A module exposing methods to build processors defined in {registry}
32
+ #
33
+ # @return [Module]
34
+ #
35
+ # @api private
36
+ attr_reader :dsl_module
37
+
38
+ # Initialize a new instance
39
+ #
40
+ # @param [Hash<Symbol, Processor::Builder>] registry
41
+ # the registry of processor builder instances
42
+ #
43
+ # @param [Module] dsl_module
44
+ # the module built by {Builder}, suitable for +registry+
45
+ #
46
+ # @return [undefined]
47
+ #
48
+ # @api private
49
+ def initialize(registry, dsl_module)
50
+ @registry, @dsl_module = registry, dsl_module
51
+ end
52
+ end # class Config
53
+ end # class DSL
54
+ end # class Chain
55
+ end # module Substation
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ class Chain
5
+ class DSL
6
+
7
+ # Builds a {Module} suitable for a {DSL} instance
8
+ class ModuleBuilder
9
+
10
+ # Builds a new {Module} targeted for a {DSL} instance
11
+ #
12
+ # @param [Hash<Symbol, Processor::Builder>] registry
13
+ # the registry of processor builders used in an {Environment}
14
+ #
15
+ # @return [Module]
16
+ #
17
+ # @api private
18
+ def self.call(registry)
19
+ new(registry).dsl_module
20
+ end
21
+
22
+ include Adamantium::Flat
23
+
24
+ # A module suitable for inclusion in a {DSL} instance
25
+ #
26
+ # @return [Module]
27
+ #
28
+ # @api private
29
+ attr_reader :dsl_module
30
+
31
+ # Initialize a new instance
32
+ #
33
+ # @param [Hash<Symbol, Processor::Builder>] registry
34
+ # the registry of processor builders to define methods for
35
+ #
36
+ # @return [undefined]
37
+ #
38
+ # @api private
39
+ def initialize(registry)
40
+ @registry = registry
41
+ @dsl_module = Module.new
42
+ initialize_dsl_module
43
+ end
44
+
45
+ private
46
+
47
+ # Compile a new module for inclusion into a {DSL} instance
48
+ #
49
+ # @param [Hash<Symbol, Processor::Builder>] registry
50
+ # the registry of processor builders to define methods for
51
+ #
52
+ # @return [undefined]
53
+ #
54
+ # @api private
55
+ def initialize_dsl_module
56
+ @registry.each { |pair| define_dsl_method(*pair) }
57
+ end
58
+
59
+ # Define a new instance method on the +dsl+ module
60
+ #
61
+ # @param [Symbol] name
62
+ # the name of the method
63
+ #
64
+ # @param [Processor::Builder] builder
65
+ # the processor builder to use within the chain
66
+ #
67
+ # @param [Module] dsl
68
+ # the module to define the method on
69
+ #
70
+ # @return [undefined]
71
+ #
72
+ # @api private
73
+ def define_dsl_method(name, builder)
74
+ @dsl_module.module_eval do
75
+ define_method(name) { |handler, failure_chain = EMPTY, observers = EMPTY_ARRAY|
76
+ use(builder.call(handler, failure_chain, observers))
77
+ }
78
+ end
79
+ end
80
+
81
+ end # class ModuleBuilder
82
+ end # class DSL
83
+ end # class Chain
84
+ end # module Substation
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Substation
2
4
 
3
5
  # Encapsulates all registered actions and their observers
@@ -7,207 +9,20 @@ module Substation
7
9
  # application use case.
8
10
  class Dispatcher
9
11
 
10
- # Encapsulates access to one registered action
11
- class Action
12
-
13
- # Raised when no action class name is configured
14
- MissingHandlerError = Class.new(StandardError)
15
-
16
- # Coerce the given +name+ and +config+ to an {Action} instance
17
- #
18
- # @param [#call, Hash<Symbol, Object>] config
19
- # the action configuration object
20
- #
21
- # @return [Action]
22
- # the coerced instance
23
- #
24
- # @raise [MissingHandlerError]
25
- # if no action handler is configured
26
- #
27
- # @raise [ArgumentError]
28
- # if action or observer handlers are not coercible
29
- #
30
- # @api private
31
- def self.coerce(config)
32
- if config.respond_to?(:fetch)
33
- action = config.fetch(:action) { raise(MissingHandlerError) }
34
- observer = config[:observer]
35
- else
36
- action = config
37
- end
38
-
39
- action_handler = Utils.coerce_callable(action)
40
- observer_handler = Observer.coerce(observer)
41
-
42
- new(action_handler, observer_handler)
43
- end
44
-
45
- include Concord.new(:handler, :observer)
46
- include Adamantium::Flat
47
-
48
- # Call the action
49
- #
50
- # @param [Substation::Request] request
51
- # the request passed to the registered action
52
- #
53
- # @return [Substation::Response]
54
- # the response returned when calling the action
55
- #
56
- # @api private
57
- def call(request)
58
- response = handler.call(request)
59
- observer.call(response)
60
- response
61
- end
62
-
63
- end # class Action
12
+ include Concord.new(:actions, :env)
13
+ include Adamantium::Flat
64
14
 
65
- # Raised when trying to dispatch to an unregistered action
66
- UnknownActionError = Class.new(StandardError)
15
+ GUARD = DSL::Guard.new(EMPTY_ARRAY)
67
16
 
68
- # Coerce the given +config+ to a {Dispatcher} instance
69
- #
70
- # @example setup code for all the other examples
71
- #
72
- # module App
73
- # class Environment
74
- # def initialize(storage, logger)
75
- # @storage, @logger = storage, logger
76
- # end
77
- # end
78
- #
79
- # class SomeUseCase
80
- # def self.call(request)
81
- # data = perform_work
82
- # request.success(data)
83
- # end
84
- # end
85
- #
86
- # class SomeObserver
87
- # def self.call(response)
88
- # # do something
89
- # end
90
- # end
91
- #
92
- # class AnotherObserver
93
- # def self.call(response)
94
- # # do something
95
- # end
96
- # end
97
- # end
98
- #
99
- # storage = SomeStorageAbstraction.new
100
- # env = App::Environment.new(storage, Logger.new($stdout))
101
- #
102
- # @example without observers (short form, symbol keys)
103
- #
104
- # dispatcher = Substation::Dispatcher.coerce({
105
- # :some_use_case => App::SomeUseCase
106
- # }, env)
107
- #
108
- # dispatcher = Substation::Dispatcher.coerce({
109
- # :some_use_case => 'App::SomeUseCase'
110
- # }, env)
111
- #
112
- # dispatcher = Substation::Dispatcher.coerce({
113
- # :some_use_case => :App::SomeUseCase
114
- # }, env)
115
- #
116
- # dispatcher = Substation::Dispatcher.coerce({
117
- # :some_use_case => Proc.new { |request| request.success(:data) }
118
- # }, env)
119
- #
120
- # @example without observers (long form, string keys)
121
- #
122
- # dispatcher = Substation::Dispatcher.coerce({
123
- # 'some_use_case' => { 'action' => 'SomeUseCase' }
124
- # }, env)
125
- #
126
- # @example with a single observer
127
- #
128
- # dispatcher = Substation::Dispatcher.coerce({
129
- # 'some_use_case' => {
130
- # 'action' => 'App::SomeUseCase',
131
- # 'observer' => 'App::SomeObserver'
132
- # }
133
- # }, env)
134
- #
135
- # @example with multiple observers
136
- #
137
- # dispatcher = Substation::Dispatcher.coerce({
138
- # 'some_use_case' => {
139
- # 'action' => 'App::SomeUseCase',
140
- # 'observer' => [
141
- # 'App::SomeObserver',
142
- # 'App::AnotherObserver'
143
- # ]
144
- # }
145
- # }, env)
146
- #
147
- # @example with Symbol keys and const handlers
148
- #
149
- # dispatcher = Substation::Dispatcher.coerce({
150
- # :some_use_case => {
151
- # :action => App::SomeUseCase,
152
- # :observer => App::SomeObserver
153
- # }
154
- # }, env)
17
+ # Return a new registry instance suitable for {Dispatcher}
155
18
  #
156
- # @example with Symbol keys and proc handlers
157
- #
158
- # dispatcher = Substation::Dispatcher.coerce({
159
- # :some_use_case => {
160
- # :action => Proc.new { |request| request.success(:foo) },
161
- # :observer => Proc.new { |response| do_something }
162
- # }
163
- # }, env)
164
- #
165
- # @param [Hash<#to_sym, Object>] config
166
- # the action configuration
167
- #
168
- # @param [Object] env
169
- # the application environment
170
- #
171
- # @return [Dispatcher]
172
- # the coerced instance
173
- #
174
- # @raise [Action::MissingHandlerError]
175
- # if no action handler is configured
176
- #
177
- # @raise [ArgumentError]
178
- # if action or observer handlers are not coercible
179
- #
180
- # @api public
181
- def self.coerce(config, env)
182
- new(normalize_config(config), env)
183
- end
184
-
185
- # Normalize the given +config+
186
- #
187
- # @param [Hash<#to_sym, Object>] config
188
- # the action configuration
189
- #
190
- # @return [Hash<Symbol, Action>]
191
- # the normalized config hash
192
- #
193
- # @raise [Action::MissingHandlerError]
194
- # if no action handler is configured
195
- #
196
- # @raise [ArgumentError]
197
- # if action or observer handlers are not coercible
19
+ # @return [DSL::Registry]
198
20
  #
199
21
  # @api private
200
- def self.normalize_config(config)
201
- Utils.symbolize_keys(config).each_with_object({}) { |(name, action), actions|
202
- actions[name] = Action.coerce(action)
203
- }
22
+ def self.new_registry
23
+ DSL::Registry.new(GUARD)
204
24
  end
205
25
 
206
- private_class_method :normalize_config
207
-
208
- include Concord.new(:actions, :env)
209
- include Adamantium::Flat
210
-
211
26
  # Invoke the action identified by +name+
212
27
  #
213
28
  # @example
@@ -249,45 +64,21 @@ module Substation
249
64
  #
250
65
  # @api public
251
66
  def call(name, input)
252
- fetch(name).call(Request.new(env, input))
67
+ fetch(name).call(Request.new(name, env, input))
253
68
  end
254
69
 
255
- # The names of all registered actions
70
+ # Test wether a chain with the given +name+ is registered
256
71
  #
257
- # @example
258
- #
259
- # module App
260
- # class Environment
261
- # def initialize(storage, logger)
262
- # @storage, @logger = storage, logger
263
- # end
264
- # end
265
- #
266
- # class SomeUseCase
267
- # def self.call(request)
268
- # data = perform_work
269
- # request.success(data)
270
- # end
271
- # end
272
- # end
273
- #
274
- # storage = SomeStorageAbstraction.new
275
- # env = App::Environment.new(storage, Logger.new($stdout))
276
- # config = { :some_use_case => { :action => App::SomeUseCase } }
277
- # dispatcher = Substation::Dispatcher.coerce(config, env)
278
- #
279
- # dispatcher.action_names # => #<Set: {:some_use_case}>
72
+ # @param [Symbol] name
73
+ # the name of the chain to test for
280
74
  #
281
- # @return [Set<Symbol>]
282
- # the set of registered action names
75
+ # @return [Boolean]
283
76
  #
284
- # @api public
285
- def action_names
286
- Set.new(actions.keys)
77
+ # @api private
78
+ def include?(name)
79
+ actions.include?(name)
287
80
  end
288
81
 
289
- memoize :action_names
290
-
291
82
  private
292
83
 
293
84
  # The action registered with +name+
@@ -295,10 +86,10 @@ module Substation
295
86
  # @param [Symbol] name
296
87
  # a name for which an action is registered
297
88
  #
298
- # @return [Action]
299
- # the action configuration registered for +name+
89
+ # @return [#call]
90
+ # the callable registered for +name+
300
91
  #
301
- # @raise [KeyError]
92
+ # @raise [UnknownActionError]
302
93
  # if no action is registered with +name+
303
94
  #
304
95
  # @api private
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ module DSL
5
+
6
+ # A guard used for rejecting invalid names in {DSL}
7
+ class Guard
8
+
9
+ include Equalizer.new(:reserved_names)
10
+ include Adamantium::Flat
11
+
12
+ # Message for ReservedNameError
13
+ RESERVED_NAME_MSG = '%s is a reserved name'.freeze
14
+
15
+ # Message for AlreadyRegisteredError
16
+ ALREADY_REGISTERED_MSG = '%s is already registered'.freeze
17
+
18
+ # The list of reserved names
19
+ #
20
+ # @return [Enumerable<Symbol>]
21
+ #
22
+ # @api private
23
+ attr_reader :reserved_names
24
+ private :reserved_names
25
+
26
+ # Initialize a new instance
27
+ #
28
+ # @param [Enumerable<Symbol>] reserved_names
29
+ # a list of reserved names
30
+ #
31
+ # @return [undefined]
32
+ #
33
+ # @api private
34
+ def initialize(reserved_names = EMPTY_ARRAY)
35
+ @reserved_names = reserved_names
36
+ end
37
+
38
+ # Raise if {#name} is either reserved or already registered
39
+ #
40
+ # @param [Symbol] name
41
+ # the name to test
42
+ #
43
+ # @param [#include?] registry
44
+ # the registry to test
45
+ #
46
+ # @raise [AlreadyRegisteredError]
47
+ # if +name+ is already registered
48
+ #
49
+ # @raise [ReservedNameError]
50
+ # if +name+ is a reserved name
51
+ #
52
+ # @return [undefined]
53
+ #
54
+ # @api private
55
+ def call(name, registry)
56
+ raise_if_already_registered(name, registry)
57
+ raise_if_reserved(name)
58
+ end
59
+
60
+ private
61
+
62
+ # Raise if +name+ is already included in {#names}
63
+ #
64
+ # @param [Symbol] name
65
+ # the name to test
66
+ #
67
+ # @raise [AlreadyRegisteredError]
68
+ #
69
+ # @return [undefined]
70
+ #
71
+ # @api private
72
+ def raise_if_already_registered(name, registry)
73
+ if registry.include?(name)
74
+ raise AlreadyRegisteredError, ALREADY_REGISTERED_MSG % name.inspect
75
+ end
76
+ end
77
+
78
+ # Raise if {Chain::DSL.methods} include +name+
79
+ #
80
+ # @param [Symbol] name
81
+ # the name to test
82
+ #
83
+ # @raise [ReservedNameError]
84
+ #
85
+ # @return [undefined]
86
+ #
87
+ # @api private
88
+ def raise_if_reserved(name)
89
+ if reserved_names.include?(name)
90
+ raise ReservedNameError, RESERVED_NAME_MSG % name.inspect
91
+ end
92
+ end
93
+
94
+ end # class Guard
95
+ end # module DSL
96
+ end # module Substation