servactory 1.2.0 → 1.4.0
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 +155 -11
- data/lib/servactory/context/dsl.rb +10 -5
- data/lib/servactory/input_arguments/checks/inclusion.rb +2 -2
- data/lib/servactory/input_arguments/checks/must.rb +4 -2
- data/lib/servactory/input_arguments/checks/type.rb +9 -1
- data/lib/servactory/input_arguments/dsl.rb +9 -1
- data/lib/servactory/input_arguments/input_argument.rb +158 -44
- data/lib/servactory/input_arguments/option.rb +68 -0
- data/lib/servactory/input_arguments/options_collection.rb +35 -0
- data/lib/servactory/input_arguments/tools/check.rb +5 -9
- data/lib/servactory/input_arguments/workbench.rb +6 -3
- data/lib/servactory/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4ffa3b926585163837e461a8a1b129a81f951f88a8d715dd6e74297e0a37ddd
|
4
|
+
data.tar.gz: 1d1a3326828e282ad0f46bc76e2754fb44e0dbd5f2e00c452cd6e856866bcbbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07c4e1f255a4fabe953a3c1381229000b564b80fc0e4f1c08547fed23dcc9cb9b31ebab678d76f894ce55e5506120d412fab26bf214f433f00cf43d958b502d7
|
7
|
+
data.tar.gz: 85cadb2169b968a0e9cda6f9279d9be37b01acdc0f7f91ca2b7f8458e89a219213ad317b84002d1b7684bb695a73b4c5a3a6c092a4e3a61c05984e2ee027a164
|
data/README.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
A set of tools for building reliable services of any complexity.
|
4
4
|
|
5
|
+
[](https://rubygems.org/gems/servactory)
|
6
|
+
|
7
|
+
## Contents
|
8
|
+
|
9
|
+
- [Requirements](https://github.com/afuno/servactory/edit/main/README.md#requirements)
|
10
|
+
- [Getting started](https://github.com/afuno/servactory/edit/main/README.md#getting-started)
|
11
|
+
- [Conventions](https://github.com/afuno/servactory/edit/main/README.md#conventions)
|
12
|
+
- [Installation](https://github.com/afuno/servactory/edit/main/README.md#installation)
|
13
|
+
- [Preparation](https://github.com/afuno/servactory/edit/main/README.md#preparation)
|
14
|
+
- [Usage](https://github.com/afuno/servactory/edit/main/README.md#usage)
|
15
|
+
- [Minimal example](https://github.com/afuno/servactory#minimal-example)
|
16
|
+
- [Input attributes](https://github.com/afuno/servactory#input-attributes)
|
17
|
+
- [Isolated usage](https://github.com/afuno/servactory#isolated-usage)
|
18
|
+
- [As an internal argument](https://github.com/afuno/servactory#isolated-usage)
|
19
|
+
- [Optional inputs](https://github.com/afuno/servactory#optional-inputs)
|
20
|
+
- [An array of specific values](https://github.com/afuno/servactory#an-array-of-specific-values)
|
21
|
+
- [Inclusion](https://github.com/afuno/servactory#inclusion)
|
22
|
+
- [Must](https://github.com/afuno/servactory#must)
|
23
|
+
- [Output attributes](https://github.com/afuno/servactory/edit/main/README.md#output-attributes)
|
24
|
+
- [Internal attributes](https://github.com/afuno/servactory/edit/main/README.md#internal-attributes)
|
25
|
+
- [Result](https://github.com/afuno/servactory/edit/main/README.md#result)
|
26
|
+
|
5
27
|
## Requirements
|
6
28
|
|
7
29
|
- Ruby >= 2.7
|
@@ -70,7 +92,7 @@ end
|
|
70
92
|
### Minimal example
|
71
93
|
|
72
94
|
```ruby
|
73
|
-
class
|
95
|
+
class MinimalService < ApplicationService::Base
|
74
96
|
stage { make :something }
|
75
97
|
|
76
98
|
private
|
@@ -81,36 +103,158 @@ class SendService < ApplicationService::Base
|
|
81
103
|
end
|
82
104
|
```
|
83
105
|
|
84
|
-
###
|
106
|
+
### Input attributes
|
107
|
+
|
108
|
+
#### Isolated usage
|
109
|
+
|
110
|
+
With this approach, all input attributes are available only from `inputs`. This is default behaviour.
|
85
111
|
|
86
112
|
```ruby
|
87
|
-
class
|
113
|
+
class UsersService::Accept < ApplicationService::Base
|
88
114
|
input :user, type: User
|
89
115
|
|
90
|
-
stage { make :
|
116
|
+
stage { make :accept! }
|
91
117
|
|
92
118
|
private
|
93
119
|
|
94
|
-
def
|
95
|
-
|
120
|
+
def accept!
|
121
|
+
inputs.user.accept!
|
122
|
+
end
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
#### As an internal argument
|
127
|
+
|
128
|
+
With this approach, all input attributes are available from `inputs` as well as directly from the context.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class UsersService::Accept < ApplicationService::Base
|
132
|
+
input :user, type: User, internal: true
|
133
|
+
|
134
|
+
stage { make :accept! }
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def accept!
|
139
|
+
user.accept!
|
96
140
|
end
|
97
141
|
end
|
98
142
|
```
|
99
143
|
|
100
|
-
|
144
|
+
#### Optional inputs
|
145
|
+
|
146
|
+
By default, all inputs are required. To make an input optional, specify `false` in the `required` option.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
class UsersService::Create < ApplicationService::Base
|
150
|
+
input :first_name, type: String, internal: true
|
151
|
+
input :middle_name, type: String, required: false
|
152
|
+
input :last_name, type: String, internal: true
|
153
|
+
|
154
|
+
# ...
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
#### An array of specific values
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class PymentsService::Send < ApplicationService::Base
|
162
|
+
input :invoice_numbers, type: String, array: true
|
163
|
+
|
164
|
+
# ...
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
#### Inclusion
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
class EventService::Send < ApplicationService::Base
|
172
|
+
input :event_name, type: String, inclusion: %w[created rejected approved]
|
173
|
+
|
174
|
+
# ...
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
#### Must
|
179
|
+
|
180
|
+
Sometimes there are cases that require the implementation of a specific input attribute check. In such cases `must` can help.
|
101
181
|
|
102
182
|
```ruby
|
103
|
-
class
|
183
|
+
class PymentsService::Send < ApplicationService::Base
|
184
|
+
input :invoice_numbers,
|
185
|
+
type: String,
|
186
|
+
array: true,
|
187
|
+
must: {
|
188
|
+
be_6_characters: {
|
189
|
+
is: ->(value:) { value.all? { |id| id.size == 6 } }
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
# ...
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
### Output attributes
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
class NotificationService::Create < ApplicationService::Base
|
104
201
|
input :user, type: User
|
105
202
|
|
106
203
|
output :notification, type: Notification
|
107
204
|
|
108
|
-
stage { make :
|
205
|
+
stage { make :create_notification! }
|
109
206
|
|
110
207
|
private
|
111
208
|
|
112
|
-
def
|
113
|
-
self.notification = Notification.create!
|
209
|
+
def create_notification!
|
210
|
+
self.notification = Notification.create!(user: inputs.user)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
### Internal attributes
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class NotificationService::Create < ApplicationService::Base
|
219
|
+
input :user, type: User
|
220
|
+
|
221
|
+
internal :inviter, type: User
|
222
|
+
|
223
|
+
output :notification, type: Notification
|
224
|
+
|
225
|
+
stage do
|
226
|
+
make :assign_inviter
|
227
|
+
make :create_notification!
|
228
|
+
end
|
229
|
+
|
230
|
+
private
|
231
|
+
|
232
|
+
def assign_inviter
|
233
|
+
self.inviter = user.inviter
|
234
|
+
end
|
235
|
+
|
236
|
+
def create_notification!
|
237
|
+
self.notification = Notification.create!(user: inputs.user, inviter:)
|
114
238
|
end
|
115
239
|
end
|
116
240
|
```
|
241
|
+
|
242
|
+
### Result
|
243
|
+
|
244
|
+
All services have the result of their work. For example, in case of success this call:
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
service_result = NotificationService::Create.call!(user: User.first)
|
248
|
+
```
|
249
|
+
|
250
|
+
Will return this:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
#<Servactory::Result:0x0000000112c00748 @notification=...>
|
254
|
+
```
|
255
|
+
|
256
|
+
And then you can work with this result, for example, in this way:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
Notification::SendJob.perform_later(service_result.notification.id)
|
260
|
+
```
|
@@ -35,11 +35,16 @@ module Servactory
|
|
35
35
|
|
36
36
|
attr_reader :context_store
|
37
37
|
|
38
|
-
def assign_data_with(arguments)
|
39
|
-
input_arguments_workbench.assign(
|
40
|
-
|
41
|
-
|
42
|
-
|
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)
|
43
48
|
end
|
44
49
|
|
45
50
|
def prepare_data
|
@@ -5,7 +5,7 @@ module Servactory
|
|
5
5
|
module Checks
|
6
6
|
class Inclusion < Base
|
7
7
|
DEFAULT_MESSAGE = lambda do |service_class_name:, input:|
|
8
|
-
"[#{service_class_name}] Wrong value in `#{input.name}`, must be one of `#{input.inclusion}`"
|
8
|
+
"[#{service_class_name}] Wrong value in `#{input.name}`, must be one of `#{input.inclusion[:in]}`"
|
9
9
|
end
|
10
10
|
|
11
11
|
private_constant :DEFAULT_MESSAGE
|
@@ -31,7 +31,7 @@ module Servactory
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def check
|
34
|
-
return if @input.inclusion.include?(@value)
|
34
|
+
return if @input.inclusion[:in].include?(@value)
|
35
35
|
|
36
36
|
add_error(
|
37
37
|
DEFAULT_MESSAGE,
|
@@ -32,7 +32,7 @@ module Servactory
|
|
32
32
|
@check_options = check_options
|
33
33
|
end
|
34
34
|
|
35
|
-
def check
|
35
|
+
def check # rubocop:disable Metrics/MethodLength
|
36
36
|
@check_options.each do |code, options|
|
37
37
|
message = call_or_fetch_message_from(code, options)
|
38
38
|
|
@@ -57,10 +57,12 @@ module Servactory
|
|
57
57
|
return if check.call(value: @value)
|
58
58
|
|
59
59
|
message.presence || DEFAULT_MESSAGE
|
60
|
-
rescue StandardError =>
|
60
|
+
rescue StandardError => e
|
61
61
|
message_text =
|
62
62
|
"[#{@context.class.name}] Syntax error inside `#{code}` of `#{@input.name}` input"
|
63
63
|
|
64
|
+
puts "#{message_text}: #{e}"
|
65
|
+
|
64
66
|
add_error(
|
65
67
|
message_text,
|
66
68
|
service_class_name: @context.class.name,
|
@@ -6,7 +6,15 @@ module Servactory
|
|
6
6
|
class Type < Base
|
7
7
|
DEFAULT_MESSAGE = lambda do |service_class_name:, input:, expected_type:, given_type:|
|
8
8
|
if input.array?
|
9
|
-
|
9
|
+
array_message = input.array[:message]
|
10
|
+
|
11
|
+
if array_message.is_a?(Proc)
|
12
|
+
array_message.call(input: input, expected_type: expected_type)
|
13
|
+
elsif array_message.is_a?(String) && array_message.present?
|
14
|
+
array_message
|
15
|
+
else
|
16
|
+
"[#{service_class_name}] Wrong type in input array `#{input.name}`, expected `#{expected_type}`"
|
17
|
+
end
|
10
18
|
else
|
11
19
|
"[#{service_class_name}] Wrong type of input `#{input.name}`, " \
|
12
20
|
"expected `#{expected_type}`, " \
|
@@ -11,13 +11,21 @@ module Servactory
|
|
11
11
|
private
|
12
12
|
|
13
13
|
def input(name, **options)
|
14
|
-
collection_of_input_arguments << InputArgument.new(
|
14
|
+
collection_of_input_arguments << InputArgument.new(
|
15
|
+
name,
|
16
|
+
collection_of_options: collection_of_input_options,
|
17
|
+
**options
|
18
|
+
)
|
15
19
|
end
|
16
20
|
|
17
21
|
def collection_of_input_arguments
|
18
22
|
@collection_of_input_arguments ||= Collection.new
|
19
23
|
end
|
20
24
|
|
25
|
+
def collection_of_input_options
|
26
|
+
@collection_of_input_options ||= OptionsCollection.new
|
27
|
+
end
|
28
|
+
|
21
29
|
def input_arguments_workbench
|
22
30
|
@input_arguments_workbench ||= Workbench.work_with(collection_of_input_arguments)
|
23
31
|
end
|
@@ -2,73 +2,187 @@
|
|
2
2
|
|
3
3
|
module Servactory
|
4
4
|
module InputArguments
|
5
|
-
class InputArgument
|
5
|
+
class InputArgument # rubocop:disable Metrics/ClassLength
|
6
|
+
ARRAY_DEFAULT_VALUE = ->(is: false, message: nil) { { is: is, message: message } }
|
7
|
+
|
6
8
|
attr_reader :name,
|
7
|
-
:
|
8
|
-
:
|
9
|
-
|
10
|
-
|
11
|
-
:required,
|
12
|
-
:internal,
|
13
|
-
:default
|
14
|
-
|
15
|
-
def initialize(name, type:, **options)
|
9
|
+
:collection_of_options,
|
10
|
+
:types
|
11
|
+
|
12
|
+
def initialize(name, collection_of_options:, type:, **options)
|
16
13
|
@name = name
|
14
|
+
@collection_of_options = collection_of_options
|
17
15
|
@types = Array(type)
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
@
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
add_basic_options_with(options)
|
18
|
+
|
19
|
+
@collection_of_options.each do |option|
|
20
|
+
self.class.attr_reader(:"#{option.name}")
|
21
|
+
|
22
|
+
instance_variable_set(:"@#{option.name}", option.value)
|
23
|
+
end
|
25
24
|
end
|
26
25
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
def add_basic_options_with(options)
|
27
|
+
# Check Class: Servactory::InputArguments::Checks::Required
|
28
|
+
add_required_option_with(options)
|
29
|
+
|
30
|
+
# Check Class: Servactory::InputArguments::Checks::Type
|
31
|
+
add_array_option_with(options)
|
32
|
+
add_default_option_with(options)
|
33
|
+
|
34
|
+
# Check Class: Servactory::InputArguments::Checks::Inclusion
|
35
|
+
add_inclusion_option_with(options)
|
36
|
+
|
37
|
+
# Check Class: Servactory::InputArguments::Checks::Must
|
38
|
+
add_must_option_with(options)
|
39
|
+
|
40
|
+
# Check Class: nil
|
41
|
+
add_internal_option_with(options)
|
36
42
|
end
|
37
43
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
def add_required_option_with(options) # rubocop:disable Metrics/MethodLength
|
45
|
+
collection_of_options << Option.new(
|
46
|
+
name: :required,
|
47
|
+
input: self,
|
48
|
+
check_class: Servactory::InputArguments::Checks::Required,
|
49
|
+
define_input_methods: lambda do
|
50
|
+
<<-RUBY
|
51
|
+
def required?
|
52
|
+
Servactory::Utils.boolean?(required[:is])
|
53
|
+
end
|
42
54
|
|
43
|
-
|
55
|
+
def optional?
|
56
|
+
!required?
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
end,
|
60
|
+
define_conflicts: lambda do
|
61
|
+
<<-RUBY
|
62
|
+
return :required_vs_default if required? && default_value_present?
|
63
|
+
RUBY
|
64
|
+
end,
|
65
|
+
need_for_checks: true,
|
66
|
+
value_key: :is,
|
67
|
+
value_fallback: true,
|
68
|
+
**options
|
69
|
+
)
|
44
70
|
end
|
45
71
|
|
46
|
-
def
|
47
|
-
|
72
|
+
def add_array_option_with(options) # rubocop:disable Metrics/MethodLength
|
73
|
+
collection_of_options << Option.new(
|
74
|
+
name: :array,
|
75
|
+
input: self,
|
76
|
+
check_class: Servactory::InputArguments::Checks::Type,
|
77
|
+
define_input_methods: lambda do
|
78
|
+
<<-RUBY
|
79
|
+
def array?
|
80
|
+
Servactory::Utils.boolean?(array[:is])
|
81
|
+
end
|
82
|
+
RUBY
|
83
|
+
end,
|
84
|
+
define_conflicts: lambda do
|
85
|
+
<<-RUBY
|
86
|
+
return :array_vs_array if array? && types.include?(Array)
|
87
|
+
return :array_vs_inclusion if array? && inclusion_present?
|
88
|
+
RUBY
|
89
|
+
end,
|
90
|
+
need_for_checks: false,
|
91
|
+
value_key: :is,
|
92
|
+
value_fallback: false,
|
93
|
+
**options
|
94
|
+
)
|
48
95
|
end
|
49
96
|
|
50
|
-
def
|
51
|
-
|
97
|
+
def add_default_option_with(options) # rubocop:disable Metrics/MethodLength
|
98
|
+
collection_of_options << Option.new(
|
99
|
+
name: :default,
|
100
|
+
input: self,
|
101
|
+
check_class: Servactory::InputArguments::Checks::Type,
|
102
|
+
define_input_methods: lambda do
|
103
|
+
<<-RUBY
|
104
|
+
def default_value_present?
|
105
|
+
!default.nil?
|
106
|
+
end
|
107
|
+
RUBY
|
108
|
+
end,
|
109
|
+
need_for_checks: true,
|
110
|
+
value_fallback: nil,
|
111
|
+
with_advanced_mode: false,
|
112
|
+
**options
|
113
|
+
)
|
52
114
|
end
|
53
115
|
|
54
|
-
def
|
55
|
-
|
116
|
+
def add_inclusion_option_with(options) # rubocop:disable Metrics/MethodLength
|
117
|
+
collection_of_options << Option.new(
|
118
|
+
name: :inclusion,
|
119
|
+
input: self,
|
120
|
+
check_class: Servactory::InputArguments::Checks::Inclusion,
|
121
|
+
define_input_methods: lambda do
|
122
|
+
<<-RUBY
|
123
|
+
def inclusion_present?
|
124
|
+
inclusion[:in].is_a?(Array) && inclusion[:in].present?
|
125
|
+
end
|
126
|
+
RUBY
|
127
|
+
end,
|
128
|
+
need_for_checks: true,
|
129
|
+
value_key: :in,
|
130
|
+
value_fallback: nil,
|
131
|
+
**options
|
132
|
+
)
|
56
133
|
end
|
57
134
|
|
58
|
-
def
|
59
|
-
|
135
|
+
def add_must_option_with(options) # rubocop:disable Metrics/MethodLength
|
136
|
+
collection_of_options << Option.new(
|
137
|
+
name: :must,
|
138
|
+
input: self,
|
139
|
+
check_class: Servactory::InputArguments::Checks::Must,
|
140
|
+
define_input_methods: lambda do
|
141
|
+
<<-RUBY
|
142
|
+
def must_present?
|
143
|
+
must.present?
|
144
|
+
end
|
145
|
+
RUBY
|
146
|
+
end,
|
147
|
+
need_for_checks: true,
|
148
|
+
value_key: :is,
|
149
|
+
value_fallback: nil,
|
150
|
+
with_advanced_mode: false,
|
151
|
+
**options
|
152
|
+
)
|
60
153
|
end
|
61
154
|
|
62
|
-
def
|
63
|
-
|
155
|
+
def add_internal_option_with(options) # rubocop:disable Metrics/MethodLength
|
156
|
+
collection_of_options << Option.new(
|
157
|
+
name: :internal,
|
158
|
+
input: self,
|
159
|
+
define_input_methods: lambda do
|
160
|
+
<<-RUBY
|
161
|
+
def internal?
|
162
|
+
Servactory::Utils.boolean?(internal[:is])
|
163
|
+
end
|
164
|
+
RUBY
|
165
|
+
end,
|
166
|
+
need_for_checks: false,
|
167
|
+
check_class: nil,
|
168
|
+
value_key: :is,
|
169
|
+
value_fallback: false,
|
170
|
+
**options
|
171
|
+
)
|
64
172
|
end
|
65
173
|
|
66
|
-
def
|
67
|
-
|
174
|
+
def options_for_checks
|
175
|
+
{
|
176
|
+
types: types
|
177
|
+
}.merge(
|
178
|
+
collection_of_options.options_for_checks
|
179
|
+
)
|
68
180
|
end
|
69
181
|
|
70
|
-
def
|
71
|
-
|
182
|
+
def conflict_code
|
183
|
+
instance_eval(collection_of_options.defined_conflicts)
|
184
|
+
|
185
|
+
nil
|
72
186
|
end
|
73
187
|
|
74
188
|
def with_conflicts?
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module InputArguments
|
5
|
+
class Option
|
6
|
+
DEFAULT_VALUE = ->(key:, value:, message: nil) { { key => value, message: message } }
|
7
|
+
|
8
|
+
private_constant :DEFAULT_VALUE
|
9
|
+
|
10
|
+
attr_reader :name,
|
11
|
+
:check_class,
|
12
|
+
:define_conflicts,
|
13
|
+
:need_for_checks,
|
14
|
+
:value_key,
|
15
|
+
:value
|
16
|
+
|
17
|
+
def initialize(
|
18
|
+
name:,
|
19
|
+
input:,
|
20
|
+
check_class:,
|
21
|
+
need_for_checks:,
|
22
|
+
value_fallback:,
|
23
|
+
value_key: nil,
|
24
|
+
define_input_methods: nil,
|
25
|
+
define_conflicts: nil,
|
26
|
+
with_advanced_mode: true,
|
27
|
+
**options
|
28
|
+
) # do
|
29
|
+
@name = name.to_sym
|
30
|
+
@check_class = check_class
|
31
|
+
@define_conflicts = define_conflicts
|
32
|
+
@need_for_checks = need_for_checks
|
33
|
+
@value_key = value_key
|
34
|
+
|
35
|
+
@value = prepare_value_for(options, value_fallback: value_fallback, with_advanced_mode: with_advanced_mode)
|
36
|
+
|
37
|
+
input.instance_eval(define_input_methods.call) if define_input_methods.present?
|
38
|
+
end
|
39
|
+
|
40
|
+
def need_for_checks?
|
41
|
+
need_for_checks
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def prepare_value_for(options, value_fallback:, with_advanced_mode:)
|
47
|
+
return options.fetch(@name, value_fallback) unless with_advanced_mode
|
48
|
+
|
49
|
+
prepare_advanced_for(
|
50
|
+
value: options.fetch(@name, DEFAULT_VALUE.call(key: value_key, value: value_fallback)),
|
51
|
+
value_fallback: value_fallback
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def prepare_advanced_for(value:, value_fallback:)
|
56
|
+
if value.is_a?(Hash)
|
57
|
+
DEFAULT_VALUE.call(
|
58
|
+
key: value_key,
|
59
|
+
value: value.fetch(value_key, value_fallback),
|
60
|
+
message: value.fetch(:message, nil)
|
61
|
+
)
|
62
|
+
else
|
63
|
+
DEFAULT_VALUE.call(key: value_key, value: value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module InputArguments
|
5
|
+
class OptionsCollection
|
6
|
+
# NOTE: http://words.steveklabnik.com/beware-subclassing-ruby-core-classes
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :@collection, :<<, :each, :select, :map
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
@collection = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_classes
|
15
|
+
select { |option| option.check_class.present? }.map(&:check_class).uniq
|
16
|
+
end
|
17
|
+
|
18
|
+
def options_for_checks
|
19
|
+
select(&:need_for_checks?).to_h do |option|
|
20
|
+
value = if option.value.is_a?(Hash)
|
21
|
+
option.value.key?(:is) ? option.value.fetch(:is) : option.value
|
22
|
+
else
|
23
|
+
option.value
|
24
|
+
end
|
25
|
+
|
26
|
+
[option.name, value]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def defined_conflicts
|
31
|
+
map { |option| option.define_conflicts&.call }.reject(&:blank?).uniq.join
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -8,10 +8,11 @@ module Servactory
|
|
8
8
|
new(...).check!
|
9
9
|
end
|
10
10
|
|
11
|
-
def initialize(context, incoming_arguments, collection_of_input_arguments)
|
11
|
+
def initialize(context, incoming_arguments, collection_of_input_arguments, collection_of_input_options)
|
12
12
|
@context = context
|
13
13
|
@incoming_arguments = incoming_arguments
|
14
14
|
@collection_of_input_arguments = collection_of_input_arguments
|
15
|
+
@collection_of_input_options = collection_of_input_options
|
15
16
|
|
16
17
|
@errors = []
|
17
18
|
end
|
@@ -58,20 +59,15 @@ module Servactory
|
|
58
59
|
########################################################################
|
59
60
|
|
60
61
|
def check_classes
|
61
|
-
|
62
|
-
Servactory::InputArguments::Checks::Required,
|
63
|
-
Servactory::InputArguments::Checks::Type,
|
64
|
-
Servactory::InputArguments::Checks::Inclusion,
|
65
|
-
Servactory::InputArguments::Checks::Must
|
66
|
-
]
|
62
|
+
@collection_of_input_options.check_classes
|
67
63
|
end
|
68
64
|
|
69
65
|
########################################################################
|
70
66
|
|
71
67
|
def raise_errors
|
72
|
-
return if @errors.empty?
|
68
|
+
return if (tmp_errors = @errors.reject(&:blank?).uniq).empty?
|
73
69
|
|
74
|
-
raise Servactory.configuration.input_argument_error_class,
|
70
|
+
raise Servactory.configuration.input_argument_error_class, tmp_errors.first
|
75
71
|
end
|
76
72
|
end
|
77
73
|
end
|
@@ -11,9 +11,10 @@ module Servactory
|
|
11
11
|
@collection_of_input_arguments = collection_of_input_arguments
|
12
12
|
end
|
13
13
|
|
14
|
-
def assign(context:, arguments:)
|
14
|
+
def assign(context:, arguments:, collection_of_input_options:)
|
15
15
|
@context = context
|
16
16
|
@incoming_arguments = arguments
|
17
|
+
@collection_of_input_options = collection_of_input_options
|
17
18
|
end
|
18
19
|
|
19
20
|
def find_unnecessary!
|
@@ -29,12 +30,14 @@ module Servactory
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def check!
|
32
|
-
Tools::Check.check!(context, @incoming_arguments, collection_of_input_arguments)
|
33
|
+
Tools::Check.check!(context, @incoming_arguments, collection_of_input_arguments, collection_of_input_options)
|
33
34
|
end
|
34
35
|
|
35
36
|
private
|
36
37
|
|
37
|
-
attr_reader :context,
|
38
|
+
attr_reader :context,
|
39
|
+
:collection_of_input_arguments,
|
40
|
+
:collection_of_input_options
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
data/lib/servactory/version.rb
CHANGED
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
|
+
version: 1.4.0
|
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-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -178,6 +178,8 @@ files:
|
|
178
178
|
- lib/servactory/input_arguments/collection.rb
|
179
179
|
- lib/servactory/input_arguments/dsl.rb
|
180
180
|
- lib/servactory/input_arguments/input_argument.rb
|
181
|
+
- lib/servactory/input_arguments/option.rb
|
182
|
+
- lib/servactory/input_arguments/options_collection.rb
|
181
183
|
- lib/servactory/input_arguments/tools/check.rb
|
182
184
|
- lib/servactory/input_arguments/tools/find_unnecessary.rb
|
183
185
|
- lib/servactory/input_arguments/tools/prepare.rb
|