light-service-ext 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +9 -1
- data/README.md +193 -5
- data/dev/setup.rb +5 -3
- data/lib/light-service-ext/application_action.rb +0 -21
- data/lib/light-service-ext/application_context.rb +29 -1
- data/lib/light-service-ext/application_validator_action.rb +2 -2
- data/lib/light-service-ext/configuration.rb +28 -0
- data/lib/light-service-ext/constants.rb +1 -1
- data/lib/light-service-ext/error_info.rb +11 -11
- data/lib/light-service-ext/version.rb +1 -1
- data/lib/light-service-ext/with_error_handler.rb +26 -0
- data/lib/light-service-ext.rb +35 -13
- data/light-service-ext.gemspec +2 -1
- data/spec/light-service-ext/application_action_spec.rb +39 -0
- data/spec/light-service-ext/application_context_spec.rb +189 -0
- data/spec/{light_service_ext → light-service-ext}/application_organizer_spec.rb +9 -2
- data/spec/light-service-ext/configuration_spec.rb +66 -0
- data/spec/{light_service_ext → light-service-ext}/error_info_spec.rb +18 -7
- data/spec/light-service-ext/with_error_handler_spec.rb +62 -0
- data/spec/light_service_ext_spec.rb +67 -1
- data/spec/spec_helper.rb +7 -3
- metadata +42 -22
- data/spec/light_service_ext/application_action_spec.rb +0 -77
- data/spec/light_service_ext/application_context_spec.rb +0 -68
- /data/spec/{light_service_ext → light-service-ext}/all_actions_complete_action_spec.rb +0 -0
- /data/spec/{light_service_ext → light-service-ext}/application_contract_spec.rb +0 -0
- /data/spec/{light_service_ext → light-service-ext}/application_validator_action_spec.rb +0 -0
- /data/spec/{light_service_ext → light-service-ext}/around_action_execute_extension_spec.rb +0 -0
- /data/spec/{light_service_ext → light-service-ext}/context_error_spec.rb +0 -0
- /data/spec/{light_service_ext → light-service-ext}/regex_spec.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a72952c78aab0b82bbce081bd1c2ab955ef264a9fbb5186a9ead3a429eaa504e
|
4
|
+
data.tar.gz: 43cb1863bac420a7150573a0e24cc141bd2384e36cfc4440dbd12f2fce276e93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cabc217b43f33aa0771de27613eeecd83f425786e93946ed14d716523814a4af7045d464ae16841b6d3e2db20a8b0f4d780190363ad130bf934c100b962ba1f1
|
7
|
+
data.tar.gz: 5ab3b2151ebb98e80b65a24717a628d7e9f60f206b25c258a05d32e3d57c85e832d99b92905f4883e2d770e9240da85e611771b2497d17f7c87687e670b82838
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.1.0] - 2023-02-
|
3
|
+
## [0.1.0] - 2023-02-15
|
4
4
|
|
5
5
|
- Initial release
|
6
|
+
|
7
|
+
## [0.1.1] - 2023-02-15
|
8
|
+
|
9
|
+
- Fixing issue with with use of `relative_path` inside of `light-service-ext.gemspec`
|
10
|
+
|
11
|
+
## [0.1.2] - YYYY-MM-DD
|
12
|
+
|
13
|
+
- Updates `README.md` with detailed information on features provided
|
data/README.md
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
1
|
+

|
2
2
|
|
3
|
-
|
3
|
+
# Light Service Extensions
|
4
4
|
|
5
|
-
|
5
|
+
Aims to enhance [light-service](https://github.com/adomokos/light-service) to enhance this powerful and flexible service skeleton framework with an emphasis on simplicity
|
6
|
+
|
7
|
+
## Console
|
8
|
+
run `bin/console` for an interactive prompt.
|
6
9
|
|
7
10
|
## Installation
|
8
11
|
|
@@ -20,9 +23,194 @@ Or install it yourself as:
|
|
20
23
|
|
21
24
|
$ gem install light-service-ext
|
22
25
|
|
23
|
-
##
|
26
|
+
## ApplicationContext
|
27
|
+
|
28
|
+
> Adds useful defaults to the organizer/orchestrator context
|
29
|
+
- `:input` ~> values originally provided to organizer get moved here for better isolation
|
30
|
+
- `:params`
|
31
|
+
- stores values `filtered` and `mapped` from original `input`
|
32
|
+
- outcomes/return values provided by any action that implements `LightServiceExt::ApplicationAction`
|
33
|
+
- `:errors`
|
34
|
+
- validation errors processed by `LightServiceExt::ApplicationValidatorAction` [dry-validation](https://github.com/dry-rb/dry-validation) contract
|
35
|
+
- manually added by an action e.g. `{ errors: { email: 'not found' } }`
|
36
|
+
- `:successful_actions` ~> provides a list of actions processed mostly useful for debugging purposes
|
37
|
+
- `:api_responses` ~> contains a list of external API interactions mostly for recording/debugging purposes
|
38
|
+
- `:allow_raise_on_failure` ~> determines whether or not to throw a `RaiseOnContextError` error up the stack in the case of validation errors and/or captured exceptions
|
39
|
+
- `:outcome` denotes the current status of the organizer with one of the following flags:
|
40
|
+
- `LightServiceExt::Outcome::COMPLETE`
|
41
|
+
|
42
|
+
Example
|
43
|
+
|
44
|
+
````ruby
|
45
|
+
input = { order: order }
|
46
|
+
overrides = {} # optionally override `params`, `errors` and `allow_raise_on_failure`
|
47
|
+
LightServiceExt::ApplicationContext.make_with_defaults(input, overrides)
|
48
|
+
|
49
|
+
# => { input: { order: order },
|
50
|
+
# params: {},
|
51
|
+
# errors: {},
|
52
|
+
# successful_actions: [],
|
53
|
+
# api_responses: [],
|
54
|
+
# allow_raise_on_failure: true
|
55
|
+
# }
|
56
|
+
````
|
57
|
+
|
58
|
+
#### Useful methods
|
59
|
+
|
60
|
+
- `.add_params(**params)`
|
61
|
+
- Adds given args to context's `params` field
|
62
|
+
- e.g. `add_params(user_id: 1) # => { params: { user_id: 1 } }`
|
63
|
+
- `.add_errors(**errors)`
|
64
|
+
- Adds given args to to context's `errors` field
|
65
|
+
- Fails and returns from current action/organizer's context
|
66
|
+
- e.g. `add_to_errors(email: 'not found') # => { errors: { email: 'not found' } }`
|
67
|
+
|
68
|
+
|
69
|
+
## ApplicationOrganizer
|
70
|
+
|
71
|
+
> Adds the following support
|
72
|
+
|
73
|
+
### Useful methods
|
74
|
+
|
75
|
+
- `.reduce_if_success(<list of actions>)` prevents execution of action/step in the case of context failure or `:errors` present
|
76
|
+
- `.with_context(&block)` calls given block with `:ctx` argument
|
77
|
+
- `.execute_if` ~> Useful if you want the current `Organizer` to act as a `Orchestrator` and call another organizer
|
78
|
+
- *ONLY* modifies the current organizer/orchestrator's as a result of executing `organizer_or_action_class_or_proc` if manually applied by a given `result_callback` Proc
|
79
|
+
- Executed `steps` do modify the current organizer/orchestrator's context without the need for manual intervention
|
80
|
+
- Arguments:
|
81
|
+
- `condition_block` (required) ~> given block is called with current `context` argument
|
82
|
+
- `organizer_or_action_class_or_proc` (required) ~> only executed if `condition_block` evaluates to `true`
|
83
|
+
- must be one of `ApplicationOrganizer`, `ApplicationAction`, `Proc`
|
84
|
+
- `apply_ctx_transform` (optional)
|
85
|
+
- given block is called prior to `organizer_or_action_class_or_proc` being executed
|
86
|
+
- e.g. `apply_ctx_transform: -> (context) { context[:params][:user_id] = record(context)&.id }`
|
87
|
+
- returned value gets passed to `organizer_or_action_class_or_proc` call
|
88
|
+
- `result_callback` (optional)
|
89
|
+
- given block is called after `organizer_or_action_class_or_proc` has been executed
|
90
|
+
- Useful in the case where you want to augment the current organizer's context based on the context returned from the `organizer_or_action_class_or_proc` call
|
91
|
+
- e.g. `result_callback: -> (ctx:, result:) { ctx[:params] = result[:params] }`
|
92
|
+
- `ctx:` represents the main `organizer/orchestrator's` context
|
93
|
+
- `result:` represents the context returned from the executed `organizer_or_action_class_or_proc`
|
94
|
+
- `steps` (optional) ~> calls current `organizer/orchestrator's` actions/steps and called once `organizer_or_action_class_or_proc` has been processed
|
95
|
+
- *PLEASE NOTE* called regardless of the result from the `organizer_or_action_class_or_proc` call unless you *manually* fail the current context or add `:errors`
|
96
|
+
|
97
|
+
#### Error Handling
|
98
|
+
> Provided by `.with_error_handler`
|
99
|
+
|
100
|
+
- Records errors via `issue_error_report!` into context as exemplified below:
|
101
|
+
```ruby
|
102
|
+
{
|
103
|
+
errors: {
|
104
|
+
base: "some-exception-message",
|
105
|
+
internal_only: {
|
106
|
+
type: 'ArgumentError',
|
107
|
+
message: "`user_id` must be a number",
|
108
|
+
exception: "ArgumentError : `user_id` must be a number",
|
109
|
+
backtrace: [], # filtered backtrace via `[ActiveSupport::BacktraceCleaner](https://api.rubyonrails.org/classes/ActiveSupport/BacktraceCleaner.html)`
|
110
|
+
error: original_captured_exception
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
```
|
115
|
+
|
116
|
+
- Captures `model validation` exceptions and record the messages to the organizer's `:errors` context field
|
117
|
+
- Supports the following exceptions by default
|
118
|
+
- `ActiveRecord::Errors`
|
119
|
+
- `ActiveModel::Errors`
|
120
|
+
- Raises any non validation errors up the stack
|
121
|
+
|
122
|
+
#### API Responses
|
123
|
+
- records api responses set by an action's `:api_response` context field
|
124
|
+
- Stored inside of the organizer's `:api_responses` field
|
125
|
+
|
126
|
+
#### Retrieve Record
|
127
|
+
> Allows for a block to be defined on an organizer in order to retrieve the model record
|
128
|
+
|
129
|
+
Example
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
class TaxCalculator < LightServiceExt::ApplicationOrganizer
|
133
|
+
self.retrieve_record = -> (ctx:) { User.find_by(email: ctx.params[:email]) }
|
134
|
+
|
135
|
+
def self.call(input:)
|
136
|
+
user = record(ctx: input) # `.record` method executes proc provided to `retrieve_record`
|
137
|
+
input = { user: user }.merge(user: user)
|
138
|
+
reduce_with({ input: input }, steps)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Failing The Context
|
144
|
+
- Prevents further action's been executed in the following scenarios:
|
145
|
+
- All actions complete determined by organizer's `:outcome` context field set to `LightServiceExt::Outcome::COMPLETE`
|
146
|
+
|
147
|
+
### ApplicationAction
|
148
|
+
|
149
|
+
#### Useful methods
|
150
|
+
- TODO
|
151
|
+
|
152
|
+
#### Invoked Action
|
153
|
+
- *NOTE* Action's `executed` block gets called by the underlying `LightService::Action`
|
154
|
+
- this means in order to call your action's methods you need to invoke it from `invoked_action:` instead of `self`
|
155
|
+
- `invoked_action:` added to current action's context before it gets executed
|
156
|
+
- Consist of an instance of the current action that implements `LightServiceExt::ApplicationAction`
|
157
|
+
|
158
|
+
## ApplicationContract
|
159
|
+
|
160
|
+
- Enhances `Dry::Validation::Contract` with the following methods:
|
161
|
+
- `#keys` ~> returns names of params defined
|
162
|
+
- `#t` ~> returns translation messages in context with the current organizer
|
163
|
+
- Arguments:
|
164
|
+
- `key` e.g. :not_found
|
165
|
+
- `base_path:` e.g. :user
|
166
|
+
- `**opts` options passed into underlying Rails i18n translate call
|
167
|
+
- E.g. `t(:not_found, base_path: 'business_create', scope: 'user')` would execute
|
168
|
+
- => `I18n.t('business_create.user.not_found', opts.except(:scope))`
|
169
|
+
|
170
|
+
## ApplicationValidatorAction
|
171
|
+
|
172
|
+
> Responsible for mapping, filtering and validating the context `input:` field
|
173
|
+
|
174
|
+
- `executed` block does the following:
|
175
|
+
- Appends `params:` field to the current context with the mapped and filtered values
|
176
|
+
- Appends errors returned from a `ApplicationContract` [dry-validation](https://github.com/dry-rb/dry-validation) contract to the current context's `errors:` field
|
177
|
+
- *NOTE* fails current context if `errors:` present
|
178
|
+
|
179
|
+
##### Useful Accessors
|
180
|
+
|
181
|
+
- `.contract_class` ~> sets the [dry-validation](https://github.com/dry-rb/dry-validation) contract to be applied by the current validator action
|
182
|
+
- `.params_mapper_class` ~> sets the mapper class that must implement `.map_from(context)` and return mapped `:input` values
|
183
|
+
|
184
|
+
## ContextError
|
185
|
+
|
186
|
+
> Provides all the information related to an exception/validation errors captured by the current organizer
|
187
|
+
|
188
|
+
#### Useful methods
|
189
|
+
- `#error_info` ~> `ErrorInfo` instance
|
190
|
+
- `#context` ~> state of context provided
|
191
|
+
- `#error` ~> original exception
|
192
|
+
- `#message` ~> summarizes which action failed etc.
|
193
|
+
|
194
|
+
## ErrorInfo
|
195
|
+
- Summarize captured exception
|
196
|
+
|
197
|
+
#### Useful accessors
|
198
|
+
- `non_fatal_errors` ~> takes a list of error class names considered to be non fatal exceptions
|
199
|
+
|
200
|
+
#### Useful methods
|
201
|
+
- `#error` ~> captured exception
|
202
|
+
- `#type` ~> exception class name e.g. `ArgumentError`
|
203
|
+
- `#message` ~> error message
|
204
|
+
- `title` ~> combined error class name and error message e.g. `ArgumentError : email must be present`
|
205
|
+
- `#fatal_error?`
|
206
|
+
- `#error_summary` ~> summarizes exception with message and cleaned backtrace via `ActiveSupport::BacktraceCleaner`
|
207
|
+
|
208
|
+
## Regex
|
24
209
|
|
25
|
-
|
210
|
+
#### Useful methods
|
211
|
+
- `.match?(type, value)` e.g. `LightServiceExt::Regex.match?(email:, 'email@domain.com')`
|
212
|
+
- supported `type`:
|
213
|
+
- :email
|
26
214
|
|
27
215
|
## Development
|
28
216
|
|
data/dev/setup.rb
CHANGED
@@ -5,8 +5,10 @@
|
|
5
5
|
require 'json'
|
6
6
|
require 'light-service'
|
7
7
|
require 'dry-validation'
|
8
|
+
require 'rspec/core'
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
end
|
10
|
+
require 'active_support/core_ext/array'
|
11
|
+
require 'active_support/configurable'
|
12
12
|
|
13
|
+
require File.expand_path("../../lib/light-service-ext", Pathname.new(__FILE__).realpath)
|
14
|
+
require File.expand_path("../../spec/spec_helper", Pathname.new(__FILE__).realpath)
|
@@ -4,27 +4,6 @@ module LightServiceExt
|
|
4
4
|
class ApplicationAction
|
5
5
|
extend LightService::Action
|
6
6
|
|
7
|
-
class << self
|
8
|
-
def add_params(ctx, **params)
|
9
|
-
add_to_context(ctx, :params, **params)
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_errors(ctx, **errors)
|
13
|
-
add_to_context(ctx, :errors, **errors)
|
14
|
-
|
15
|
-
ctx.fail_and_return! if ctx[:errors].present?
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def add_to_context(ctx, key, **args)
|
21
|
-
return if ctx.nil?
|
22
|
-
|
23
|
-
ctx[key].merge!(args.dup)
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
7
|
def self.inherited(base)
|
29
8
|
base.singleton_class.prepend AroundActionExecuteExtension
|
30
9
|
super
|
@@ -13,10 +13,38 @@ module LightServiceExt
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def default_attrs
|
16
|
-
{ errors: {}, params: {}, successful_actions: [], api_responses: [],
|
16
|
+
{ errors: {}, params: {}, successful_actions: [], api_responses: [],
|
17
|
+
allow_raise_on_failure: LightServiceExt.config.allow_raise_on_failure?,
|
18
|
+
internal_only: { error_info: nil } }.freeze
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
22
|
+
def add_params(**params)
|
23
|
+
return if params.blank?
|
24
|
+
|
25
|
+
self[:params].merge!(params.dup)
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_internal_only(**attrs)
|
29
|
+
return if attrs.blank?
|
30
|
+
|
31
|
+
self[:internal_only].merge!(attrs.dup)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_errors(**errors)
|
35
|
+
return if errors.blank?
|
36
|
+
|
37
|
+
self[:errors].merge!(errors.dup)
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_errors!(**errors)
|
42
|
+
return if errors.blank?
|
43
|
+
|
44
|
+
add_errors(**errors)
|
45
|
+
fail_and_return!
|
46
|
+
end
|
47
|
+
|
20
48
|
def invoked_action
|
21
49
|
self[:invoked_action]
|
22
50
|
end
|
@@ -7,8 +7,8 @@ module LightServiceExt
|
|
7
7
|
|
8
8
|
executed do |context|
|
9
9
|
validator = map_and_validate_inputs(context)
|
10
|
-
add_params(
|
11
|
-
add_errors(
|
10
|
+
context.add_params(**validator.to_h)
|
11
|
+
context.add_errors!(**validator.errors.to_h.transform_values(&:first))
|
12
12
|
end
|
13
13
|
|
14
14
|
class << self
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LightServiceExt
|
4
|
+
class Configuration
|
5
|
+
include ActiveSupport::Configurable
|
6
|
+
|
7
|
+
config_accessor(:allow_raise_on_failure, default: true)
|
8
|
+
config_accessor(:non_fatal_error_classes, default: [])
|
9
|
+
config_accessor(:default_non_fatal_error_classes) { ['Rails::ActiveRecordError'.safe_constantize] }
|
10
|
+
config_accessor(:logger) { (defined? Rails.logger).nil? ? Logger.new($stdout) : Rails.logger }
|
11
|
+
|
12
|
+
def allow_raise_on_failure?
|
13
|
+
!!allow_raise_on_failure
|
14
|
+
end
|
15
|
+
|
16
|
+
def non_fatal_errors
|
17
|
+
(default_non_fatal_error_classes + non_fatal_error_classes).compact.uniq.map(&:to_s).freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
def fatal_error?(exception)
|
21
|
+
!non_fatal_errors.exclude?(exception.class.name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def non_fatal_error?(exception)
|
25
|
+
non_fatal_errors.include?(exception.class.name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -29,6 +29,13 @@ module LightServiceExt
|
|
29
29
|
TEXT
|
30
30
|
end
|
31
31
|
|
32
|
+
def errors
|
33
|
+
model = error && (error.try(:model) || error.try(:record))
|
34
|
+
return model.errors.messages.transform_values(&:first) if model.present?
|
35
|
+
|
36
|
+
{ base: message }
|
37
|
+
end
|
38
|
+
|
32
39
|
def to_h
|
33
40
|
{
|
34
41
|
type: type,
|
@@ -36,7 +43,8 @@ module LightServiceExt
|
|
36
43
|
exception: title,
|
37
44
|
backtrace: clean_backtrace[0, 3]&.join("\n"),
|
38
45
|
error: error,
|
39
|
-
fatal_error?: fatal_error
|
46
|
+
fatal_error?: fatal_error?,
|
47
|
+
errors: errors
|
40
48
|
}
|
41
49
|
end
|
42
50
|
|
@@ -45,7 +53,7 @@ module LightServiceExt
|
|
45
53
|
end
|
46
54
|
|
47
55
|
def clean_backtrace
|
48
|
-
@clean_backtrace ||= if defined? Rails
|
56
|
+
@clean_backtrace ||= if defined? Rails.backtrace_cleaner
|
49
57
|
Rails.backtrace_cleaner.clean(backtrace || [])
|
50
58
|
else
|
51
59
|
backtrace || []
|
@@ -53,15 +61,7 @@ module LightServiceExt
|
|
53
61
|
end
|
54
62
|
|
55
63
|
def non_fatal_error?
|
56
|
-
error.nil? ||
|
57
|
-
end
|
58
|
-
|
59
|
-
class << self
|
60
|
-
attr_writer :non_fatal_errors
|
61
|
-
|
62
|
-
def non_fatal_errors
|
63
|
-
@non_fatal_errors ||= []
|
64
|
-
end
|
64
|
+
error.nil? || LightServiceExt.config.non_fatal_error?(error)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/AbcSize
|
4
|
+
|
5
|
+
module LightServiceExt
|
6
|
+
module WithErrorHandler
|
7
|
+
def with_error_handler(ctx:)
|
8
|
+
@result = yield || ApplicationContext.make_with_defaults
|
9
|
+
rescue Rails::ActiveRecordError => e
|
10
|
+
error_info = ErrorInfo.new(e, fatal: false)
|
11
|
+
ctx.add_internal_only(error_info: error_info)
|
12
|
+
ctx.add_errors(**error_info.errors)
|
13
|
+
|
14
|
+
LightServiceExt.config.logger.error(error_info.error_summary)
|
15
|
+
|
16
|
+
ctx.fail!
|
17
|
+
ctx
|
18
|
+
rescue StandardError => e
|
19
|
+
error_info = ErrorInfo.new(e, fatal: false)
|
20
|
+
LightServiceExt.config.logger.error(error_info.error_summary)
|
21
|
+
|
22
|
+
raise
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
# rubocop:enable Metrics/AbcSize
|
data/lib/light-service-ext.rb
CHANGED
@@ -1,16 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
%w[
|
4
|
+
version
|
5
|
+
constants
|
6
|
+
regex
|
7
|
+
error_info
|
8
|
+
context_error
|
9
|
+
configuration
|
10
|
+
with_error_handler
|
11
|
+
application_context
|
12
|
+
application_contract
|
13
|
+
around_action_execute_extension
|
14
|
+
application_action
|
15
|
+
all_actions_complete_action
|
16
|
+
application_validator_action
|
17
|
+
application_organizer
|
18
|
+
].each do |filename|
|
19
|
+
require File.expand_path("../light-service-ext/#{filename}", Pathname.new(__FILE__).realpath)
|
20
|
+
end
|
15
21
|
|
16
|
-
|
22
|
+
|
23
|
+
|
24
|
+
module LightServiceExt
|
25
|
+
class << self
|
26
|
+
def config
|
27
|
+
self.configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def configuration
|
31
|
+
@configuration ||= Configuration.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def configure
|
35
|
+
yield configuration
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/light-service-ext.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require File.expand_path('../lib/light-service-ext/version', __FILE__)
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.authors = ["Desmond O'Leary"]
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |gem|
|
|
26
26
|
gem.add_runtime_dependency 'dry-struct', '~> 1.6'
|
27
27
|
gem.add_runtime_dependency 'dry-validation', '~> 1.10'
|
28
28
|
gem.add_runtime_dependency 'json', '~> 2.6', '>= 2.6.3'
|
29
|
+
gem.add_runtime_dependency 'activesupport', '>= 5'
|
29
30
|
|
30
31
|
gem.add_development_dependency("rake", "~> 13.0.6")
|
31
32
|
gem.add_development_dependency("rspec", "~> 3.12.0")
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module LightServiceExt
|
2
|
+
RSpec.describe ApplicationAction do
|
3
|
+
FakeApplicationAction = Class.new(described_class) do
|
4
|
+
executed do |context|
|
5
|
+
value = context.dig(:input, :callback).call
|
6
|
+
context.add_params(value: value)
|
7
|
+
context.add_errors!(value: value)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:organizer_class) do
|
12
|
+
Class.new(ApplicationOrganizer) do
|
13
|
+
def self.steps
|
14
|
+
[FakeApplicationAction]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:value) { 'some-value' }
|
20
|
+
let(:callback) { -> { value } }
|
21
|
+
let(:input) { { callback: callback } }
|
22
|
+
let(:ctx) do
|
23
|
+
LightService::Testing::ContextFactory
|
24
|
+
.make_from(organizer_class)
|
25
|
+
.for(FakeApplicationAction)
|
26
|
+
.with(callback: callback)
|
27
|
+
end
|
28
|
+
|
29
|
+
subject(:context) do
|
30
|
+
FakeApplicationAction.execute(ctx)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'adds value returned by callback to params' do
|
34
|
+
expect(context.keys).to include(:input, :errors, :params)
|
35
|
+
|
36
|
+
expect(context[:params]).to eql({ value: value })
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|