servactory 1.5.2 → 1.6.1
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/README.md +6 -394
- data/config/locales/en.yml +5 -5
- data/lib/servactory/base.rb +4 -4
- data/lib/servactory/configuration/factory.rb +10 -6
- data/lib/servactory/configuration/setup.rb +10 -7
- data/lib/servactory/context/callable.rb +21 -22
- data/lib/servactory/context/workspace/inputs.rb +13 -0
- data/lib/servactory/context/workspace.rb +9 -7
- data/lib/servactory/errors/base.rb +2 -1
- data/lib/servactory/errors/collection.rb +25 -0
- data/lib/servactory/errors/failure.rb +11 -1
- data/lib/servactory/errors/input_error.rb +17 -0
- data/lib/servactory/errors/internal_error.rb +15 -0
- data/lib/servactory/errors/output_error.rb +15 -0
- data/lib/servactory/{input_arguments → inputs}/checks/base.rb +3 -3
- data/lib/servactory/{input_arguments → inputs}/checks/errors.rb +1 -1
- data/lib/servactory/{input_arguments → inputs}/checks/inclusion.rb +2 -2
- data/lib/servactory/{input_arguments → inputs}/checks/must.rb +3 -3
- data/lib/servactory/{input_arguments → inputs}/checks/required.rb +2 -2
- data/lib/servactory/{input_arguments → inputs}/checks/type.rb +3 -3
- data/lib/servactory/{input_arguments → inputs}/collection.rb +1 -1
- data/lib/servactory/{input_arguments → inputs}/define_input_conflict.rb +1 -1
- data/lib/servactory/{input_arguments → inputs}/define_input_method.rb +1 -1
- data/lib/servactory/inputs/dsl.rb +36 -0
- data/lib/servactory/{input_arguments/input_argument.rb → inputs/input.rb} +12 -12
- data/lib/servactory/{input_arguments → inputs}/option.rb +5 -3
- data/lib/servactory/{input_arguments → inputs}/options_collection.rb +1 -1
- data/lib/servactory/{input_arguments → inputs}/tools/check.rb +5 -5
- data/lib/servactory/{input_arguments → inputs}/tools/check_errors.rb +1 -1
- data/lib/servactory/{input_arguments → inputs}/tools/find_unnecessary.rb +6 -6
- data/lib/servactory/{input_arguments → inputs}/tools/prepare.rb +5 -5
- data/lib/servactory/inputs/tools/rules.rb +46 -0
- data/lib/servactory/{input_arguments → inputs}/workbench.rb +8 -8
- data/lib/servactory/internals/checks/base.rb +17 -0
- data/lib/servactory/{internal_arguments → internals}/checks/type.rb +8 -8
- data/lib/servactory/{output_arguments → internals}/collection.rb +1 -1
- data/lib/servactory/internals/dsl.rb +33 -0
- data/lib/servactory/{internal_arguments/internal_argument.rb → internals/internal.rb} +2 -2
- data/lib/servactory/internals/tools/prepare.rb +60 -0
- data/lib/servactory/{internal_arguments → internals}/workbench.rb +5 -5
- data/lib/servactory/{make_methods → methods}/collection.rb +1 -1
- data/lib/servactory/methods/dsl.rb +47 -0
- data/lib/servactory/{make_methods/make_method.rb → methods/method.rb} +2 -2
- data/lib/servactory/methods/shortcuts/collection.rb +17 -0
- data/lib/servactory/{make_methods → methods}/workbench.rb +6 -6
- data/lib/servactory/outputs/checks/base.rb +17 -0
- data/lib/servactory/{output_arguments → outputs}/checks/type.rb +8 -8
- data/lib/servactory/{internal_arguments → outputs}/collection.rb +1 -1
- data/lib/servactory/outputs/dsl.rb +33 -0
- data/lib/servactory/{output_arguments/output_argument.rb → outputs/output.rb} +2 -2
- data/lib/servactory/{output_arguments → outputs}/tools/conflicts.rb +7 -7
- data/lib/servactory/outputs/tools/prepare.rb +62 -0
- data/lib/servactory/outputs/workbench.rb +31 -0
- data/lib/servactory/result.rb +4 -4
- data/lib/servactory/utils.rb +2 -0
- data/lib/servactory/version.rb +2 -2
- metadata +60 -47
- data/lib/servactory/context/configuration.rb +0 -23
- data/lib/servactory/context/workspace/error.rb +0 -19
- data/lib/servactory/context/workspace/errors.rb +0 -33
- data/lib/servactory/errors/input_argument_error.rb +0 -7
- data/lib/servactory/errors/internal_argument_error.rb +0 -7
- data/lib/servactory/errors/output_argument_error.rb +0 -7
- data/lib/servactory/input_arguments/dsl.rb +0 -36
- data/lib/servactory/input_arguments/tools/rules.rb +0 -43
- data/lib/servactory/inputs.rb +0 -9
- data/lib/servactory/internal_arguments/checks/base.rb +0 -17
- data/lib/servactory/internal_arguments/dsl.rb +0 -33
- data/lib/servactory/internal_arguments/tools/prepare.rb +0 -60
- data/lib/servactory/make_methods/dsl.rb +0 -33
- data/lib/servactory/output_arguments/checks/base.rb +0 -17
- data/lib/servactory/output_arguments/dsl.rb +0 -33
- data/lib/servactory/output_arguments/tools/prepare.rb +0 -62
- data/lib/servactory/output_arguments/workbench.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77500bca8d6ee7ee302e77b8b64eb840a2e004bece8743a2b246e49a49a42b24
|
4
|
+
data.tar.gz: dfff784e9b2787ac349d5e33f84f75a318814ecf64ac0df7915a500b2073f6ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16091e0330a74cda1246f0a3a4ccdbc9ed572cba9c29d485e306c95c2405792e12bd9d03cbf13e1e17cf0c40bd4839ea997d75eac7f5f26a199eb8bc757af01a
|
7
|
+
data.tar.gz: 2d67bd5beff3c5a4d73a28a70662b3df52e61757fadc37f15751e745e28f9a3b18cd3af43d84684339debd58b6231ca70bdcbcc8b2af8c20ef76f9eb9e68c883
|
data/README.md
CHANGED
@@ -5,402 +5,14 @@ A set of tools for building reliable services of any complexity.
|
|
5
5
|
[](https://rubygems.org/gems/servactory)
|
6
6
|
[](https://github.com/afuno/servactory/releases)
|
7
7
|
|
8
|
-
##
|
8
|
+
## Documentation
|
9
9
|
|
10
|
-
|
11
|
-
- [Getting started](#getting-started)
|
12
|
-
- [Conventions](#conventions)
|
13
|
-
- [Installation](#installation)
|
14
|
-
- [Preparation](#preparation)
|
15
|
-
- [Usage](#usage)
|
16
|
-
- [Minimal example](#minimal-example)
|
17
|
-
- [Call](#call)
|
18
|
-
- [Result](#result)
|
19
|
-
- [Input attributes](#input-attributes)
|
20
|
-
- [Isolated usage](#isolated-usage)
|
21
|
-
- [As an internal argument](#isolated-usage)
|
22
|
-
- [Optional inputs](#optional-inputs)
|
23
|
-
- [As (internal name)](#as-internal-name)
|
24
|
-
- [An array of specific values](#an-array-of-specific-values)
|
25
|
-
- [Inclusion](#inclusion)
|
26
|
-
- [Must](#must)
|
27
|
-
- [Output attributes](#output-attributes)
|
28
|
-
- [Internal attributes](#internal-attributes)
|
29
|
-
- [Make](#make)
|
30
|
-
- [Failures](#failures)
|
31
|
-
- [I18n](#i18n)
|
32
|
-
- [Testing](#testing)
|
33
|
-
- [Thanks](#thanks)
|
34
|
-
- [Contributing](#contributing)
|
10
|
+
See [servactory.com](https://servactory.com) for documentation.
|
35
11
|
|
36
|
-
##
|
37
|
-
|
38
|
-
- Ruby >= 2.7
|
39
|
-
|
40
|
-
## Getting started
|
41
|
-
|
42
|
-
### Conventions
|
43
|
-
|
44
|
-
- Services are subclasses of `Servactory::Base` and are located in the `app/services` directory. It is common practice to create and inherit from `ApplicationService::Base`, which is a subclass of `Servactory::Base`.
|
45
|
-
- Name services by what they do, not by what they accept. Try to use verbs in names. For example, `UsersService::Create` instead of `UsersService::Creation`.
|
46
|
-
|
47
|
-
### Installation
|
48
|
-
|
49
|
-
Add this to `Gemfile`:
|
50
|
-
|
51
|
-
```ruby
|
52
|
-
gem "servactory"
|
53
|
-
```
|
54
|
-
|
55
|
-
And execute:
|
56
|
-
|
57
|
-
```shell
|
58
|
-
bundle install
|
59
|
-
```
|
60
|
-
|
61
|
-
### Preparation
|
62
|
-
|
63
|
-
As a first step, it is recommended to prepare the base class for further inheritance.
|
64
|
-
|
65
|
-
#### ApplicationService::Errors
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
# app/services/application_service/errors.rb
|
69
|
-
|
70
|
-
module ApplicationService
|
71
|
-
module Errors
|
72
|
-
class InputArgumentError < Servactory::Errors::InputArgumentError; end
|
73
|
-
class OutputArgumentError < Servactory::Errors::OutputArgumentError; end
|
74
|
-
class InternalArgumentError < Servactory::Errors::InternalArgumentError; end
|
75
|
-
|
76
|
-
class Failure < Servactory::Errors::Failure; end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
```
|
80
|
-
|
81
|
-
#### ApplicationService::Base
|
82
|
-
|
83
|
-
```ruby
|
84
|
-
# app/services/application_service/base.rb
|
85
|
-
|
86
|
-
module ApplicationService
|
87
|
-
class Base < Servactory::Base
|
88
|
-
configuration do
|
89
|
-
input_argument_error_class ApplicationService::Errors::InputArgumentError
|
90
|
-
output_argument_error_class ApplicationService::Errors::OutputArgumentError
|
91
|
-
internal_argument_error_class ApplicationService::Errors::InternalArgumentError
|
92
|
-
|
93
|
-
failure_class ApplicationService::Errors::Failure
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
```
|
98
|
-
|
99
|
-
## Usage
|
100
|
-
|
101
|
-
### Minimal example
|
102
|
-
|
103
|
-
```ruby
|
104
|
-
class MinimalService < ApplicationService::Base
|
105
|
-
make :call
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def call
|
110
|
-
# ...
|
111
|
-
end
|
112
|
-
end
|
113
|
-
```
|
114
|
-
|
115
|
-
[More examples](https://github.com/afuno/servactory/tree/main/examples/usual)
|
116
|
-
|
117
|
-
### Call
|
118
|
-
|
119
|
-
Services can only be called via `.call` and `.call!` methods.
|
120
|
-
|
121
|
-
The `.call` method will only fail if it catches an exception in the input arguments.
|
122
|
-
Internal and output attributes, as well as methods for failures - all this will be collected in the result.
|
123
|
-
|
124
|
-
The `.call!` method will fail if it catches any exception.
|
125
|
-
|
126
|
-
#### Via .call
|
127
|
-
|
128
|
-
```ruby
|
129
|
-
UsersService::Accept.call(user: User.first)
|
130
|
-
```
|
131
|
-
|
132
|
-
#### Via .call!
|
133
|
-
|
134
|
-
```ruby
|
135
|
-
UsersService::Accept.call!(user: User.first)
|
136
|
-
```
|
137
|
-
|
138
|
-
### Result
|
139
|
-
|
140
|
-
All services have the result of their work. For example, in case of success this call:
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
service_result = UsersService::Accept.call!(user: User.first)
|
144
|
-
```
|
145
|
-
|
146
|
-
Will return this:
|
147
|
-
|
148
|
-
```ruby
|
149
|
-
#<Servactory::Result:0x0000000107ad9e88 @user="...">
|
150
|
-
```
|
151
|
-
|
152
|
-
And then you can work with this result, for example, in this way:
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
Notification::SendJob.perform_later(service_result.user.id)
|
156
|
-
```
|
157
|
-
|
158
|
-
### Input attributes
|
159
|
-
|
160
|
-
#### Isolated usage
|
161
|
-
|
162
|
-
With this approach, all input attributes are available only from `inputs`. This is default behaviour.
|
163
|
-
|
164
|
-
```ruby
|
165
|
-
class UsersService::Accept < ApplicationService::Base
|
166
|
-
input :user, type: User
|
167
|
-
|
168
|
-
make :accept!
|
169
|
-
|
170
|
-
private
|
171
|
-
|
172
|
-
def accept!
|
173
|
-
inputs.user.accept!
|
174
|
-
end
|
175
|
-
end
|
176
|
-
```
|
177
|
-
|
178
|
-
#### As an internal argument
|
179
|
-
|
180
|
-
With this approach, all input attributes are available from `inputs` as well as directly from the context.
|
181
|
-
|
182
|
-
```ruby
|
183
|
-
class UsersService::Accept < ApplicationService::Base
|
184
|
-
input :user, type: User, internal: true
|
185
|
-
|
186
|
-
make :accept!
|
187
|
-
|
188
|
-
private
|
189
|
-
|
190
|
-
def accept!
|
191
|
-
user.accept!
|
192
|
-
end
|
193
|
-
end
|
194
|
-
```
|
195
|
-
|
196
|
-
#### Optional inputs
|
197
|
-
|
198
|
-
By default, all inputs are required. To make an input optional, specify `false` in the `required` option.
|
199
|
-
|
200
|
-
```ruby
|
201
|
-
class UsersService::Create < ApplicationService::Base
|
202
|
-
input :first_name, type: String
|
203
|
-
input :middle_name, type: String, required: false
|
204
|
-
input :last_name, type: String
|
205
|
-
|
206
|
-
# ...
|
207
|
-
end
|
208
|
-
```
|
209
|
-
|
210
|
-
#### As (internal name)
|
211
|
-
|
212
|
-
This option changes the name of the input within the service.
|
213
|
-
|
214
|
-
```ruby
|
215
|
-
class NotificationService::Create < ApplicationService::Base
|
216
|
-
input :customer, as: :user, type: User
|
217
|
-
|
218
|
-
output :notification, type: Notification
|
219
|
-
|
220
|
-
make :create_notification!
|
221
|
-
|
222
|
-
private
|
223
|
-
|
224
|
-
def create_notification!
|
225
|
-
self.notification = Notification.create!(user: inputs.user)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
```
|
229
|
-
|
230
|
-
#### An array of specific values
|
231
|
-
|
232
|
-
```ruby
|
233
|
-
class PymentsService::Send < ApplicationService::Base
|
234
|
-
input :invoice_numbers, type: String, array: true
|
235
|
-
|
236
|
-
# ...
|
237
|
-
end
|
238
|
-
```
|
239
|
-
|
240
|
-
#### Inclusion
|
241
|
-
|
242
|
-
```ruby
|
243
|
-
class EventService::Send < ApplicationService::Base
|
244
|
-
input :event_name, type: String, inclusion: %w[created rejected approved]
|
245
|
-
|
246
|
-
# ...
|
247
|
-
end
|
248
|
-
```
|
249
|
-
|
250
|
-
#### Must
|
251
|
-
|
252
|
-
Sometimes there are cases that require the implementation of a specific input attribute check. In such cases `must` can help.
|
253
|
-
|
254
|
-
```ruby
|
255
|
-
class PymentsService::Send < ApplicationService::Base
|
256
|
-
input :invoice_numbers,
|
257
|
-
type: String,
|
258
|
-
array: true,
|
259
|
-
must: {
|
260
|
-
be_6_characters: {
|
261
|
-
is: ->(value:) { value.all? { |id| id.size == 6 } }
|
262
|
-
}
|
263
|
-
}
|
264
|
-
|
265
|
-
# ...
|
266
|
-
end
|
267
|
-
```
|
268
|
-
|
269
|
-
### Output attributes
|
270
|
-
|
271
|
-
```ruby
|
272
|
-
class NotificationService::Create < ApplicationService::Base
|
273
|
-
input :user, type: User
|
274
|
-
|
275
|
-
output :notification, type: Notification
|
276
|
-
|
277
|
-
make :create_notification!
|
278
|
-
|
279
|
-
private
|
280
|
-
|
281
|
-
def create_notification!
|
282
|
-
self.notification = Notification.create!(user: inputs.user)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
```
|
286
|
-
|
287
|
-
### Internal attributes
|
288
|
-
|
289
|
-
```ruby
|
290
|
-
class NotificationService::Create < ApplicationService::Base
|
291
|
-
input :user, type: User
|
292
|
-
|
293
|
-
internal :inviter, type: User
|
294
|
-
|
295
|
-
output :notification, type: Notification
|
296
|
-
|
297
|
-
make :assign_inviter
|
298
|
-
make :create_notification!
|
299
|
-
|
300
|
-
private
|
301
|
-
|
302
|
-
def assign_inviter
|
303
|
-
self.inviter = user.inviter
|
304
|
-
end
|
305
|
-
|
306
|
-
def create_notification!
|
307
|
-
self.notification = Notification.create!(user: inputs.user, inviter:)
|
308
|
-
end
|
309
|
-
end
|
310
|
-
```
|
311
|
-
|
312
|
-
### Make
|
313
|
-
|
314
|
-
#### Minimal example
|
315
|
-
|
316
|
-
```ruby
|
317
|
-
make :something
|
318
|
-
|
319
|
-
def something
|
320
|
-
# ...
|
321
|
-
end
|
322
|
-
```
|
323
|
-
|
324
|
-
#### Condition
|
325
|
-
|
326
|
-
```ruby
|
327
|
-
make :something, if: -> { Settings.something.enabled }
|
328
|
-
|
329
|
-
def something
|
330
|
-
# ...
|
331
|
-
end
|
332
|
-
```
|
333
|
-
|
334
|
-
#### Several
|
335
|
-
|
336
|
-
```ruby
|
337
|
-
make :assign_api_model
|
338
|
-
make :perform_api_request
|
339
|
-
make :process_result
|
340
|
-
|
341
|
-
def assign_api_model
|
342
|
-
self.api_model = APIModel.new
|
343
|
-
end
|
344
|
-
|
345
|
-
def perform_api_request
|
346
|
-
self.response = APIClient.resource.create(api_model)
|
347
|
-
end
|
348
|
-
|
349
|
-
def process_result
|
350
|
-
ARModel.create!(response)
|
351
|
-
end
|
352
|
-
```
|
353
|
-
|
354
|
-
#### Inheritance
|
355
|
-
|
356
|
-
Service inheritance is also supported.
|
357
|
-
|
358
|
-
### Failures
|
359
|
-
|
360
|
-
The methods that are used in `make` may fail. In order to more informatively provide information about this outside the service, the following methods were prepared.
|
361
|
-
|
362
|
-
#### Fail
|
363
|
-
|
364
|
-
```ruby
|
365
|
-
make :check!
|
366
|
-
|
367
|
-
def check!
|
368
|
-
return if inputs.invoice_number.start_with?("AA")
|
369
|
-
|
370
|
-
fail!("Invalid invoice number")
|
371
|
-
end
|
372
|
-
```
|
373
|
-
|
374
|
-
#### Fail for input
|
375
|
-
|
376
|
-
```ruby
|
377
|
-
make :check!
|
378
|
-
|
379
|
-
def check!
|
380
|
-
return if inputs.invoice_number.start_with?("AA")
|
381
|
-
|
382
|
-
fail_input!(:invoice_number, "Invalid invoice number")
|
383
|
-
end
|
384
|
-
```
|
385
|
-
|
386
|
-
## I18n
|
387
|
-
|
388
|
-
All texts are stored in the localization file. All texts can be changed or supplemented by new locales.
|
389
|
-
|
390
|
-
[See en.yml file](https://github.com/afuno/servactory/tree/main/config/locales/en.yml)
|
391
|
-
|
392
|
-
## Testing
|
393
|
-
|
394
|
-
Testing Servactory services is the same as testing regular Ruby classes.
|
395
|
-
|
396
|
-
## Thanks
|
12
|
+
## Contributing
|
397
13
|
|
398
|
-
|
14
|
+
This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. We recommend reading the [contributing guide](./docs/pages/CONTRIBUTING.md) as well.
|
399
15
|
|
400
|
-
##
|
16
|
+
## License
|
401
17
|
|
402
|
-
|
403
|
-
2. Create your feature branch (`git checkout -b my-new-feature`);
|
404
|
-
3. Commit your changes (`git commit -am "Add some feature"`);
|
405
|
-
4. Push to the branch (`git push origin my-new-feature`);
|
406
|
-
5. Create a new Pull Request.
|
18
|
+
ViewComponent is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/config/locales/en.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
en:
|
2
2
|
servactory:
|
3
|
-
|
3
|
+
inputs:
|
4
4
|
checks:
|
5
5
|
inclusion:
|
6
6
|
default_error: "[%{service_class_name}] Wrong value in `%{input_name}`, must be one of `%{input_inclusion}`"
|
@@ -20,14 +20,14 @@ en:
|
|
20
20
|
error: "[%{service_class_name}] Unexpected attributes: `%{unnecessary_attributes}`"
|
21
21
|
rules:
|
22
22
|
error: "[%{service_class_name}] Conflict in `%{input_name}` input options: `%{conflict_code}`"
|
23
|
-
|
23
|
+
internals:
|
24
24
|
checks:
|
25
25
|
type:
|
26
|
-
default_error: "[%{service_class_name}] Wrong type of internal
|
27
|
-
|
26
|
+
default_error: "[%{service_class_name}] Wrong type of internal attribute `%{internal_name}`, expected `%{expected_type}`, got `%{given_type}`"
|
27
|
+
outputs:
|
28
28
|
checks:
|
29
29
|
type:
|
30
|
-
default_error: "[%{service_class_name}] Wrong type of output
|
30
|
+
default_error: "[%{service_class_name}] Wrong type of output attribute `%{output_name}`, expected `%{expected_type}`, got `%{given_type}`"
|
31
31
|
tools:
|
32
32
|
conflicts:
|
33
33
|
error: "[%{service_class_name}] Conflict between internal and output attributes `%{overlapping_attributes}`"
|
data/lib/servactory/base.rb
CHANGED
@@ -4,10 +4,10 @@ module Servactory
|
|
4
4
|
class Base
|
5
5
|
include Configuration::DSL
|
6
6
|
include Context::DSL
|
7
|
-
include
|
8
|
-
include
|
9
|
-
include
|
10
|
-
include
|
7
|
+
include Inputs::DSL
|
8
|
+
include Internals::DSL
|
9
|
+
include Outputs::DSL
|
10
|
+
include Methods::DSL
|
11
11
|
|
12
12
|
private_class_method :new
|
13
13
|
end
|
@@ -3,21 +3,25 @@
|
|
3
3
|
module Servactory
|
4
4
|
module Configuration
|
5
5
|
class Factory
|
6
|
-
def
|
7
|
-
Servactory.configuration.
|
6
|
+
def input_error_class(input_error_class)
|
7
|
+
Servactory.configuration.input_error_class = input_error_class
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
Servactory.configuration.
|
10
|
+
def output_error_class(output_error_class)
|
11
|
+
Servactory.configuration.output_error_class = output_error_class
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
Servactory.configuration.
|
14
|
+
def internal_error_class(internal_error_class)
|
15
|
+
Servactory.configuration.internal_error_class = internal_error_class
|
16
16
|
end
|
17
17
|
|
18
18
|
def failure_class(failure_class)
|
19
19
|
Servactory.configuration.failure_class = failure_class
|
20
20
|
end
|
21
|
+
|
22
|
+
def method_shortcuts(method_shortcuts)
|
23
|
+
Servactory.configuration.method_shortcuts.merge(method_shortcuts)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
@@ -3,17 +3,20 @@
|
|
3
3
|
module Servactory
|
4
4
|
module Configuration
|
5
5
|
class Setup
|
6
|
-
attr_accessor :
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:failure_class
|
6
|
+
attr_accessor :input_error_class,
|
7
|
+
:internal_error_class,
|
8
|
+
:output_error_class,
|
9
|
+
:failure_class,
|
10
|
+
:method_shortcuts
|
10
11
|
|
11
12
|
def initialize
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
13
|
+
@input_error_class = Servactory::Errors::InputError
|
14
|
+
@internal_error_class = Servactory::Errors::InternalError
|
15
|
+
@output_error_class = Servactory::Errors::OutputError
|
15
16
|
|
16
17
|
@failure_class = Servactory::Errors::Failure
|
18
|
+
|
19
|
+
@method_shortcuts = Servactory::Methods::Shortcuts::Collection.new
|
17
20
|
end
|
18
21
|
end
|
19
22
|
end
|
@@ -8,23 +8,23 @@ module Servactory
|
|
8
8
|
|
9
9
|
assign_data_with(arguments)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
inputs_workbench.find_unnecessary!
|
12
|
+
inputs_workbench.check_rules!
|
13
|
+
outputs_workbench.find_conflicts_in!(
|
14
|
+
collection_of_internals: collection_of_internals
|
15
15
|
)
|
16
16
|
|
17
17
|
prepare_data
|
18
18
|
|
19
|
-
|
19
|
+
inputs_workbench.check!
|
20
20
|
|
21
|
-
|
21
|
+
methods_workbench.run!
|
22
22
|
|
23
23
|
context_store.context.raise_first_fail
|
24
24
|
|
25
25
|
Servactory::Result.prepare_for(
|
26
26
|
context: context_store.context,
|
27
|
-
|
27
|
+
collection_of_outputs: collection_of_outputs
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
@@ -33,21 +33,21 @@ module Servactory
|
|
33
33
|
|
34
34
|
assign_data_with(arguments)
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
inputs_workbench.find_unnecessary!
|
37
|
+
inputs_workbench.check_rules!
|
38
|
+
outputs_workbench.find_conflicts_in!(
|
39
|
+
collection_of_internals: collection_of_internals
|
40
40
|
)
|
41
41
|
|
42
42
|
prepare_data
|
43
43
|
|
44
|
-
|
44
|
+
inputs_workbench.check!
|
45
45
|
|
46
|
-
|
46
|
+
methods_workbench.run!
|
47
47
|
|
48
48
|
Servactory::Result.prepare_for(
|
49
49
|
context: context_store.context,
|
50
|
-
|
50
|
+
collection_of_outputs: collection_of_outputs
|
51
51
|
)
|
52
52
|
end
|
53
53
|
|
@@ -56,21 +56,20 @@ module Servactory
|
|
56
56
|
attr_reader :context_store
|
57
57
|
|
58
58
|
def assign_data_with(arguments)
|
59
|
-
|
59
|
+
inputs_workbench.assign(
|
60
60
|
context: context_store.context,
|
61
61
|
arguments: arguments
|
62
62
|
)
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
internals_workbench.assign(context: context_store.context)
|
65
|
+
outputs_workbench.assign(context: context_store.context)
|
66
|
+
methods_workbench.assign(context: context_store.context)
|
67
67
|
end
|
68
68
|
|
69
69
|
def prepare_data
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
internal_arguments_workbench.prepare # 3
|
70
|
+
inputs_workbench.prepare # 1
|
71
|
+
outputs_workbench.prepare # 2
|
72
|
+
internals_workbench.prepare # 3
|
74
73
|
end
|
75
74
|
end
|
76
75
|
end
|
@@ -6,26 +6,28 @@ module Servactory
|
|
6
6
|
attr_reader :inputs
|
7
7
|
|
8
8
|
def errors
|
9
|
-
@errors ||= Errors.new
|
9
|
+
@errors ||= Servactory::Errors::Collection.new
|
10
10
|
end
|
11
11
|
|
12
12
|
def assign_inputs(inputs)
|
13
13
|
@inputs = inputs
|
14
14
|
end
|
15
15
|
|
16
|
-
def fail_input!(
|
17
|
-
raise Servactory.configuration.
|
18
|
-
|
16
|
+
def fail_input!(input_name, message:)
|
17
|
+
raise Servactory.configuration.input_error_class.new(
|
18
|
+
input_name: input_name,
|
19
|
+
message: message
|
20
|
+
)
|
19
21
|
end
|
20
22
|
|
21
|
-
def fail!(
|
22
|
-
errors <<
|
23
|
+
def fail!(message:, meta: nil)
|
24
|
+
errors << Servactory.configuration.failure_class.new(message: message, meta: meta)
|
23
25
|
end
|
24
26
|
|
25
27
|
def raise_first_fail
|
26
28
|
return if (tmp_errors = errors.for_fails.not_blank).empty?
|
27
29
|
|
28
|
-
raise
|
30
|
+
raise tmp_errors.first
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Errors
|
5
|
+
class Collection
|
6
|
+
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :@collection, :<<, :to_a, :filter, :reject, :empty?, :first
|
9
|
+
|
10
|
+
def initialize(collection = Set.new)
|
11
|
+
@collection = collection
|
12
|
+
end
|
13
|
+
|
14
|
+
def not_blank
|
15
|
+
Collection.new(reject(&:blank?))
|
16
|
+
end
|
17
|
+
|
18
|
+
def for_fails
|
19
|
+
filtered = filter { |error| error.is_a?(Failure) }
|
20
|
+
|
21
|
+
Collection.new(filtered)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|