servactory 1.4.2 → 1.4.4
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 +123 -3
- data/lib/servactory/base.rb +3 -0
- data/lib/servactory/configuration/dsl.rb +21 -0
- data/lib/servactory/configuration/factory.rb +23 -0
- data/lib/servactory/configuration/setup.rb +20 -0
- data/lib/servactory/context/callable.rb +55 -0
- data/lib/servactory/context/dsl.rb +2 -55
- data/lib/servactory/context/store.rb +1 -39
- data/lib/servactory/context/workspace/error.rb +19 -0
- data/lib/servactory/context/workspace/errors.rb +33 -0
- data/lib/servactory/context/workspace.rb +32 -0
- data/lib/servactory/input_arguments/checks/base.rb +7 -7
- data/lib/servactory/input_arguments/checks/errors.rb +17 -0
- data/lib/servactory/input_arguments/collection.rb +1 -1
- data/lib/servactory/input_arguments/input_argument.rb +13 -3
- data/lib/servactory/input_arguments/options_collection.rb +4 -4
- data/lib/servactory/input_arguments/tools/check.rb +6 -4
- data/lib/servactory/input_arguments/tools/check_errors.rb +21 -0
- data/lib/servactory/input_arguments/tools/prepare.rb +7 -5
- data/lib/servactory/internal_arguments/collection.rb +1 -1
- data/lib/servactory/internal_arguments/tools/prepare.rb +12 -12
- data/lib/servactory/output_arguments/collection.rb +1 -1
- data/lib/servactory/output_arguments/tools/prepare.rb +13 -13
- data/lib/servactory/stage/methods.rb +1 -1
- data/lib/servactory/version.rb +1 -1
- data/lib/servactory.rb +2 -2
- metadata +11 -3
- data/lib/servactory/configuration.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54a713971d52bebd38a97f473eb942be19f5c4029604aa26f0729cb1dc40f24a
|
4
|
+
data.tar.gz: 1b368e874cdf3c502328fe3dbf71758a3c0821140c1b0e9a595f6622b41ec1bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2e412f4e06a1a21aa70a43a0f898f6d5fc0adcca1eaf7922edb80aa719313b9c2325d83ef41e34eda9c8cacc988e60b076938e23b1ff1e709d50aee9ce0f0b1
|
7
|
+
data.tar.gz: d871cef64e8249b89572f6b97e9fdd9410632d20a393ea77d59f36481acc7f0207bfa26e6c79749a2031962927b965955986f257ce298d554d8289f2f85bfaf4
|
data/README.md
CHANGED
@@ -23,7 +23,12 @@ A set of tools for building reliable services of any complexity.
|
|
23
23
|
- [Must](#must)
|
24
24
|
- [Output attributes](#output-attributes)
|
25
25
|
- [Internal attributes](#internal-attributes)
|
26
|
+
- [Stage](#stage)
|
27
|
+
- [Failures](#failures)
|
26
28
|
- [Result](#result)
|
29
|
+
- [Testing](#testing)
|
30
|
+
- [Thanks](#thanks)
|
31
|
+
- [Contributing](#contributing)
|
27
32
|
|
28
33
|
## Requirements
|
29
34
|
|
@@ -52,7 +57,7 @@ bundle install
|
|
52
57
|
|
53
58
|
### Preparation
|
54
59
|
|
55
|
-
|
60
|
+
As a first step, it is recommended to prepare the base class for further inheritance.
|
56
61
|
|
57
62
|
#### ApplicationService::Errors
|
58
63
|
|
@@ -150,14 +155,34 @@ By default, all inputs are required. To make an input optional, specify `false`
|
|
150
155
|
|
151
156
|
```ruby
|
152
157
|
class UsersService::Create < ApplicationService::Base
|
153
|
-
input :first_name, type: String
|
158
|
+
input :first_name, type: String
|
154
159
|
input :middle_name, type: String, required: false
|
155
|
-
input :last_name, type: String
|
160
|
+
input :last_name, type: String
|
156
161
|
|
157
162
|
# ...
|
158
163
|
end
|
159
164
|
```
|
160
165
|
|
166
|
+
#### As
|
167
|
+
|
168
|
+
This option changes the name of the input within the service.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
class NotificationService::Create < ApplicationService::Base
|
172
|
+
input :customer, as: :user, type: User
|
173
|
+
|
174
|
+
output :notification, type: Notification
|
175
|
+
|
176
|
+
stage { make :create_notification! }
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
def create_notification!
|
181
|
+
self.notification = Notification.create!(user: inputs.user)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
161
186
|
#### An array of specific values
|
162
187
|
|
163
188
|
```ruby
|
@@ -242,6 +267,85 @@ class NotificationService::Create < ApplicationService::Base
|
|
242
267
|
end
|
243
268
|
```
|
244
269
|
|
270
|
+
### Stage
|
271
|
+
|
272
|
+
A "stage" is a single action or group of actions that needs to be "make".
|
273
|
+
|
274
|
+
#### Minimal example
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
stage { make :something }
|
278
|
+
|
279
|
+
def something
|
280
|
+
# ...
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
#### Condition
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
stage { make :something, if: -> { Settings.something.enabled } }
|
288
|
+
|
289
|
+
def something
|
290
|
+
# ...
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
#### Groups
|
295
|
+
|
296
|
+
The functionality of stage groups will be expanded in future releases.
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
stage do
|
300
|
+
make :assign_api_model
|
301
|
+
make :perform_api_request
|
302
|
+
end
|
303
|
+
|
304
|
+
stage do
|
305
|
+
make :process_result
|
306
|
+
end
|
307
|
+
|
308
|
+
def assign_api_model
|
309
|
+
self.api_model = APIModel.new
|
310
|
+
end
|
311
|
+
|
312
|
+
def perform_api_request
|
313
|
+
self.response = APIClient.resource.create(api_model)
|
314
|
+
end
|
315
|
+
|
316
|
+
def process_result
|
317
|
+
ARModel.create!(response)
|
318
|
+
end
|
319
|
+
```
|
320
|
+
|
321
|
+
### Failures
|
322
|
+
|
323
|
+
The methods that are used in the stages may fail. In order to more informatively provide information about this outside the service, the following methods were prepared.
|
324
|
+
|
325
|
+
#### Fail
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
stage { make :check! }
|
329
|
+
|
330
|
+
def check!
|
331
|
+
return if inputs.invoice_number.start_with?("AA")
|
332
|
+
|
333
|
+
fail!("Invalid invoice number")
|
334
|
+
end
|
335
|
+
```
|
336
|
+
|
337
|
+
#### Fail for input
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
stage { make :check! }
|
341
|
+
|
342
|
+
def check!
|
343
|
+
return if inputs.invoice_number.start_with?("AA")
|
344
|
+
|
345
|
+
fail_input!(:invoice_number, "Invalid invoice number")
|
346
|
+
end
|
347
|
+
```
|
348
|
+
|
245
349
|
### Result
|
246
350
|
|
247
351
|
All services have the result of their work. For example, in case of success this call:
|
@@ -261,3 +365,19 @@ And then you can work with this result, for example, in this way:
|
|
261
365
|
```ruby
|
262
366
|
Notification::SendJob.perform_later(service_result.notification.id)
|
263
367
|
```
|
368
|
+
|
369
|
+
## Testing
|
370
|
+
|
371
|
+
Testing Servactory services is the same as testing regular Ruby classes.
|
372
|
+
|
373
|
+
## Thanks
|
374
|
+
|
375
|
+
Thanks to [@sunny](https://github.com/sunny) for [Service Actor](https://github.com/sunny/actor).
|
376
|
+
|
377
|
+
## Contributing
|
378
|
+
|
379
|
+
1. Fork it (https://github.com/afuno/servactory/fork);
|
380
|
+
2. Create your feature branch (`git checkout -b my-new-feature`);
|
381
|
+
3. Commit your changes (`git commit -am "Add some feature"`);
|
382
|
+
4. Push to the branch (`git push origin my-new-feature`);
|
383
|
+
5. Create a new Pull Request.
|
data/lib/servactory/base.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Configuration
|
5
|
+
module DSL
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
private
|
12
|
+
|
13
|
+
def configuration(&block)
|
14
|
+
@configuration_factory ||= Factory.new
|
15
|
+
|
16
|
+
@configuration_factory.instance_eval(&block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Configuration
|
5
|
+
class Factory
|
6
|
+
def input_argument_error_class(input_argument_error_class)
|
7
|
+
Servactory.configuration.input_argument_error_class = input_argument_error_class
|
8
|
+
end
|
9
|
+
|
10
|
+
def output_argument_error_class(output_argument_error_class)
|
11
|
+
Servactory.configuration.output_argument_error_class = output_argument_error_class
|
12
|
+
end
|
13
|
+
|
14
|
+
def internal_argument_error_class(internal_argument_error_class)
|
15
|
+
Servactory.configuration.internal_argument_error_class = internal_argument_error_class
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_class(failure_class)
|
19
|
+
Servactory.configuration.failure_class = failure_class
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Configuration
|
5
|
+
class Setup
|
6
|
+
attr_accessor :input_argument_error_class,
|
7
|
+
:internal_argument_error_class,
|
8
|
+
:output_argument_error_class,
|
9
|
+
:failure_class
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@input_argument_error_class = Servactory::Errors::InputArgumentError
|
13
|
+
@internal_argument_error_class = Servactory::Errors::InternalArgumentError
|
14
|
+
@output_argument_error_class = Servactory::Errors::OutputArgumentError
|
15
|
+
|
16
|
+
@failure_class = Servactory::Errors::Failure
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Context
|
5
|
+
module Callable
|
6
|
+
def call!(arguments = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
7
|
+
@context_store = Store.new(self)
|
8
|
+
|
9
|
+
assign_data_with(arguments)
|
10
|
+
|
11
|
+
input_arguments_workbench.find_unnecessary!
|
12
|
+
input_arguments_workbench.check_rules!
|
13
|
+
output_arguments_workbench.find_conflicts_in!(
|
14
|
+
collection_of_internal_arguments: collection_of_internal_arguments
|
15
|
+
)
|
16
|
+
|
17
|
+
prepare_data
|
18
|
+
|
19
|
+
input_arguments_workbench.check!
|
20
|
+
|
21
|
+
stage_handyman.run_methods!
|
22
|
+
|
23
|
+
context_store.context.raise_first_fail
|
24
|
+
|
25
|
+
Servactory::Result.prepare_for(
|
26
|
+
context: context_store.context,
|
27
|
+
collection_of_output_arguments: collection_of_output_arguments
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :context_store
|
34
|
+
|
35
|
+
def assign_data_with(arguments) # rubocop:disable Metrics/AbcSize
|
36
|
+
input_arguments_workbench.assign(
|
37
|
+
context: context_store.context,
|
38
|
+
arguments: arguments,
|
39
|
+
collection_of_input_options: collection_of_input_options
|
40
|
+
)
|
41
|
+
|
42
|
+
internal_arguments_workbench.assign(context: context_store.context)
|
43
|
+
output_arguments_workbench.assign(context: context_store.context)
|
44
|
+
stage_handyman&.assign(context: context_store.context)
|
45
|
+
end
|
46
|
+
|
47
|
+
def prepare_data
|
48
|
+
input_arguments_workbench.prepare # 1
|
49
|
+
|
50
|
+
output_arguments_workbench.prepare # 2
|
51
|
+
internal_arguments_workbench.prepare # 3
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -4,61 +4,8 @@ module Servactory
|
|
4
4
|
module Context
|
5
5
|
module DSL
|
6
6
|
def self.included(base)
|
7
|
-
base.extend(
|
8
|
-
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def call!(arguments = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
12
|
-
@context_store ||= Store.new(self)
|
13
|
-
|
14
|
-
assign_data_with(arguments)
|
15
|
-
|
16
|
-
input_arguments_workbench.find_unnecessary!
|
17
|
-
input_arguments_workbench.check_rules!
|
18
|
-
output_arguments_workbench.find_conflicts_in!(
|
19
|
-
collection_of_internal_arguments: collection_of_internal_arguments
|
20
|
-
)
|
21
|
-
|
22
|
-
prepare_data
|
23
|
-
|
24
|
-
input_arguments_workbench.check!
|
25
|
-
|
26
|
-
stage_handyman.run_methods!
|
27
|
-
|
28
|
-
Servactory::Result.prepare_for(
|
29
|
-
context: context_store.context,
|
30
|
-
collection_of_output_arguments: collection_of_output_arguments
|
31
|
-
)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_reader :context_store
|
37
|
-
|
38
|
-
def assign_data_with(arguments) # rubocop:disable Metrics/AbcSize
|
39
|
-
input_arguments_workbench.assign(
|
40
|
-
context: context_store.context,
|
41
|
-
arguments: arguments,
|
42
|
-
collection_of_input_options: collection_of_input_options
|
43
|
-
)
|
44
|
-
|
45
|
-
internal_arguments_workbench.assign(context: context_store.context)
|
46
|
-
output_arguments_workbench.assign(context: context_store.context)
|
47
|
-
stage_handyman&.assign(context: context_store.context)
|
48
|
-
end
|
49
|
-
|
50
|
-
def prepare_data
|
51
|
-
input_arguments_workbench.prepare # 1
|
52
|
-
|
53
|
-
output_arguments_workbench.prepare # 2
|
54
|
-
internal_arguments_workbench.prepare # 3
|
55
|
-
end
|
56
|
-
|
57
|
-
def configuration(&block)
|
58
|
-
context_configuration = Servactory::Context::Configuration.new
|
59
|
-
|
60
|
-
context_configuration.instance_eval(&block)
|
61
|
-
end
|
7
|
+
base.extend(Callable)
|
8
|
+
base.prepend(Workspace)
|
62
9
|
end
|
63
10
|
end
|
64
11
|
end
|
@@ -6,45 +6,7 @@ module Servactory
|
|
6
6
|
attr_reader :context
|
7
7
|
|
8
8
|
def initialize(service_class)
|
9
|
-
@context = service_class.new
|
10
|
-
|
11
|
-
service_class.class_eval(service_class_template_with(context))
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
# EXAMPLE:
|
17
|
-
#
|
18
|
-
# attr_reader(:inputs)
|
19
|
-
#
|
20
|
-
# def assign_inputs(inputs)
|
21
|
-
# @inputs = inputs
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# def fail_input!(input_attribute_name, message, prefix: true)
|
25
|
-
# message_text = prefix ? "[#{context.class.name}] Custom `\#{input_attribute_name}` input error: " : ""
|
26
|
-
#
|
27
|
-
# message_text += message
|
28
|
-
#
|
29
|
-
# raise Servactory.configuration.input_argument_error_class, message_text
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
def service_class_template_with(context)
|
33
|
-
<<-RUBY
|
34
|
-
attr_reader(:inputs)
|
35
|
-
|
36
|
-
def assign_inputs(inputs)
|
37
|
-
@inputs = inputs
|
38
|
-
end
|
39
|
-
|
40
|
-
def fail_input!(input_attribute_name, message, prefix: true)
|
41
|
-
message_text = prefix ? "[#{context.class.name}] Custom `\#{input_attribute_name}` input error: " : ""
|
42
|
-
|
43
|
-
message_text += message
|
44
|
-
|
45
|
-
raise Servactory.configuration.input_argument_error_class, message_text
|
46
|
-
end
|
47
|
-
RUBY
|
9
|
+
@context = service_class.send(:new)
|
48
10
|
end
|
49
11
|
end
|
50
12
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Context
|
5
|
+
module Workspace
|
6
|
+
class Error
|
7
|
+
attr_reader :type,
|
8
|
+
:message,
|
9
|
+
:attribute_name
|
10
|
+
|
11
|
+
def initialize(type:, message:, attribute_name: nil)
|
12
|
+
@type = type
|
13
|
+
@message = message
|
14
|
+
@attribute_name = attribute_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Context
|
5
|
+
module Workspace
|
6
|
+
class Errors
|
7
|
+
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :@collection, :<<, :filter, :reject, :empty?, :first
|
10
|
+
|
11
|
+
def initialize(collection = Set.new)
|
12
|
+
@collection = collection
|
13
|
+
end
|
14
|
+
|
15
|
+
def not_blank
|
16
|
+
Errors.new(reject(&:blank?))
|
17
|
+
end
|
18
|
+
|
19
|
+
def for_fails
|
20
|
+
filtered = filter { |error| error.type == :fail }
|
21
|
+
|
22
|
+
Errors.new(filtered)
|
23
|
+
end
|
24
|
+
|
25
|
+
def for_inputs
|
26
|
+
filtered = filter { |error| error.type == :inputs }
|
27
|
+
|
28
|
+
Errors.new(filtered)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module Context
|
5
|
+
module Workspace
|
6
|
+
attr_reader :inputs
|
7
|
+
|
8
|
+
def errors
|
9
|
+
@errors ||= Errors.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def assign_inputs(inputs)
|
13
|
+
@inputs = inputs
|
14
|
+
end
|
15
|
+
|
16
|
+
def fail_input!(input_attribute_name, message)
|
17
|
+
raise Servactory.configuration.input_argument_error_class,
|
18
|
+
Error.new(type: :input, attribute_name: input_attribute_name, message: message).message
|
19
|
+
end
|
20
|
+
|
21
|
+
def fail!(error)
|
22
|
+
errors << Error.new(type: :fail, message: error)
|
23
|
+
end
|
24
|
+
|
25
|
+
def raise_first_fail
|
26
|
+
return if (tmp_errors = errors.for_fails.not_blank).empty?
|
27
|
+
|
28
|
+
raise Servactory.configuration.failure_class, tmp_errors.first.message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -4,18 +4,18 @@ module Servactory
|
|
4
4
|
module InputArguments
|
5
5
|
module Checks
|
6
6
|
class Base
|
7
|
-
def initialize
|
8
|
-
@errors = []
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :errors
|
12
|
-
|
13
7
|
protected
|
14
8
|
|
15
9
|
def add_error(message, **arguments)
|
16
10
|
message = message.call(**arguments) if message.is_a?(Proc)
|
17
11
|
|
18
|
-
errors.
|
12
|
+
errors.add(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def errors
|
18
|
+
@errors ||= Errors.new
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module InputArguments
|
5
|
+
module Checks
|
6
|
+
class Errors
|
7
|
+
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :@collection, :add, :to_a
|
10
|
+
|
11
|
+
def initialize(*)
|
12
|
+
@collection = Set.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -6,10 +6,19 @@ module Servactory
|
|
6
6
|
ARRAY_DEFAULT_VALUE = ->(is: false, message: nil) { { is: is, message: message } }
|
7
7
|
|
8
8
|
attr_reader :name,
|
9
|
+
:internal_name,
|
9
10
|
:collection_of_options
|
10
11
|
|
11
|
-
|
12
|
+
# rubocop:disable Style/KeywordParametersOrder
|
13
|
+
def initialize(
|
14
|
+
name,
|
15
|
+
as: nil,
|
16
|
+
collection_of_options:,
|
17
|
+
type:,
|
18
|
+
**options
|
19
|
+
)
|
12
20
|
@name = name
|
21
|
+
@internal_name = as.present? ? as : name
|
13
22
|
@collection_of_options = collection_of_options
|
14
23
|
|
15
24
|
add_basic_options_with(type: type, options: options)
|
@@ -20,6 +29,7 @@ module Servactory
|
|
20
29
|
instance_variable_set(:"@#{option.name}", option.value)
|
21
30
|
end
|
22
31
|
end
|
32
|
+
# rubocop:enable Style/KeywordParametersOrder
|
23
33
|
|
24
34
|
def add_basic_options_with(type:, options:)
|
25
35
|
# Check Class: Servactory::InputArguments::Checks::Required
|
@@ -72,8 +82,8 @@ module Servactory
|
|
72
82
|
collection_of_options << Option.new(
|
73
83
|
name: :types,
|
74
84
|
input: self,
|
75
|
-
original_value: Array(type),
|
76
85
|
check_class: Servactory::InputArguments::Checks::Type,
|
86
|
+
original_value: Array(type),
|
77
87
|
need_for_checks: true,
|
78
88
|
value_fallback: nil,
|
79
89
|
with_advanced_mode: false
|
@@ -167,6 +177,7 @@ module Servactory
|
|
167
177
|
collection_of_options << Option.new(
|
168
178
|
name: :internal,
|
169
179
|
input: self,
|
180
|
+
check_class: nil,
|
170
181
|
define_input_methods: lambda do
|
171
182
|
<<-RUBY
|
172
183
|
def internal?
|
@@ -175,7 +186,6 @@ module Servactory
|
|
175
186
|
RUBY
|
176
187
|
end,
|
177
188
|
need_for_checks: false,
|
178
|
-
check_class: nil,
|
179
189
|
value_key: :is,
|
180
190
|
value_fallback: false,
|
181
191
|
**options
|
@@ -5,18 +5,18 @@ module Servactory
|
|
5
5
|
class OptionsCollection
|
6
6
|
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
7
7
|
extend Forwardable
|
8
|
-
def_delegators :@collection, :<<, :
|
8
|
+
def_delegators :@collection, :<<, :filter, :each, :map
|
9
9
|
|
10
10
|
def initialize(*)
|
11
|
-
@collection =
|
11
|
+
@collection = Set.new
|
12
12
|
end
|
13
13
|
|
14
14
|
def check_classes
|
15
|
-
|
15
|
+
filter { |option| option.check_class.present? }.map(&:check_class).uniq
|
16
16
|
end
|
17
17
|
|
18
18
|
def options_for_checks
|
19
|
-
|
19
|
+
filter(&:need_for_checks?).to_h do |option|
|
20
20
|
value = if option.value.is_a?(Hash)
|
21
21
|
option.value.key?(:is) ? option.value.fetch(:is) : option.value
|
22
22
|
else
|
@@ -13,8 +13,6 @@ module Servactory
|
|
13
13
|
@incoming_arguments = incoming_arguments
|
14
14
|
@collection_of_input_arguments = collection_of_input_arguments
|
15
15
|
@collection_of_input_options = collection_of_input_options
|
16
|
-
|
17
|
-
@errors = []
|
18
16
|
end
|
19
17
|
|
20
18
|
def check!
|
@@ -42,7 +40,7 @@ module Servactory
|
|
42
40
|
check_options: check_options
|
43
41
|
)
|
44
42
|
|
45
|
-
|
43
|
+
errors.merge(errors_from_checks.to_a)
|
46
44
|
end
|
47
45
|
end
|
48
46
|
|
@@ -64,8 +62,12 @@ module Servactory
|
|
64
62
|
|
65
63
|
########################################################################
|
66
64
|
|
65
|
+
def errors
|
66
|
+
@errors ||= CheckErrors.new
|
67
|
+
end
|
68
|
+
|
67
69
|
def raise_errors
|
68
|
-
return if (tmp_errors =
|
70
|
+
return if (tmp_errors = errors.not_blank).empty?
|
69
71
|
|
70
72
|
raise Servactory.configuration.input_argument_error_class, tmp_errors.first
|
71
73
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module InputArguments
|
5
|
+
module Tools
|
6
|
+
class CheckErrors
|
7
|
+
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :@collection, :merge, :reject, :first, :empty?
|
10
|
+
|
11
|
+
def initialize(collection = Set.new)
|
12
|
+
@collection = collection
|
13
|
+
end
|
14
|
+
|
15
|
+
def not_blank
|
16
|
+
CheckErrors.new(reject(&:blank?))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -31,7 +31,7 @@ module Servactory
|
|
31
31
|
input_value = @incoming_arguments.fetch(input.name, nil)
|
32
32
|
input_value = input.default if input.optional? && input_value.blank?
|
33
33
|
|
34
|
-
@inputs_variables[input.
|
34
|
+
@inputs_variables[input.internal_name] = input_value
|
35
35
|
|
36
36
|
return unless input.internal?
|
37
37
|
|
@@ -75,15 +75,17 @@ module Servactory
|
|
75
75
|
|
76
76
|
# EXAMPLE:
|
77
77
|
#
|
78
|
-
# private
|
78
|
+
# private
|
79
|
+
#
|
80
|
+
# attr_reader(*[:attr_1])
|
79
81
|
#
|
80
82
|
def context_internal_variables_template
|
81
83
|
return if @internal_variables.blank?
|
82
84
|
|
83
|
-
@context_internal_variables_template ||= <<-RUBY
|
84
|
-
private
|
85
|
+
@context_internal_variables_template ||= <<-RUBY
|
86
|
+
private
|
85
87
|
|
86
|
-
attr_reader(*#{@internal_variables.keys})
|
88
|
+
attr_reader(*#{@internal_variables.keys})
|
87
89
|
RUBY
|
88
90
|
end
|
89
91
|
end
|
@@ -29,29 +29,29 @@ module Servactory
|
|
29
29
|
|
30
30
|
# EXAMPLE:
|
31
31
|
#
|
32
|
-
# define_method(:user=) do |value
|
33
|
-
# Servactory::InternalArguments::Checks::Type.check!( context: self, internal_argument:, value: )
|
32
|
+
# define_method(:user=) do |value|
|
33
|
+
# Servactory::InternalArguments::Checks::Type.check!( context: self, internal_argument:, value: )
|
34
34
|
#
|
35
|
-
# instance_variable_set(:@user, value)
|
36
|
-
# end
|
35
|
+
# instance_variable_set(:@user, value)
|
36
|
+
# end
|
37
37
|
#
|
38
|
-
# private attr_reader :user
|
38
|
+
# private attr_reader :user
|
39
39
|
#
|
40
40
|
def context_internal_argument_template_for(internal_argument)
|
41
|
-
<<-RUBY
|
42
|
-
define_method(:#{internal_argument.name}=) do |value
|
41
|
+
<<-RUBY
|
42
|
+
define_method(:#{internal_argument.name}=) do |value|
|
43
43
|
Servactory::InternalArguments::Checks::Type.check!(
|
44
44
|
context: self,
|
45
45
|
internal_argument: internal_argument,
|
46
46
|
value: value
|
47
|
-
)
|
47
|
+
)
|
48
48
|
|
49
|
-
instance_variable_set(:@#{internal_argument.name}, value)
|
50
|
-
end
|
49
|
+
instance_variable_set(:@#{internal_argument.name}, value)
|
50
|
+
end
|
51
51
|
|
52
|
-
private
|
52
|
+
private
|
53
53
|
|
54
|
-
attr_reader :#{internal_argument.name}
|
54
|
+
attr_reader :#{internal_argument.name}
|
55
55
|
RUBY
|
56
56
|
end
|
57
57
|
end
|
@@ -29,31 +29,31 @@ module Servactory
|
|
29
29
|
|
30
30
|
# EXAMPLE:
|
31
31
|
#
|
32
|
-
# define_method(:user=) do |value
|
33
|
-
# Servactory::InternalArguments::Checks::Type.check!( context: self, output_argument:, value: )
|
32
|
+
# define_method(:user=) do |value|
|
33
|
+
# Servactory::InternalArguments::Checks::Type.check!( context: self, output_argument:, value: )
|
34
34
|
#
|
35
|
-
# instance_variable_set(:@user, value)
|
36
|
-
# end
|
35
|
+
# instance_variable_set(:@user, value)
|
36
|
+
# end
|
37
37
|
#
|
38
|
-
# private
|
38
|
+
# private
|
39
39
|
#
|
40
|
-
# attr_reader :user
|
40
|
+
# attr_reader :user
|
41
41
|
#
|
42
42
|
def context_output_argument_template_for(output_argument)
|
43
|
-
<<-RUBY
|
44
|
-
define_method(:#{output_argument.name}=) do |value
|
43
|
+
<<-RUBY
|
44
|
+
define_method(:#{output_argument.name}=) do |value|
|
45
45
|
Servactory::OutputArguments::Checks::Type.check!(
|
46
46
|
context: self,
|
47
47
|
output_argument: output_argument,
|
48
48
|
value: value
|
49
|
-
)
|
49
|
+
)
|
50
50
|
|
51
|
-
instance_variable_set(:@#{output_argument.name}, value)
|
52
|
-
end
|
51
|
+
instance_variable_set(:@#{output_argument.name}, value)
|
52
|
+
end
|
53
53
|
|
54
|
-
private
|
54
|
+
private
|
55
55
|
|
56
|
-
attr_reader :#{output_argument.name}
|
56
|
+
attr_reader :#{output_argument.name}
|
57
57
|
RUBY
|
58
58
|
end
|
59
59
|
end
|
data/lib/servactory/version.rb
CHANGED
data/lib/servactory.rb
CHANGED
@@ -17,11 +17,11 @@ module Servactory
|
|
17
17
|
module_function
|
18
18
|
|
19
19
|
def configuration
|
20
|
-
@configuration ||= Servactory::Configuration.new
|
20
|
+
@configuration ||= Servactory::Configuration::Setup.new
|
21
21
|
end
|
22
22
|
|
23
23
|
def reset
|
24
|
-
@configuration = Servactory::Configuration.new
|
24
|
+
@configuration = Servactory::Configuration::Setup.new
|
25
25
|
end
|
26
26
|
|
27
27
|
def configure
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: servactory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Sokolov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -161,16 +161,23 @@ files:
|
|
161
161
|
- Rakefile
|
162
162
|
- lib/servactory.rb
|
163
163
|
- lib/servactory/base.rb
|
164
|
-
- lib/servactory/configuration.rb
|
164
|
+
- lib/servactory/configuration/dsl.rb
|
165
|
+
- lib/servactory/configuration/factory.rb
|
166
|
+
- lib/servactory/configuration/setup.rb
|
167
|
+
- lib/servactory/context/callable.rb
|
165
168
|
- lib/servactory/context/configuration.rb
|
166
169
|
- lib/servactory/context/dsl.rb
|
167
170
|
- lib/servactory/context/store.rb
|
171
|
+
- lib/servactory/context/workspace.rb
|
172
|
+
- lib/servactory/context/workspace/error.rb
|
173
|
+
- lib/servactory/context/workspace/errors.rb
|
168
174
|
- lib/servactory/errors/base.rb
|
169
175
|
- lib/servactory/errors/failure.rb
|
170
176
|
- lib/servactory/errors/input_argument_error.rb
|
171
177
|
- lib/servactory/errors/internal_argument_error.rb
|
172
178
|
- lib/servactory/errors/output_argument_error.rb
|
173
179
|
- lib/servactory/input_arguments/checks/base.rb
|
180
|
+
- lib/servactory/input_arguments/checks/errors.rb
|
174
181
|
- lib/servactory/input_arguments/checks/inclusion.rb
|
175
182
|
- lib/servactory/input_arguments/checks/must.rb
|
176
183
|
- lib/servactory/input_arguments/checks/required.rb
|
@@ -181,6 +188,7 @@ files:
|
|
181
188
|
- lib/servactory/input_arguments/option.rb
|
182
189
|
- lib/servactory/input_arguments/options_collection.rb
|
183
190
|
- lib/servactory/input_arguments/tools/check.rb
|
191
|
+
- lib/servactory/input_arguments/tools/check_errors.rb
|
184
192
|
- lib/servactory/input_arguments/tools/find_unnecessary.rb
|
185
193
|
- lib/servactory/input_arguments/tools/prepare.rb
|
186
194
|
- lib/servactory/input_arguments/tools/rules.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Servactory
|
4
|
-
class Configuration
|
5
|
-
attr_accessor :input_argument_error_class,
|
6
|
-
:internal_argument_error_class,
|
7
|
-
:output_argument_error_class,
|
8
|
-
:failure_class
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@input_argument_error_class = Servactory::Errors::InputArgumentError
|
12
|
-
@internal_argument_error_class = Servactory::Errors::InternalArgumentError
|
13
|
-
@output_argument_error_class = Servactory::Errors::OutputArgumentError
|
14
|
-
|
15
|
-
@failure_class = Servactory::Errors::Failure
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|