decouplio 1.0.0alpha
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 +7 -0
- data/.circleci/config.yml +53 -0
- data/.dockerignore +12 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +106 -0
- data/.rubocop_todo.yml +147 -0
- data/.ruby-version +1 -0
- data/.vscode/settings.json +3 -0
- data/Dockerfile +12 -0
- data/Gemfile +8 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/benchmarks/.ruby-version +1 -0
- data/benchmarks/Dockerfile +12 -0
- data/benchmarks/Gemfile +11 -0
- data/benchmarks/benchmarks.rb +527 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/decouplio.gemspec +40 -0
- data/docker-compose.yml +18 -0
- data/docs/_config.yml +1 -0
- data/docs/benchmarks.md +1 -0
- data/docs/context.md +74 -0
- data/docs/context.rb +62 -0
- data/docs/doby.md +80 -0
- data/docs/doby.rb +38 -0
- data/docs/error_store.md +347 -0
- data/docs/error_store.rb +202 -0
- data/docs/fail.md +1016 -0
- data/docs/fail.rb +762 -0
- data/docs/index.md +25 -0
- data/docs/inner_action.md +63 -0
- data/docs/inner_action.rb +43 -0
- data/docs/logic_block.md +25 -0
- data/docs/octo.md +269 -0
- data/docs/octo.rb +164 -0
- data/docs/pass.md +309 -0
- data/docs/pass.rb +213 -0
- data/docs/quick_start.md +71 -0
- data/docs/quick_start.rb +38 -0
- data/docs/resq.md +263 -0
- data/docs/resq.rb +176 -0
- data/docs/step.md +737 -0
- data/docs/step.rb +526 -0
- data/docs/step_as_a_service.md +109 -0
- data/docs/step_as_a_service.rb +77 -0
- data/docs/wrap.md +232 -0
- data/docs/wrap.rb +137 -0
- data/lib/decouplio/action.rb +111 -0
- data/lib/decouplio/composer.rb +599 -0
- data/lib/decouplio/const/colors.rb +25 -0
- data/lib/decouplio/const/reserved_methods.rb +18 -0
- data/lib/decouplio/const/results.rb +13 -0
- data/lib/decouplio/const/types.rb +173 -0
- data/lib/decouplio/const/validations/action_option_class.rb +17 -0
- data/lib/decouplio/const/validations/common.rb +14 -0
- data/lib/decouplio/const/validations/fail.rb +34 -0
- data/lib/decouplio/const/validations/logic.rb +15 -0
- data/lib/decouplio/const/validations/octo.rb +44 -0
- data/lib/decouplio/const/validations/palp.rb +20 -0
- data/lib/decouplio/const/validations/pass.rb +32 -0
- data/lib/decouplio/const/validations/resq.rb +67 -0
- data/lib/decouplio/const/validations/step.rb +35 -0
- data/lib/decouplio/const/validations/wrap.rb +41 -0
- data/lib/decouplio/default_error_handler.rb +24 -0
- data/lib/decouplio/errors/action_class_error.rb +26 -0
- data/lib/decouplio/errors/base_error.rb +30 -0
- data/lib/decouplio/errors/error_store_error.rb +17 -0
- data/lib/decouplio/errors/extra_key_for_fail_error.rb +26 -0
- data/lib/decouplio/errors/extra_key_for_octo_error.rb +26 -0
- data/lib/decouplio/errors/extra_key_for_pass_error.rb +26 -0
- data/lib/decouplio/errors/extra_key_for_resq_error.rb +29 -0
- data/lib/decouplio/errors/extra_key_for_step_error.rb +23 -0
- data/lib/decouplio/errors/extra_key_for_wrap_error.rb +23 -0
- data/lib/decouplio/errors/fail_controversial_keys_error.rb +26 -0
- data/lib/decouplio/errors/fail_finish_him_error.rb +26 -0
- data/lib/decouplio/errors/fail_is_first_step_error.rb +18 -0
- data/lib/decouplio/errors/invalid_error_class_error.rb +29 -0
- data/lib/decouplio/errors/invalid_wrap_name_error.rb +23 -0
- data/lib/decouplio/errors/logic_is_not_defined_error.rb +23 -0
- data/lib/decouplio/errors/logic_redefinition_error.rb +23 -0
- data/lib/decouplio/errors/octo_block_is_not_defined_error.rb +18 -0
- data/lib/decouplio/errors/octo_controversial_keys_error.rb +26 -0
- data/lib/decouplio/errors/options_validation_error.rb +7 -0
- data/lib/decouplio/errors/palp_block_is_not_defined_error.rb +18 -0
- data/lib/decouplio/errors/palp_is_not_defined_error.rb +26 -0
- data/lib/decouplio/errors/palp_validation_error.rb +21 -0
- data/lib/decouplio/errors/pass_controversial_keys_error.rb +26 -0
- data/lib/decouplio/errors/pass_finish_him_error.rb +26 -0
- data/lib/decouplio/errors/required_options_is_missing_for_octo_error.rb +25 -0
- data/lib/decouplio/errors/resq_definition_error.rb +21 -0
- data/lib/decouplio/errors/resq_error_class_error.rb +29 -0
- data/lib/decouplio/errors/resq_handler_method_error.rb +26 -0
- data/lib/decouplio/errors/step_controversial_keys_error.rb +26 -0
- data/lib/decouplio/errors/step_finish_him_error.rb +26 -0
- data/lib/decouplio/errors/step_is_not_defined_for_fail_error.rb +26 -0
- data/lib/decouplio/errors/step_is_not_defined_for_step_error.rb +27 -0
- data/lib/decouplio/errors/step_is_not_defined_for_wrap_error.rb +26 -0
- data/lib/decouplio/errors/step_name_error.rb +20 -0
- data/lib/decouplio/errors/wrap_block_is_not_defined_error.rb +18 -0
- data/lib/decouplio/errors/wrap_controversial_keys_error.rb +26 -0
- data/lib/decouplio/errors/wrap_finish_him_error.rb +26 -0
- data/lib/decouplio/errors/wrap_klass_method_error.rb +23 -0
- data/lib/decouplio/flow.rb +17 -0
- data/lib/decouplio/logic_dsl.rb +96 -0
- data/lib/decouplio/octo_hash_case.rb +31 -0
- data/lib/decouplio/octo_options_validator.rb +89 -0
- data/lib/decouplio/options_validator.rb +566 -0
- data/lib/decouplio/processor.rb +20 -0
- data/lib/decouplio/steps/base_resq.rb +31 -0
- data/lib/decouplio/steps/base_step.rb +16 -0
- data/lib/decouplio/steps/doby.rb +32 -0
- data/lib/decouplio/steps/fail.rb +50 -0
- data/lib/decouplio/steps/if_condition_fail.rb +28 -0
- data/lib/decouplio/steps/if_condition_pass.rb +26 -0
- data/lib/decouplio/steps/inner_action_fail.rb +55 -0
- data/lib/decouplio/steps/inner_action_pass.rb +38 -0
- data/lib/decouplio/steps/inner_action_step.rb +51 -0
- data/lib/decouplio/steps/octo.rb +22 -0
- data/lib/decouplio/steps/pass.rb +35 -0
- data/lib/decouplio/steps/resq_fail.rb +10 -0
- data/lib/decouplio/steps/resq_pass.rb +10 -0
- data/lib/decouplio/steps/service_fail.rb +51 -0
- data/lib/decouplio/steps/service_pass.rb +36 -0
- data/lib/decouplio/steps/service_step.rb +47 -0
- data/lib/decouplio/steps/step.rb +43 -0
- data/lib/decouplio/steps/unless_condition_fail.rb +28 -0
- data/lib/decouplio/steps/unless_condition_pass.rb +26 -0
- data/lib/decouplio/steps/wrap.rb +62 -0
- data/lib/decouplio/validators/condition.rb +49 -0
- data/lib/decouplio/version.rb +5 -0
- data/lib/decouplio.rb +7 -0
- metadata +266 -0
@@ -0,0 +1,566 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'const/types'
|
4
|
+
require_relative 'const/reserved_methods'
|
5
|
+
require_relative 'errors/action_class_error'
|
6
|
+
require_relative 'errors/extra_key_for_step_error'
|
7
|
+
require_relative 'errors/extra_key_for_fail_error'
|
8
|
+
require_relative 'errors/extra_key_for_octo_error'
|
9
|
+
require_relative 'errors/extra_key_for_pass_error'
|
10
|
+
require_relative 'errors/extra_key_for_resq_error'
|
11
|
+
require_relative 'errors/extra_key_for_wrap_error'
|
12
|
+
require_relative 'errors/fail_finish_him_error'
|
13
|
+
require_relative 'errors/invalid_error_class_error'
|
14
|
+
require_relative 'errors/invalid_wrap_name_error'
|
15
|
+
require_relative 'errors/pass_finish_him_error'
|
16
|
+
require_relative 'errors/required_options_is_missing_for_octo_error'
|
17
|
+
require_relative 'errors/resq_error_class_error'
|
18
|
+
require_relative 'errors/resq_handler_method_error'
|
19
|
+
require_relative 'errors/step_finish_him_error'
|
20
|
+
require_relative 'errors/step_is_not_defined_for_step_error'
|
21
|
+
require_relative 'errors/step_is_not_defined_for_fail_error'
|
22
|
+
require_relative 'errors/step_is_not_defined_for_wrap_error'
|
23
|
+
require_relative 'errors/wrap_finish_him_error'
|
24
|
+
require_relative 'errors/wrap_klass_method_error'
|
25
|
+
require_relative 'errors/step_controversial_keys_error'
|
26
|
+
require_relative 'errors/fail_controversial_keys_error'
|
27
|
+
require_relative 'errors/pass_controversial_keys_error'
|
28
|
+
require_relative 'errors/octo_controversial_keys_error'
|
29
|
+
require_relative 'errors/wrap_controversial_keys_error'
|
30
|
+
require_relative 'errors/palp_is_not_defined_error'
|
31
|
+
require_relative 'errors/error_store_error'
|
32
|
+
require_relative 'errors/step_name_error'
|
33
|
+
|
34
|
+
module Decouplio
|
35
|
+
class OptionsValidator
|
36
|
+
def initialize(flow:, palps:, next_steps:, action_class:)
|
37
|
+
@flow = flow
|
38
|
+
@palps = palps
|
39
|
+
@next_steps = next_steps
|
40
|
+
@action_class = action_class
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
@flow.each_with_index do |(_step_id, options), index|
|
45
|
+
step_names = extract_step_names(flow: @flow.to_a[index..].to_h.merge(@next_steps || {}))
|
46
|
+
|
47
|
+
validate(options: options, step_names: step_names)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def validate(options:, step_names:)
|
54
|
+
filtered_options = options.reject { |key, _val| OPTIONS_TO_FILTER.include?(key) }
|
55
|
+
|
56
|
+
validate_name(name: options[:name])
|
57
|
+
@palps.each_key do |palp_name|
|
58
|
+
validate_name(name: palp_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
case options[:type]
|
62
|
+
when Decouplio::Const::Types::STEP_TYPE
|
63
|
+
validate_step(options: filtered_options, step_names: step_names)
|
64
|
+
when Decouplio::Const::Types::FAIL_TYPE
|
65
|
+
validate_fail(options: filtered_options, step_names: step_names)
|
66
|
+
when Decouplio::Const::Types::PASS_TYPE
|
67
|
+
validate_pass(options: filtered_options)
|
68
|
+
when Decouplio::Const::Types::OCTO_TYPE
|
69
|
+
validate_octo(options: filtered_options, hash_case: options[:hash_case])
|
70
|
+
when Decouplio::Const::Types::WRAP_TYPE
|
71
|
+
validate_wrap(options: filtered_options, name: options[:name], step_names: step_names)
|
72
|
+
when Decouplio::Const::Types::ACTION_TYPE_STEP
|
73
|
+
validate_action(action_class: options[:action], type: Decouplio::Const::Types::STEP_TYPE)
|
74
|
+
validate_error_store(parent_action_class: @action_class, child_action_class: options[:action])
|
75
|
+
validate_step(options: filtered_options, step_names: step_names)
|
76
|
+
when Decouplio::Const::Types::ACTION_TYPE_FAIL
|
77
|
+
validate_action(action_class: options[:action], type: Decouplio::Const::Types::FAIL_TYPE)
|
78
|
+
validate_error_store(parent_action_class: @action_class, child_action_class: options[:action])
|
79
|
+
validate_fail(options: filtered_options, step_names: step_names)
|
80
|
+
when Decouplio::Const::Types::ACTION_TYPE_PASS
|
81
|
+
validate_action(action_class: options[:action], type: Decouplio::Const::Types::PASS_TYPE)
|
82
|
+
validate_error_store(parent_action_class: @action_class, child_action_class: options[:action])
|
83
|
+
validate_pass(options: filtered_options)
|
84
|
+
when Decouplio::Const::Types::RESQ_TYPE_STEP,
|
85
|
+
Decouplio::Const::Types::RESQ_TYPE_FAIL,
|
86
|
+
Decouplio::Const::Types::RESQ_TYPE_PASS
|
87
|
+
validate(options: options[:step_to_resq], step_names: step_names)
|
88
|
+
validate_resq(options: filtered_options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_action(action_class:, type:)
|
93
|
+
return if action_class.is_a?(Class) && action_class <= Decouplio::Action
|
94
|
+
|
95
|
+
raise Decouplio::Errors::ActionClassError.new(
|
96
|
+
step_type: type,
|
97
|
+
errored_option: "action: #{action_class}"
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
def validate_step(options:, step_names:)
|
102
|
+
check_step_presence_for_step(options: options, step_names: step_names)
|
103
|
+
check_step_controversial_keys(options: options)
|
104
|
+
check_step_extra_keys(options: options)
|
105
|
+
check_step_finish_him(options: options)
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_fail(options:, step_names:)
|
109
|
+
check_step_presence_for_fail(options: options, step_names: step_names)
|
110
|
+
check_fail_controversial_keys(options: options)
|
111
|
+
check_fail_extra_keys(options: options)
|
112
|
+
check_fail_finish_him(options: options)
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate_pass(options:)
|
116
|
+
check_pass_extra_keys(options: options)
|
117
|
+
check_pass_finish_him(options: options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def validate_octo(options:, hash_case:)
|
121
|
+
check_octo_required_keys(options: options)
|
122
|
+
check_octo_extra_keys(options: options)
|
123
|
+
check_octo_palps(hash_case: hash_case)
|
124
|
+
end
|
125
|
+
|
126
|
+
def validate_wrap(options:, name:, step_names:)
|
127
|
+
check_wrap_name(name: name)
|
128
|
+
check_wrap_controversial_keys(options: options)
|
129
|
+
check_step_presence_for_wrap(options: options, step_names: step_names)
|
130
|
+
check_wrap_extra_keys(options: options)
|
131
|
+
check_wrap_finish_him(options: options)
|
132
|
+
check_wrap_klass_method_presence(options: options)
|
133
|
+
end
|
134
|
+
|
135
|
+
def validate_resq(options:)
|
136
|
+
options[:handler_hash].each_value do |error_handler_name|
|
137
|
+
validate_name(name: error_handler_name)
|
138
|
+
end
|
139
|
+
check_resq_extra_keys(options: options)
|
140
|
+
check_resq_handler_method_is_a_symbol(options: options)
|
141
|
+
check_resq_error_classes(options: options)
|
142
|
+
check_resq_exception_classes_inheritance(options: options)
|
143
|
+
end
|
144
|
+
|
145
|
+
def validate_name(name:)
|
146
|
+
return unless Decouplio::Const::ReservedMethods::NAMES.include?(name)
|
147
|
+
|
148
|
+
raise Decouplio::Errors::StepNameError.new(
|
149
|
+
errored_option: name
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def check_step_presence_for_step(options:, step_names:)
|
154
|
+
options.slice(*STEP_CHECK_STEP_PRESENCE).each do |option_key, option_value|
|
155
|
+
next if %i[on_success on_failure].include?(option_key) && option_value == :finish_him
|
156
|
+
|
157
|
+
next if step_names.keys.include?(option_value)
|
158
|
+
|
159
|
+
raise Decouplio::Errors::StepIsNotDefinedForStepError.new(
|
160
|
+
errored_option: options.slice(option_key).to_s,
|
161
|
+
details: option_value
|
162
|
+
)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def check_step_presence_for_fail(options:, step_names:)
|
167
|
+
options.slice(*STEP_CHECK_STEP_PRESENCE).each do |option_key, option_value|
|
168
|
+
next if %i[on_success on_failure].include?(option_key) && option_value == :finish_him
|
169
|
+
|
170
|
+
next if step_names.keys.include?(option_value)
|
171
|
+
|
172
|
+
raise Decouplio::Errors::StepIsNotDefinedForFailError.new(
|
173
|
+
errored_option: options.slice(option_key).to_s,
|
174
|
+
details: option_value
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def check_step_presence_for_wrap(options:, step_names:)
|
180
|
+
options.slice(*WRAP_CHECK_STEP_PRESENCE).each do |option_key, option_value|
|
181
|
+
next if %i[on_success on_failure].include?(option_key) && option_value == :finish_him
|
182
|
+
|
183
|
+
next if step_names.keys.include?(option_value)
|
184
|
+
|
185
|
+
raise Decouplio::Errors::StepIsNotDefinedForWrapError.new(
|
186
|
+
errored_option: options.slice(option_key).to_s,
|
187
|
+
details: option_value
|
188
|
+
)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def check_step_extra_keys(options:)
|
193
|
+
extra_keys = options.keys - STEP_ALLOWED_OPTIONS
|
194
|
+
|
195
|
+
if extra_keys.size.positive?
|
196
|
+
raise Decouplio::Errors::ExtraKeyForStepError.new(
|
197
|
+
errored_option: options.slice(*extra_keys).to_s
|
198
|
+
)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def check_step_controversial_keys(options:)
|
203
|
+
on_success_on_failure = options.slice(:on_success, :on_failure)
|
204
|
+
finish_him = options.slice(:finish_him)
|
205
|
+
|
206
|
+
if !on_success_on_failure.empty? && !finish_him.empty?
|
207
|
+
raise Decouplio::Errors::StepControversialKeysError.new(
|
208
|
+
errored_option: on_success_on_failure.merge(finish_him).to_s,
|
209
|
+
details: [on_success_on_failure.keys.join(', '), :finish_him]
|
210
|
+
)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def validate_error_store(parent_action_class:, child_action_class:)
|
215
|
+
return if parent_action_class.error_store == child_action_class.error_store
|
216
|
+
|
217
|
+
raise Decouplio::Errors::ErrorStoreError
|
218
|
+
end
|
219
|
+
|
220
|
+
def check_fail_extra_keys(options:)
|
221
|
+
extra_keys = options.keys - FAIL_ALLOWED_OPTIONS
|
222
|
+
|
223
|
+
return if extra_keys.size.zero?
|
224
|
+
|
225
|
+
raise Decouplio::Errors::ExtraKeyForFailError.new(
|
226
|
+
errored_option: options.slice(*extra_keys).to_s,
|
227
|
+
details: extra_keys.join(', ')
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
def check_fail_controversial_keys(options:)
|
232
|
+
on_success_on_failure = options.slice(:on_success, :on_failure)
|
233
|
+
finish_him = options.slice(:finish_him)
|
234
|
+
|
235
|
+
if !on_success_on_failure.empty? && !finish_him.empty?
|
236
|
+
raise Decouplio::Errors::FailControversialKeysError.new(
|
237
|
+
errored_option: on_success_on_failure.merge(finish_him).to_s,
|
238
|
+
details: [on_success_on_failure.keys.join(', '), :finish_him]
|
239
|
+
)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def check_pass_extra_keys(options:)
|
244
|
+
extra_keys = options.keys - PASS_ALLOWED_OPTIONS
|
245
|
+
|
246
|
+
if extra_keys.size.positive?
|
247
|
+
raise Decouplio::Errors::ExtraKeyForPassError.new(
|
248
|
+
errored_option: options.slice(*extra_keys).to_s,
|
249
|
+
details: extra_keys.join(', ')
|
250
|
+
)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def check_octo_extra_keys(options:)
|
255
|
+
extra_keys = options.keys - OCTO_ALLOWED_OPTIONS
|
256
|
+
|
257
|
+
if extra_keys.size.positive?
|
258
|
+
raise Decouplio::Errors::ExtraKeyForOctoError.new(
|
259
|
+
errored_option: options.slice(*extra_keys).to_s,
|
260
|
+
details: extra_keys.join(', ')
|
261
|
+
)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def check_wrap_extra_keys(options:)
|
266
|
+
extra_keys = options.keys - WRAP_ALLOWED_OPTIONS
|
267
|
+
|
268
|
+
if extra_keys.size.positive?
|
269
|
+
raise Decouplio::Errors::ExtraKeyForWrapError.new(
|
270
|
+
errored_option: options.slice(*extra_keys).to_s
|
271
|
+
)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def check_wrap_controversial_keys(options:)
|
276
|
+
on_success_on_failure = options.slice(:on_success, :on_failure)
|
277
|
+
finish_him = options.slice(:finish_him)
|
278
|
+
|
279
|
+
if !on_success_on_failure.empty? && !finish_him.empty?
|
280
|
+
raise Decouplio::Errors::WrapControversialKeysError.new(
|
281
|
+
errored_option: on_success_on_failure.merge(finish_him).to_s,
|
282
|
+
details: [on_success_on_failure.keys.join(', '), :finish_him]
|
283
|
+
)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def check_octo_palps(hash_case:)
|
288
|
+
hash_casse_palps = hash_case.map { |_octo_key, hash| hash[:palp] }.compact
|
289
|
+
undefined_palps = hash_casse_palps - @palps.keys
|
290
|
+
|
291
|
+
return if undefined_palps.empty?
|
292
|
+
|
293
|
+
errored_options = hash_case.select do |_key, val|
|
294
|
+
undefined_palps.include?(val[:palp])
|
295
|
+
end
|
296
|
+
errored_options = errored_options.map do |key, val|
|
297
|
+
"\"on :#{key}, palp: :#{val[:palp]}\""
|
298
|
+
end
|
299
|
+
|
300
|
+
raise Decouplio::Errors::PalpIsNotDefinedError.new(
|
301
|
+
errored_option: errored_options,
|
302
|
+
details: undefined_palps
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
306
|
+
def check_octo_required_keys(options:)
|
307
|
+
return if (OCTO_REQUIRED_KEYS - options.keys).size.zero?
|
308
|
+
|
309
|
+
raise Decouplio::Errors::RequiredOptionsIsMissingForOctoError.new(
|
310
|
+
details: OCTO_REQUIRED_KEYS.join(', ')
|
311
|
+
)
|
312
|
+
end
|
313
|
+
|
314
|
+
def check_step_finish_him(options:)
|
315
|
+
finish_him_value = options.dig(:finish_him)
|
316
|
+
|
317
|
+
return unless finish_him_value && options.key?(:finish_him)
|
318
|
+
|
319
|
+
unless ALLOWED_STEP_FINISH_HIM_VALUES.include?(finish_him_value)
|
320
|
+
raise Decouplio::Errors::StepFinishHimError.new(
|
321
|
+
errored_option: options.slice(:finish_him).to_s,
|
322
|
+
details: finish_him_value
|
323
|
+
)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def check_fail_finish_him(options:)
|
328
|
+
finish_him_value = options.dig(:finish_him)
|
329
|
+
|
330
|
+
return unless options.key?(:finish_him)
|
331
|
+
|
332
|
+
return if ALLOWED_FAIL_FINISH_HIM_VALUES.include?(finish_him_value)
|
333
|
+
|
334
|
+
raise Decouplio::Errors::FailFinishHimError.new(
|
335
|
+
errored_option: options.slice(:finish_him).to_s,
|
336
|
+
details: finish_him_value
|
337
|
+
)
|
338
|
+
end
|
339
|
+
|
340
|
+
def check_pass_finish_him(options:)
|
341
|
+
finish_him_value = options.dig(:finish_him)
|
342
|
+
|
343
|
+
return unless finish_him_value && options.key?(:finish_him)
|
344
|
+
|
345
|
+
unless ALLOWED_PASS_FINISH_HIM_VALUES.include?(finish_him_value)
|
346
|
+
raise Decouplio::Errors::PassFinishHimError.new(
|
347
|
+
errored_option: options.slice(:finish_him).to_s,
|
348
|
+
details: finish_him_value
|
349
|
+
)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def check_wrap_finish_him(options:)
|
354
|
+
finish_him_value = options.dig(:finish_him)
|
355
|
+
|
356
|
+
return unless finish_him_value && options.key?(:finish_him)
|
357
|
+
|
358
|
+
unless ALLOWED_WRAP_FINISH_HIM_VALUES.include?(finish_him_value)
|
359
|
+
raise Decouplio::Errors::WrapFinishHimError.new(
|
360
|
+
errored_option: options.slice(:finish_him).to_s,
|
361
|
+
details: finish_him_value
|
362
|
+
)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def check_wrap_klass_method_presence(options:)
|
367
|
+
klass_method_options = options.slice(:klass, :method)
|
368
|
+
klass_method_options_size = klass_method_options.size
|
369
|
+
|
370
|
+
return if klass_method_options_size.zero? || klass_method_options_size == 2
|
371
|
+
|
372
|
+
raise Decouplio::Errors::WrapKlassMethodError.new(
|
373
|
+
errored_option: klass_method_options.to_s
|
374
|
+
)
|
375
|
+
end
|
376
|
+
|
377
|
+
def check_wrap_name(name:)
|
378
|
+
return if name.is_a?(Symbol)
|
379
|
+
|
380
|
+
raise Decouplio::Errors::InvalidWrapNameError
|
381
|
+
end
|
382
|
+
|
383
|
+
def check_resq_extra_keys(options:)
|
384
|
+
extra_options = options[:handler_hash].values.select do |option|
|
385
|
+
RESQ_NOT_ALLOWED_OPTIONS.include?(option)
|
386
|
+
end
|
387
|
+
|
388
|
+
return if extra_options.empty?
|
389
|
+
|
390
|
+
raise Decouplio::Errors::ExtraKeyForResqError.new(
|
391
|
+
errored_option: extra_options.join(', ').to_s,
|
392
|
+
details: extra_options.join(', ').to_s
|
393
|
+
)
|
394
|
+
end
|
395
|
+
|
396
|
+
def check_resq_handler_method_is_a_symbol(options:)
|
397
|
+
options[:handler_hash].values.uniq.each do |handler_method|
|
398
|
+
next if handler_method.is_a?(Symbol)
|
399
|
+
|
400
|
+
raise Decouplio::Errors::ResqHandlerMethodError.new(
|
401
|
+
errored_option: handler_method.to_s
|
402
|
+
)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def check_resq_error_classes(options:)
|
407
|
+
options[:handler_hash].each_key do |error_class|
|
408
|
+
next if error_class.is_a?(Class)
|
409
|
+
|
410
|
+
raise Decouplio::Errors::ResqErrorClassError.new(
|
411
|
+
errored_option: error_class.to_s,
|
412
|
+
details: options[:handler_hash][error_class].to_s
|
413
|
+
)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def check_resq_exception_classes_inheritance(options:)
|
418
|
+
options[:handler_hash].each_key do |klass|
|
419
|
+
next if klass < Exception
|
420
|
+
|
421
|
+
raise Decouplio::Errors::InvalidErrorClassError.new(
|
422
|
+
errored_option: klass.to_s,
|
423
|
+
details: klass.to_s
|
424
|
+
)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def extract_step_names(flow:)
|
429
|
+
flow.to_h do |_step_id, stp|
|
430
|
+
[stp[:name], stp[:type]]
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
OPTIONS_TO_FILTER = %i[
|
435
|
+
step_id
|
436
|
+
flow
|
437
|
+
name
|
438
|
+
type
|
439
|
+
hash_case
|
440
|
+
wrap_flow
|
441
|
+
step_to_resq
|
442
|
+
].freeze
|
443
|
+
|
444
|
+
# *************************************************
|
445
|
+
# STEP
|
446
|
+
# *************************************************
|
447
|
+
|
448
|
+
STEP_CHECK_METHOD_EXISTENCE_OPTIONS = %i[
|
449
|
+
on_success
|
450
|
+
on_failure
|
451
|
+
if
|
452
|
+
unless
|
453
|
+
].freeze
|
454
|
+
STEP_CHECK_STEP_PRESENCE = %i[
|
455
|
+
on_success
|
456
|
+
on_failure
|
457
|
+
].freeze
|
458
|
+
STEP_ALLOWED_OPTIONS = %i[
|
459
|
+
on_success
|
460
|
+
on_failure
|
461
|
+
finish_him
|
462
|
+
if
|
463
|
+
unless
|
464
|
+
action
|
465
|
+
].freeze
|
466
|
+
ALLOWED_STEP_FINISH_HIM_VALUES = %i[
|
467
|
+
on_success
|
468
|
+
on_failure
|
469
|
+
].freeze
|
470
|
+
|
471
|
+
# *************************************************
|
472
|
+
# FAIL
|
473
|
+
# *************************************************
|
474
|
+
|
475
|
+
FAIL_CHECK_METHOD_EXISTENCE_OPTIONS = %i[
|
476
|
+
if
|
477
|
+
unless
|
478
|
+
].freeze
|
479
|
+
FAIL_ALLOWED_OPTIONS = %i[
|
480
|
+
on_success
|
481
|
+
on_failure
|
482
|
+
finish_him
|
483
|
+
if
|
484
|
+
unless
|
485
|
+
action
|
486
|
+
].freeze
|
487
|
+
ALLOWED_FAIL_FINISH_HIM_VALUES = [true, :on_success, :on_failure].freeze
|
488
|
+
|
489
|
+
# *************************************************
|
490
|
+
# PASS
|
491
|
+
# *************************************************
|
492
|
+
|
493
|
+
PASS_ALLOWED_OPTIONS = %i[
|
494
|
+
finish_him
|
495
|
+
if
|
496
|
+
unless
|
497
|
+
action
|
498
|
+
].freeze
|
499
|
+
|
500
|
+
PASS_CHECK_METHOD_EXISTENCE_OPTIONS = %i[
|
501
|
+
if
|
502
|
+
unless
|
503
|
+
].freeze
|
504
|
+
ALLOWED_PASS_FINISH_HIM_VALUES = [true].freeze
|
505
|
+
|
506
|
+
# *************************************************
|
507
|
+
# OCTO
|
508
|
+
# *************************************************
|
509
|
+
|
510
|
+
OCTO_ALLOWED_OPTIONS = %i[
|
511
|
+
ctx_key
|
512
|
+
if
|
513
|
+
unless
|
514
|
+
].freeze
|
515
|
+
OCTO_CHECK_METHOD_EXISTENCE_OPTIONS = %i[
|
516
|
+
if
|
517
|
+
unless
|
518
|
+
].freeze
|
519
|
+
OCTO_REQUIRED_KEYS = %i[
|
520
|
+
ctx_key
|
521
|
+
].freeze
|
522
|
+
|
523
|
+
# *************************************************
|
524
|
+
# WRAP
|
525
|
+
# *************************************************
|
526
|
+
|
527
|
+
WRAP_CHECK_METHOD_EXISTENCE_OPTIONS = %i[
|
528
|
+
on_success
|
529
|
+
on_failure
|
530
|
+
if
|
531
|
+
unless
|
532
|
+
].freeze
|
533
|
+
WRAP_CHECK_STEP_PRESENCE = %i[
|
534
|
+
on_success
|
535
|
+
on_failure
|
536
|
+
].freeze
|
537
|
+
WRAP_ALLOWED_OPTIONS = %i[
|
538
|
+
on_success
|
539
|
+
on_failure
|
540
|
+
finish_him
|
541
|
+
if
|
542
|
+
unless
|
543
|
+
klass
|
544
|
+
method
|
545
|
+
wrap_block
|
546
|
+
].freeze
|
547
|
+
ALLOWED_WRAP_FINISH_HIM_VALUES = %i[
|
548
|
+
on_success
|
549
|
+
on_failure
|
550
|
+
].freeze
|
551
|
+
|
552
|
+
# *************************************************
|
553
|
+
# RESQ
|
554
|
+
# *************************************************
|
555
|
+
|
556
|
+
RESQ_NOT_ALLOWED_OPTIONS = %i[
|
557
|
+
on_success
|
558
|
+
on_failure
|
559
|
+
finish_him
|
560
|
+
if
|
561
|
+
unless
|
562
|
+
klass
|
563
|
+
method
|
564
|
+
].freeze
|
565
|
+
end
|
566
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decouplio
|
4
|
+
class Processor
|
5
|
+
class << self
|
6
|
+
def call(first_step:, steps_pool:, steps_flow:, instance:)
|
7
|
+
process(first_step, instance, steps_pool, steps_flow)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def process(next_step_name, instance, steps_pool, steps_flow)
|
13
|
+
while next_step_name
|
14
|
+
result = steps_pool[next_step_name].process(instance: instance)
|
15
|
+
next_step_name = steps_flow[next_step_name][result]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_step'
|
4
|
+
|
5
|
+
module Decouplio
|
6
|
+
module Steps
|
7
|
+
class BaseResq < BaseStep
|
8
|
+
def initialize(handler_hash:, step_to_resq:)
|
9
|
+
super()
|
10
|
+
@handler_hash = handler_hash
|
11
|
+
@step_to_resq = step_to_resq
|
12
|
+
end
|
13
|
+
|
14
|
+
def process(instance:)
|
15
|
+
result = @step_to_resq.process(instance: instance)
|
16
|
+
rescue *@handler_hash.keys => e
|
17
|
+
handler_method = @handler_hash[e.class]
|
18
|
+
|
19
|
+
raise e unless handler_method
|
20
|
+
|
21
|
+
instance.append_railway_flow(handler_method)
|
22
|
+
instance.public_send(handler_method, e, **instance.ctx)
|
23
|
+
|
24
|
+
instance.fail_action
|
25
|
+
Decouplio::Const::Results::ERROR
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../const/results'
|
4
|
+
|
5
|
+
module Decouplio
|
6
|
+
module Steps
|
7
|
+
class BaseStep
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
def process(*)
|
11
|
+
raise NotImplementedError,
|
12
|
+
'Please implement process method'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_step'
|
4
|
+
|
5
|
+
module Decouplio
|
6
|
+
module Steps
|
7
|
+
class Doby < Decouplio::Steps::BaseStep
|
8
|
+
def initialize(name:, doby_class:, doby_options:)
|
9
|
+
super()
|
10
|
+
@name = name
|
11
|
+
@doby_class = doby_class
|
12
|
+
@doby_options = doby_options
|
13
|
+
end
|
14
|
+
|
15
|
+
def process(instance:)
|
16
|
+
instance.append_railway_flow(@name)
|
17
|
+
result = @doby_class.call(ctx: instance.ctx, **@doby_options)
|
18
|
+
resolve(result: result, instance: instance)
|
19
|
+
end
|
20
|
+
|
21
|
+
def resolve(result:, instance:)
|
22
|
+
if result
|
23
|
+
instance.pass_action
|
24
|
+
Decouplio::Const::Results::PASS
|
25
|
+
else
|
26
|
+
instance.fail_action
|
27
|
+
Decouplio::Const::Results::FAIL
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|