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,59 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ class Response
5
+ class Exception < self
6
+
7
+ # Wraps response data and an exception not caught from a handler
8
+ class Output
9
+ include Equalizer.new(:data)
10
+
11
+ # Return the data available when +exception+ was raised
12
+ #
13
+ # @return [Object]
14
+ #
15
+ # @api private
16
+ attr_reader :data
17
+
18
+ # Return the exception instance
19
+ #
20
+ # @return [Class<StandardError>]
21
+ #
22
+ # @api private
23
+ attr_reader :exception
24
+
25
+ # Initialize a new instance
26
+ #
27
+ # @param [Object] data
28
+ # the data available when +exception+ was raised
29
+ #
30
+ # @param [Class<StandardError>] exception
31
+ # the exception instance raised from a handler
32
+ #
33
+ # @return [undefined]
34
+ #
35
+ # @api private
36
+ def initialize(data, exception)
37
+ @data, @exception = data, exception
38
+ end
39
+
40
+ private
41
+
42
+ # Tests wether +other+ is comparable using +comparator+
43
+ #
44
+ # @param [Symbol] comparator
45
+ # the operation used for comparison
46
+ #
47
+ # @param [Object] other
48
+ # the object to test
49
+ #
50
+ # @return [Boolean]
51
+ #
52
+ # @api private
53
+ def cmp?(comparator, other)
54
+ super && exception.class.send(comparator, other.exception.class)
55
+ end
56
+ end # class Output
57
+ end # class Exception
58
+ end # class Response
59
+ end # module Substation
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ class Response
5
+
6
+ # An errorneous {Response}
7
+ class Failure < self
8
+ include API::Failure
9
+ end # class Failure
10
+ end # class Response
11
+ end # module Substation
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ module Substation
4
+ class Response
5
+
6
+ # A successful {Response}
7
+ class Success < self
8
+ include API::Success
9
+ end # class Success
10
+ end # class Response
11
+ end # module Substation
@@ -1,4 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  module Substation
2
4
  # Gem version
3
- VERSION = '0.0.10.beta2'.freeze
5
+ VERSION = '0.0.10'.freeze
4
6
  end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pp'
4
+
5
+ require 'anima'
6
+ require 'ducktrap'
7
+ require 'vanguard'
8
+ require 'substation'
9
+
10
+ class Demo
11
+
12
+ Undefined = Object.new.freeze
13
+
14
+ require 'demo/domain/storage'
15
+ require 'demo/domain/environment'
16
+ require 'demo/domain/actor'
17
+ require 'demo/domain/dto/person'
18
+
19
+ DATABASE =
20
+ {
21
+ :privileges => [
22
+ { :name => 'create_person' }
23
+ ],
24
+
25
+ :accounts => [
26
+ { :id => 1, :name => 'Jane' },
27
+ { :id => 2, :name => 'Mr.X' }
28
+ ],
29
+
30
+ :account_privileges => [
31
+ { :account_id => 1, :privilege_name => 'create_person' }
32
+ ],
33
+ }
34
+
35
+ logger = Object.new # some logger instance
36
+ storage = Domain::Storage.new(DATABASE)
37
+ env_name = ::ENV.fetch('APP_ENV', :development)
38
+
39
+ APP_ENV = Domain::Environment.build(env_name, storage, logger)
40
+
41
+ require 'demo/core/errors'
42
+ require 'demo/core/input'
43
+ require 'demo/core/handler'
44
+ require 'demo/core/handler/authenticator'
45
+ require 'demo/core/handler/authorizer'
46
+ require 'demo/core/handler/acceptor'
47
+ require 'demo/core/validator'
48
+ require 'demo/core/action'
49
+ require 'demo/core/action/create_person'
50
+ require 'demo/core/observers'
51
+
52
+ module Core
53
+ ENV = Substation::Environment.build(APP_ENV) do
54
+ register :authenticate, Substation::Processor::Evaluator::Request
55
+ register :authorize, Substation::Processor::Evaluator::Request
56
+ register :validate, Substation::Processor::Evaluator::Request, Core::Validator::EXECUTOR
57
+ register :accept, Substation::Processor::Transformer::Incoming, Core::Handler::Acceptor::EXECUTOR
58
+ register :call, Substation::Processor::Evaluator::Pivot
59
+ register :wrap, Substation::Processor::Wrapper::Outgoing, Core::Handler::Wrapper::Outgoing::EXECUTOR
60
+ end
61
+ end
62
+
63
+ require 'demo/core/facade'
64
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+
6
+ class Action
7
+ include AbstractType
8
+ include Adamantium::Flat
9
+
10
+ def self.call(request)
11
+ new(request).call
12
+ end
13
+
14
+ private_class_method :new
15
+
16
+ def initialize(request)
17
+ @request = request
18
+ @env = @request.env
19
+ @input = @request.input
20
+ @db = @env.storage
21
+ end
22
+
23
+ abstract_method :call
24
+
25
+ attr_reader :request
26
+ private :request
27
+
28
+ attr_reader :env
29
+ private :env
30
+
31
+ attr_reader :input
32
+ private :input
33
+
34
+ attr_reader :db
35
+ private :db
36
+
37
+ private
38
+
39
+ def success(data)
40
+ request.success(data)
41
+ end
42
+
43
+ def error(data)
44
+ request.error(data)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ class Action
6
+
7
+ class CreatePerson < self
8
+
9
+ def initialize(*)
10
+ super
11
+ @person = input.data
12
+ end
13
+
14
+ def call
15
+ name = @person.name
16
+ if name == 'error'
17
+ error(@person)
18
+ elsif name == 'exception'
19
+ raise RuntimeError
20
+ else
21
+ success(db.create_person(@person))
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ class Error
6
+ include Concord::Public.new(:object)
7
+ include Adamantium::Flat
8
+
9
+ InternalError = Class.new(self)
10
+ ApplicationError = Class.new(self)
11
+ AuthenticationError = Class.new(self)
12
+ AuthorizationError = Class.new(self)
13
+ ValidationError = Class.new(self)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+
6
+ module App
7
+
8
+ AUTHENTICATION_ERROR = Core::ENV.chain { wrap Error::AuthenticationError }
9
+ AUTHORIZATION_ERROR = Core::ENV.chain { wrap Error::AuthorizationError }
10
+ VALIDATION_ERROR = Core::ENV.chain { wrap Error::ValidationError }
11
+ APPLICATION_ERROR = Core::ENV.chain { wrap Error::ApplicationError }
12
+ INTERNAL_ERROR = Core::ENV.chain { wrap Error::InternalError }
13
+
14
+ AUTHENTICATE = Core::ENV.chain do
15
+ authenticate Handler::Authenticator, AUTHENTICATION_ERROR
16
+ end
17
+
18
+ AUTHORIZE = Core::ENV.chain(nil, AUTHENTICATE) do
19
+ authorize Handler::Authorizer, AUTHORIZATION_ERROR
20
+ end
21
+
22
+ Core::ENV.register(:create_person, AUTHORIZE, INTERNAL_ERROR) do
23
+ validate Domain::DTO::NEW_PERSON_VALIDATOR, VALIDATION_ERROR
24
+ accept Handler::Acceptor
25
+
26
+ call Action::CreatePerson, APPLICATION_ERROR, [
27
+ Observers::LOG_EVENT,
28
+ Observers::SEND_EMAIL
29
+ ]
30
+ end
31
+
32
+ end
33
+
34
+ # The application
35
+ APP = Core::ENV.dispatcher
36
+
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ module Handler
6
+ include Adamantium::Flat
7
+
8
+ def call(request)
9
+ new(request).call
10
+ end
11
+
12
+ module Wrapper
13
+ module Outgoing
14
+ DECOMPOSER = ->(response) { response.data }
15
+ COMPOSER = ->(response, output) { output }
16
+ EXECUTOR = Substation::Processor::Executor.new(DECOMPOSER, COMPOSER)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ module Handler
6
+
7
+ class Acceptor
8
+ extend Handler
9
+ include Equalizer.new(:session)
10
+
11
+ DECOMPOSER = ->(request) { request }
12
+
13
+ COMPOSER = ->(request, output) {
14
+ Input::Accepted.new(output, request.input.data)
15
+ }
16
+
17
+ EXECUTOR = Substation::Processor::Executor.new(DECOMPOSER, COMPOSER)
18
+
19
+ def initialize(request)
20
+ @db = request.env.storage
21
+ @session = request.input.session
22
+ @account_id = @session.fetch('account_id')
23
+ end
24
+
25
+ def call
26
+ Domain::Actor.coerce(session, person)
27
+ end
28
+
29
+ attr_reader :session
30
+ private :session
31
+
32
+ attr_reader :account_id
33
+ private :account_id
34
+
35
+ private
36
+
37
+ def person
38
+ Domain::DTO::Person.new(:id => account_id, :name => name)
39
+ end
40
+
41
+ def name
42
+ @db.load_person(account_id).name
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ module Handler
6
+
7
+ class Authenticator
8
+ extend Handler
9
+ include Substation::Processor::Evaluator::Handler
10
+
11
+ def initialize(request)
12
+ @request = request
13
+ @input = @request.input
14
+ @db = @request.env.storage
15
+ @account_id = @request.input.session.fetch('account_id')
16
+ end
17
+
18
+ def call
19
+ authenticated? ? success(input) : error(input)
20
+ end
21
+
22
+ attr_reader :request
23
+ private :request
24
+
25
+ attr_reader :input
26
+ private :input
27
+
28
+ private
29
+
30
+ def authenticated?
31
+ !!@db.load_person(@account_id)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+ module Handler
6
+
7
+ class Authorizer
8
+ extend Handler
9
+ include Substation::Processor::Evaluator::Handler
10
+
11
+ def initialize(request)
12
+ @request = request
13
+ @input = @request.input
14
+ @db = @request.env.storage
15
+ @account_id = @request.input.session.fetch('account_id')
16
+ @privilege = @request.name.to_s
17
+ end
18
+
19
+ def call
20
+ authorized? ? success(input) : error(input)
21
+ end
22
+
23
+ attr_reader :request
24
+ private :request
25
+
26
+ attr_reader :input
27
+ private :input
28
+
29
+ private
30
+
31
+ def authorized?
32
+ !!@db.load_account_privilege(@account_id, @privilege)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ class Demo
4
+ module Core
5
+
6
+ class Input
7
+ class Incomplete
8
+ include Concord::Public.new(:session, :data)
9
+ end
10
+ class Accepted
11
+ include Concord::Public.new(:actor, :data)
12
+ end
13
+ end
14
+ end
15
+ end