decouplio 1.0.0alpha7 → 1.0.0rc

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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +313 -15
  3. data/decouplio.gemspec +8 -2
  4. data/lib/decouplio/action.rb +34 -74
  5. data/lib/decouplio/action_state_printer.rb +34 -0
  6. data/lib/decouplio/const/flows.rb +59 -0
  7. data/lib/decouplio/const/reserved_methods.rb +6 -13
  8. data/lib/decouplio/const/types.rb +1 -165
  9. data/lib/decouplio/const/validations/common.rb +10 -0
  10. data/lib/decouplio/const/validations/octo.rb +16 -0
  11. data/lib/decouplio/const/validations/resq.rb +12 -1
  12. data/lib/decouplio/ctx.rb +13 -0
  13. data/lib/decouplio/default_meta_store.rb +37 -0
  14. data/lib/decouplio/errors/action_class_error.rb +0 -3
  15. data/lib/decouplio/errors/base_error.rb +0 -3
  16. data/lib/decouplio/errors/execution_error.rb +0 -2
  17. data/lib/decouplio/errors/extra_key_for_pass_error.rb +0 -3
  18. data/lib/decouplio/errors/fail_can_not_be_first_step_error.rb +0 -3
  19. data/lib/decouplio/errors/fail_controversial_keys_error.rb +0 -3
  20. data/lib/decouplio/errors/fail_finish_him_error.rb +0 -3
  21. data/lib/decouplio/errors/invalid_error_class_error.rb +0 -3
  22. data/lib/decouplio/errors/invalid_options_for_resq_step.rb +18 -0
  23. data/lib/decouplio/errors/invalid_wrap_name_error.rb +0 -3
  24. data/lib/decouplio/errors/logic_is_not_defined_error.rb +0 -3
  25. data/lib/decouplio/errors/logic_redefinition_error.rb +0 -3
  26. data/lib/decouplio/errors/octo_block_is_not_defined_error.rb +0 -3
  27. data/lib/decouplio/errors/octo_case_is_not_defined_error.rb +19 -0
  28. data/lib/decouplio/errors/octo_controversial_keys_error.rb +0 -3
  29. data/lib/decouplio/errors/{error_store_error.rb → octo_finish_him_is_not_allowed_error.rb} +2 -4
  30. data/lib/decouplio/errors/options_validation_error.rb +13 -1
  31. data/lib/decouplio/errors/palp_block_is_not_defined_error.rb +0 -3
  32. data/lib/decouplio/errors/palp_validation_error.rb +0 -3
  33. data/lib/decouplio/errors/pass_controversial_keys_error.rb +0 -3
  34. data/lib/decouplio/errors/pass_finish_him_error.rb +0 -3
  35. data/lib/decouplio/errors/required_options_is_missing_for_octo_error.rb +0 -3
  36. data/lib/decouplio/errors/resq_definition_error.rb +0 -3
  37. data/lib/decouplio/errors/resq_error_class_error.rb +0 -3
  38. data/lib/decouplio/errors/resq_handler_method_error.rb +0 -3
  39. data/lib/decouplio/errors/step_controversial_keys_error.rb +0 -3
  40. data/lib/decouplio/errors/step_definition_error.rb +17 -0
  41. data/lib/decouplio/errors/step_finish_him_error.rb +0 -3
  42. data/lib/decouplio/errors/step_is_not_defined_for_fail_error.rb +0 -3
  43. data/lib/decouplio/errors/step_is_not_defined_for_pass_error.rb +0 -4
  44. data/lib/decouplio/errors/step_is_not_defined_for_step_error.rb +0 -4
  45. data/lib/decouplio/errors/step_is_not_defined_for_wrap_error.rb +0 -3
  46. data/lib/decouplio/errors/step_name_error.rb +0 -3
  47. data/lib/decouplio/errors/wrap_block_is_not_defined_error.rb +0 -3
  48. data/lib/decouplio/errors/wrap_controversial_keys_error.rb +0 -3
  49. data/lib/decouplio/errors/wrap_finish_him_error.rb +0 -3
  50. data/lib/decouplio/errors/wrap_klass_method_error.rb +0 -3
  51. data/lib/decouplio/graph.rb +9 -0
  52. data/lib/decouplio/logic_dsl.rb +337 -107
  53. data/lib/decouplio/new_flow.rb +283 -0
  54. data/lib/decouplio/octo_hash_case.rb +20 -5
  55. data/lib/decouplio/octo_options_validator.rb +10 -64
  56. data/lib/decouplio/step_validator.rb +200 -0
  57. data/lib/decouplio/steps/base_condition.rb +21 -0
  58. data/lib/decouplio/steps/base_if_condition.rb +11 -0
  59. data/lib/decouplio/steps/base_inner_action.rb +42 -0
  60. data/lib/decouplio/steps/base_octo.rb +26 -0
  61. data/lib/decouplio/steps/base_resq.rb +25 -28
  62. data/lib/decouplio/steps/base_resq_with_mapping.rb +34 -0
  63. data/lib/decouplio/steps/base_service_step.rb +39 -0
  64. data/lib/decouplio/steps/base_step.rb +33 -6
  65. data/lib/decouplio/steps/base_unless_condition.rb +11 -0
  66. data/lib/decouplio/steps/base_wrap.rb +27 -0
  67. data/lib/decouplio/steps/fail.rb +1 -28
  68. data/lib/decouplio/steps/if_condition_fail.rb +1 -21
  69. data/lib/decouplio/steps/if_condition_pass.rb +1 -19
  70. data/lib/decouplio/steps/inner_action_fail.rb +1 -33
  71. data/lib/decouplio/steps/inner_action_pass.rb +12 -30
  72. data/lib/decouplio/steps/inner_action_step.rb +1 -33
  73. data/lib/decouplio/steps/octo_by_key.rb +31 -0
  74. data/lib/decouplio/steps/octo_by_method.rb +31 -0
  75. data/lib/decouplio/steps/pass.rb +5 -26
  76. data/lib/decouplio/steps/resq_fail.rb +0 -2
  77. data/lib/decouplio/steps/resq_pass.rb +1 -3
  78. data/lib/decouplio/steps/resq_with_mapping_fail.rb +8 -0
  79. data/lib/decouplio/steps/resq_with_mapping_pass.rb +8 -0
  80. data/lib/decouplio/steps/service_as_fail.rb +8 -0
  81. data/lib/decouplio/steps/service_as_pass.rb +16 -0
  82. data/lib/decouplio/steps/service_as_step.rb +8 -0
  83. data/lib/decouplio/steps/step.rb +0 -24
  84. data/lib/decouplio/steps/unless_condition_fail.rb +1 -21
  85. data/lib/decouplio/steps/unless_condition_pass.rb +1 -19
  86. data/lib/decouplio/steps/wrap.rb +25 -37
  87. data/lib/decouplio/steps/wrap_with_class.rb +43 -0
  88. data/lib/decouplio/steps/wrap_with_class_method.rb +45 -0
  89. data/lib/decouplio/utils/prepare_resq_mappings.rb +17 -0
  90. data/lib/decouplio/version.rb +1 -1
  91. data/lib/decouplio.rb +93 -0
  92. metadata +32 -55
  93. data/.circleci/config.yml +0 -63
  94. data/.dockerignore +0 -12
  95. data/.gitignore +0 -13
  96. data/.rspec +0 -3
  97. data/.rubocop.yml +0 -116
  98. data/.rubocop_todo.yml +0 -147
  99. data/.ruby-version +0 -1
  100. data/.vscode/settings.json +0 -3
  101. data/Dockerfile +0 -12
  102. data/Gemfile +0 -8
  103. data/benchmarks/.ruby-version +0 -1
  104. data/benchmarks/Dockerfile +0 -12
  105. data/benchmarks/Gemfile +0 -12
  106. data/benchmarks/multi_step_benchmark.rb +0 -336
  107. data/benchmarks/single_step_benchmark.rb +0 -159
  108. data/bin/console +0 -15
  109. data/bin/setup +0 -8
  110. data/docker-compose.yml +0 -29
  111. data/lib/decouplio/composer.rb +0 -691
  112. data/lib/decouplio/const/colors.rb +0 -25
  113. data/lib/decouplio/const/doby_aide_options.rb +0 -16
  114. data/lib/decouplio/const/results.rb +0 -15
  115. data/lib/decouplio/const/step_options.rb +0 -16
  116. data/lib/decouplio/const/validations/aide.rb +0 -38
  117. data/lib/decouplio/const/validations/doby.rb +0 -36
  118. data/lib/decouplio/default_error_handler.rb +0 -39
  119. data/lib/decouplio/errors/aide_can_not_be_first_step_error.rb +0 -18
  120. data/lib/decouplio/errors/aide_controversial_keys_error.rb +0 -26
  121. data/lib/decouplio/errors/aide_finish_him_error.rb +0 -26
  122. data/lib/decouplio/errors/doby_controversial_keys_error.rb +0 -26
  123. data/lib/decouplio/errors/doby_finish_him_error.rb +0 -26
  124. data/lib/decouplio/errors/extra_key_for_fail_error.rb +0 -26
  125. data/lib/decouplio/errors/extra_key_for_octo_error.rb +0 -26
  126. data/lib/decouplio/errors/extra_key_for_resq_error.rb +0 -29
  127. data/lib/decouplio/errors/extra_key_for_step_error.rb +0 -23
  128. data/lib/decouplio/errors/extra_key_for_wrap_error.rb +0 -23
  129. data/lib/decouplio/errors/palp_is_not_defined_error.rb +0 -26
  130. data/lib/decouplio/errors/step_is_not_defined_for_aide_error.rb +0 -26
  131. data/lib/decouplio/errors/step_is_not_defined_for_doby_error.rb +0 -27
  132. data/lib/decouplio/flow.rb +0 -17
  133. data/lib/decouplio/options_validator.rb +0 -716
  134. data/lib/decouplio/processor.rb +0 -20
  135. data/lib/decouplio/steps/aide.rb +0 -37
  136. data/lib/decouplio/steps/doby.rb +0 -37
  137. data/lib/decouplio/steps/octo.rb +0 -27
  138. data/lib/decouplio/steps/service_fail.rb +0 -41
  139. data/lib/decouplio/steps/service_pass.rb +0 -41
  140. data/lib/decouplio/steps/service_step.rb +0 -41
  141. data/lib/decouplio/steps/shared/fail_resolver.rb +0 -40
  142. data/lib/decouplio/steps/shared/step_resolver.rb +0 -43
  143. data/lib/decouplio/validators/condition.rb +0 -59
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decouplio
4
+ class NewFlow
5
+ def self.call(logic)
6
+ logic_container_raw_data = Class.new(Decouplio::LogicDsl, &logic)
7
+
8
+ steps = logic_container_raw_data.steps
9
+
10
+ compose_steps(steps.delete_at(0), steps)
11
+ end
12
+
13
+ def self.compose_steps(stp, steps)
14
+ return stp if stp.nil?
15
+
16
+ Decouplio::StepValidator.call(stp, steps)
17
+
18
+ if stp.is_a?(Decouplio::Steps::BaseOcto)
19
+ next_success_step, success_resolver = compose_flow_direction(stp, steps, :success)
20
+ next_failure_step, failure_resolver = compose_flow_direction(stp, steps, :failure)
21
+ next_on_error, on_error_resolver = compose_flow_direction(stp, steps, :error)
22
+
23
+ stp._add_next_steps([next_success_step, next_failure_step, next_on_error])
24
+ stp._add_resolvers([success_resolver, failure_resolver, on_error_resolver])
25
+
26
+ compose_octo(stp, steps)
27
+ elsif Decouplio::Const::Flows::RESQ_CLASSES.include?(stp.class)
28
+ next_success_step, success_resolver = compose_flow_direction(stp.step_to_resq, steps, :success)
29
+ next_failure_step, failure_resolver = compose_flow_direction(stp.step_to_resq, steps, :failure)
30
+ next_on_error, on_error_resolver = compose_flow_direction(stp.step_to_resq, steps, :error)
31
+
32
+ stp.step_to_resq._add_next_steps([next_success_step, next_failure_step, next_on_error])
33
+ stp.step_to_resq._add_resolvers([success_resolver, failure_resolver, on_error_resolver])
34
+
35
+ compose_wrap(stp.step_to_resq) if stp.step_to_resq.is_a?(Decouplio::Steps::BaseWrap)
36
+
37
+ # next_success_step, success_resolver = compose_flow_direction(stp.step_to_resq, steps, :success)
38
+ # next_failure_step, failure_resolver = compose_flow_direction(stp.step_to_resq, steps, :failure)
39
+ # next_on_error, on_error_resolver = compose_flow_direction(stp.step_to_resq, steps, :error)
40
+
41
+ # stp.step_to_resq._add_next_steps([next_success_step, next_failure_step, next_on_error])
42
+ # stp.step_to_resq._add_resolvers([success_resolver, failure_resolver, on_error_resolver])
43
+ elsif stp.is_a?(Decouplio::Steps::BaseWrap)
44
+ compose_wrap(stp)
45
+ compose_step(stp, steps)
46
+ else
47
+ compose_step(stp, steps)
48
+ end
49
+
50
+ next_step_to_process = steps.delete_at(0)
51
+ compose_steps(next_step_to_process, steps)
52
+ stp
53
+ end
54
+
55
+ def self.compose_wrap(stp)
56
+ wrap_first_step = call(stp.wrap_block)
57
+ stp._add_wrap_first_step(wrap_first_step)
58
+ end
59
+
60
+ def self.compose_octo(stp, steps)
61
+ linked_hash_case = stp.hash_case.to_h do |key, octo_step|
62
+ if octo_step.on_success.nil?
63
+ next_success_step = stp.on_success
64
+ success_resolver = stp.on_success_resolver
65
+ else
66
+ next_success_step, success_resolver = compose_flow_direction(octo_step, steps, :success)
67
+ end
68
+
69
+ if octo_step.on_failure.nil?
70
+ next_failure_step = stp.on_failure
71
+ failure_resolver = stp.on_failure_resolver
72
+ else
73
+ next_failure_step, failure_resolver = compose_flow_direction(octo_step, steps, :failure)
74
+ end
75
+
76
+ if octo_step.on_error.nil?
77
+ next_on_error = stp.on_error
78
+ on_error_resolver = stp.on_error_resolver
79
+ else
80
+ next_on_error, on_error_resolver = compose_flow_direction(octo_step, steps, :error)
81
+ end
82
+
83
+ compose_wrap(octo_step)
84
+
85
+ octo_step._add_next_steps(
86
+ [
87
+ next_success_step,
88
+ next_failure_step,
89
+ next_on_error
90
+ ]
91
+ )
92
+ octo_step._add_resolvers(
93
+ [
94
+ success_resolver,
95
+ failure_resolver,
96
+ on_error_resolver
97
+ ]
98
+ )
99
+
100
+ if stp.resq
101
+ octo_resq_step = stp.resq.clone
102
+ octo_resq_step._add_step_to_resq(octo_step)
103
+ [key, octo_resq_step]
104
+ else
105
+ [key, octo_step]
106
+ end
107
+ end
108
+
109
+ stp._add_octo_next_steps(linked_hash_case)
110
+ end
111
+
112
+ def self.compose_step(stp, steps)
113
+ next_success_step, success_resolver = compose_flow_direction(stp, steps, :success)
114
+ next_failure_step, failure_resolver = compose_flow_direction(stp, steps, :failure)
115
+
116
+ stp._add_next_steps([next_success_step, next_failure_step])
117
+ stp._add_resolvers([success_resolver, failure_resolver])
118
+ end
119
+
120
+ def self.compose_flow_direction(stp, steps, type)
121
+ case stp
122
+ when Decouplio::Steps::Step,
123
+ Decouplio::Steps::InnerActionStep,
124
+ Decouplio::Steps::ServiceAsStep
125
+ compose_step_outcome("for_step_#{type}".to_sym, stp, steps)
126
+ when Decouplio::Steps::Fail,
127
+ Decouplio::Steps::InnerActionFail,
128
+ Decouplio::Steps::ServiceAsFail
129
+ compose_step_outcome("for_fail_#{type}".to_sym, stp, steps)
130
+ when Decouplio::Steps::Pass,
131
+ Decouplio::Steps::InnerActionPass,
132
+ Decouplio::Steps::ServiceAsPass
133
+ compose_step_outcome("for_pass_#{type}".to_sym, stp, steps)
134
+ when Decouplio::Steps::IfConditionPass
135
+ compose_condition_outcome("for_if_pass_#{type}".to_sym, stp, steps)
136
+ when Decouplio::Steps::IfConditionFail
137
+ compose_condition_outcome("for_if_fail_#{type}".to_sym, stp, steps)
138
+ when Decouplio::Steps::UnlessConditionPass
139
+ compose_condition_outcome("for_unless_pass_#{type}".to_sym, stp, steps)
140
+ when Decouplio::Steps::UnlessConditionFail
141
+ compose_condition_outcome("for_unless_fail_#{type}".to_sym, stp, steps)
142
+ when Decouplio::Steps::Wrap,
143
+ Decouplio::Steps::WrapWithClass,
144
+ Decouplio::Steps::WrapWithClassMethod
145
+ compose_step_outcome("for_wrap_#{type}".to_sym, stp, steps)
146
+ when Decouplio::Steps::BaseOcto
147
+ compose_step_outcome("for_octo_#{type}".to_sym, stp, steps)
148
+ end
149
+ end
150
+
151
+ def self.compose_step_outcome(flow, stp, steps)
152
+ case flow
153
+ when :for_fail_success
154
+ return [nil, false] if stp.finish_him == true
155
+ return [nil, false] if stp.finish_him == :on_success
156
+ return [next_failure_step(steps), false] if stp.on_success.nil?
157
+ return [nil, false] if stp.on_success == :finish_him
158
+ return [next_success_step(steps), true] if stp.on_success == :PASS
159
+ return [next_failure_step(steps), false] if stp.on_success == :FAIL
160
+
161
+ [next_step(stp.on_success, steps), false]
162
+ when :for_fail_failure
163
+ return [nil, false] if stp.finish_him == true
164
+ return [nil, false] if stp.finish_him == :on_failure
165
+ return [next_failure_step(steps), false] if stp.on_failure.nil?
166
+ return [nil, false] if stp.on_failure == :finish_him
167
+ return [next_success_step(steps), true] if stp.on_failure == :PASS
168
+ return [next_failure_step(steps), false] if stp.on_failure == :FAIL
169
+
170
+ [next_step(stp.on_failure, steps), false]
171
+ when :for_pass_success
172
+ return [nil, true] if stp.finish_him == true
173
+
174
+ [next_success_step(steps), true]
175
+ when :for_pass_failure
176
+ [nil, nil]
177
+ when :for_step_success, :for_wrap_success, :for_octo_success
178
+ return [nil, true] if stp.finish_him == :on_success
179
+ return [next_success_step(steps), true] if stp.on_success.nil?
180
+ return [nil, true] if stp.on_success == :finish_him
181
+ return [next_success_step(steps), true] if stp.on_success == :PASS
182
+ return [next_failure_step(steps), false] if stp.on_success == :FAIL
183
+
184
+ [next_step(stp.on_success, steps), true]
185
+ when :for_step_failure, :for_wrap_failure, :for_octo_failure
186
+ return [nil, false] if stp.finish_him == :on_failure
187
+ return [next_failure_step(steps), false] if stp.on_failure.nil?
188
+ return [nil, false] if stp.on_failure == :finish_him
189
+ return [next_success_step(steps), true] if stp.on_failure == :PASS
190
+ return [next_failure_step(steps), false] if stp.on_failure == :FAIL
191
+
192
+ [next_step(stp.on_failure, steps), false]
193
+ when :for_step_error,
194
+ :for_fail_error,
195
+ :for_pass_error,
196
+ :for_octo_error,
197
+ :for_wrap_error
198
+ return [nil, false] if stp.finish_him == :on_error
199
+ return [next_failure_step(steps), false] if stp.on_error.nil?
200
+ return [nil, false] if stp.on_error == :finish_him
201
+ return [next_success_step(steps), true] if stp.on_error == :PASS
202
+ return [next_failure_step(steps), false] if stp.on_error == :FAIL
203
+
204
+ [next_step(stp.on_error, steps), false]
205
+ end
206
+ end
207
+
208
+ def self.compose_condition_outcome(flow, _stp, steps)
209
+ case flow
210
+ when :for_if_pass_success, :for_unless_pass_success
211
+ [next_success_step(steps), nil]
212
+ when :for_if_pass_failure, :for_unless_pass_failure
213
+ [next_success_step(steps[1..]), nil]
214
+ when :for_if_fail_success, :for_unless_fail_success
215
+ [next_failure_step(steps), nil]
216
+ when :for_if_fail_failure, :for_unless_fail_failure
217
+ [next_failure_step(steps[1..]), nil]
218
+ end
219
+ end
220
+
221
+ def self.next_success_step(steps)
222
+ steps.detect do |flow_step|
223
+ [
224
+ Decouplio::Steps::Step,
225
+ Decouplio::Steps::Pass,
226
+ Decouplio::Steps::IfConditionPass,
227
+ Decouplio::Steps::UnlessConditionPass,
228
+ Decouplio::Steps::OctoByKey,
229
+ Decouplio::Steps::OctoByMethod,
230
+ Decouplio::Steps::InnerActionStep,
231
+ Decouplio::Steps::InnerActionPass,
232
+ Decouplio::Steps::ServiceAsStep,
233
+ Decouplio::Steps::ServiceAsPass,
234
+ Decouplio::Steps::ResqPass,
235
+ Decouplio::Steps::ResqWithMappingPass,
236
+ Decouplio::Steps::Wrap,
237
+ Decouplio::Steps::WrapWithClass,
238
+ Decouplio::Steps::WrapWithClassMethod
239
+ ].include?(flow_step.class)
240
+ end
241
+ end
242
+
243
+ def self.next_failure_step(steps)
244
+ steps.detect do |flow_step|
245
+ [
246
+ Decouplio::Steps::Fail,
247
+ Decouplio::Steps::IfConditionFail,
248
+ Decouplio::Steps::UnlessConditionFail,
249
+ Decouplio::Steps::InnerActionFail,
250
+ Decouplio::Steps::ServiceAsFail,
251
+ Decouplio::Steps::ResqFail,
252
+ Decouplio::Steps::ResqWithMappingFail
253
+ ].include?(flow_step.class)
254
+ end
255
+ end
256
+
257
+ def self.next_step(step_name, steps)
258
+ steps.each_with_index do |flow_step, index|
259
+ if flow_step.name == step_name
260
+ if [
261
+ Decouplio::Steps::IfConditionFail,
262
+ Decouplio::Steps::UnlessConditionFail,
263
+ Decouplio::Steps::IfConditionPass,
264
+ Decouplio::Steps::UnlessConditionPass
265
+ ].include?(steps[index - 1].class)
266
+ return steps[index - 1]
267
+ else
268
+ return flow_step
269
+ end
270
+ end
271
+ end
272
+ raise StandardError, 'Most likely it is a bug, please create an issue here https://github.com/differencialx/decouplio/issues'
273
+ end
274
+
275
+ def self.validate_wrap(logic_container_raw_data)
276
+ logic_container_raw_data.steps.map(&:class).each do |step_class|
277
+ next unless Decouplio::Const::Flows::OCTO_CLASSES.include?(step_class)
278
+
279
+ raise Decouplio::Errors::OctoInsideWrapError
280
+ end
281
+ end
282
+ end
283
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'octo_options_validator'
4
-
5
3
  module Decouplio
6
4
  class OctoHashCase
7
5
  class << self
@@ -16,9 +14,26 @@ module Decouplio
16
14
  @hash_case = {}
17
15
  end
18
16
 
19
- def on(strategy_flow, **options)
20
- validate_options(options)
21
- @hash_case[strategy_flow] = options
17
+ def on(octo_case, stp = nil, **options, &block)
18
+ if stp || block_given?
19
+ validate_options(options)
20
+ on_success = options.delete(:on_success)
21
+ on_failure = options.delete(:on_failure)
22
+ on_error = options.delete(:on_error)
23
+ wrap_block = block_given? ? block : proc { step(stp, **options) }
24
+ @hash_case[octo_case] = Decouplio::Steps::Wrap.new(
25
+ octo_case,
26
+ wrap_block,
27
+ on_success,
28
+ on_failure,
29
+ on_error,
30
+ nil
31
+ )
32
+ else
33
+ raise Decouplio::Errors::OctoCaseIsNotDefinedError.new(
34
+ errored_option: "on :#{octo_case}"
35
+ )
36
+ end
22
37
  end
23
38
 
24
39
  private
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'errors/options_validation_error'
4
-
5
3
  module Decouplio
6
4
  class OctoOptionsValidator
7
5
  def self.call(options:)
@@ -13,77 +11,25 @@ module Decouplio
13
11
  end
14
12
 
15
13
  def call
16
- validate_option_keys
17
- validate_option_count
14
+ validate_options unless @options.empty?
18
15
  end
19
16
 
20
17
  private
21
18
 
22
- def validate_option_keys
23
- extra_options = (@options.keys - ON_ALLOWED_OPTIONS)
24
- return if extra_options.size.zero?
25
-
26
- raise_validation_error(
27
- compose_message(
28
- STRATEGY_ON_ERROR_MESSAGE,
29
- YELLOW,
30
- extra_options,
31
- EXTRA_OPTIONS_NOT_ALLOWED % extra_options,
32
- ON_ALLOWED_OPTIONS,
33
- STRATEGY_MANUAL_URL,
34
- NO_COLOR
35
- )
36
- )
37
- end
19
+ def validate_options
20
+ has_invalid_options = @options.keys.any? { |key| NOT_ALLOWED_OPTIONS.include?(key) }
38
21
 
39
- def validate_option_count
40
- return if @options.keys.size == 1
22
+ return unless has_invalid_options
41
23
 
42
- raise_validation_error(
43
- compose_message(
44
- STRATEGY_ON_ERROR_MESSAGE,
45
- YELLOW,
46
- @options,
47
- ONLY_ONE_OPTION_PER_TIME_IS_ALLOWED,
48
- ON_ALLOWED_OPTIONS,
49
- STRATEGY_MANUAL_URL,
50
- NO_COLOR
51
- )
52
- )
24
+ raise_validation_error
53
25
  end
54
26
 
55
- def raise_validation_error(message)
56
- raise Decouplio::Errors::OptionsValidationError, message
57
- end
58
-
59
- def compose_message(message, *interpolation_params)
60
- message % interpolation_params
27
+ def raise_validation_error
28
+ raise Decouplio::Errors::OptionsValidationError.new(
29
+ errored_option: @options
30
+ )
61
31
  end
62
32
 
63
- ALLOWED_OPTIONS = %i[palp step].freeze
64
- YELLOW = "\033[1;33m"
65
- NO_COLOR = "\033[0m"
66
- STRATEGY_ON_ERROR_MESSAGE = <<~ERROR_MESSAGE
67
- %s
68
- Next options are not allowed for "on":
69
- %s
70
-
71
- Details:
72
- %s
73
-
74
- Allowed options are:
75
- %s
76
-
77
- Please read the manual about allowed options here:
78
- %s
79
- %s
80
- ERROR_MESSAGE
81
- EXTRA_OPTIONS_NOT_ALLOWED = '%s is not allowed for "on"'
82
- ONLY_ONE_OPTION_PER_TIME_IS_ALLOWED = 'Only one option is allowed for "on".'
83
- ON_ALLOWED_OPTIONS = %i[
84
- step
85
- palp
86
- ].freeze
87
- STRATEGY_MANUAL_URL = 'https://stub.strategy.manual.url'
33
+ NOT_ALLOWED_OPTIONS = %i[finish_him if unless].freeze
88
34
  end
89
35
  end
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decouplio
4
+ class StepValidator
5
+ def self.call(stp, steps)
6
+ case stp
7
+ when Decouplio::Steps::Step
8
+ validate_name(stp.name)
9
+ validate_step(stp, steps)
10
+ when Decouplio::Steps::InnerActionStep, Decouplio::Steps::ServiceAsStep
11
+ validate_step(stp, steps)
12
+ when Decouplio::Steps::Fail
13
+ validate_name(stp.name)
14
+ validate_fail(stp, steps)
15
+ when Decouplio::Steps::InnerActionFail, Decouplio::Steps::ServiceAsFail
16
+ validate_fail(stp, steps)
17
+ when Decouplio::Steps::Pass
18
+ validate_name(stp.name)
19
+ validate_pass(stp, steps)
20
+ when Decouplio::Steps::ServiceAsPass, Decouplio::Steps::InnerActionPass
21
+ validate_pass(stp, steps)
22
+ when Decouplio::Steps::Wrap,
23
+ Decouplio::Steps::WrapWithClassMethod
24
+ validate_name(stp.name)
25
+ validate_finish_him(stp, Decouplio::Errors::WrapFinishHimError)
26
+ validate_contraversal_key(stp, Decouplio::Errors::WrapControversialKeysError)
27
+ validate_on_s(stp, steps, Decouplio::Errors::StepIsNotDefinedForWrapError)
28
+ validate_on_f(stp, steps, Decouplio::Errors::StepIsNotDefinedForWrapError)
29
+ validate_on_e(stp, steps, Decouplio::Errors::StepIsNotDefinedForWrapError)
30
+ when Decouplio::Steps::OctoByKey,
31
+ Decouplio::Steps::OctoByMethod
32
+ validate_name(stp.name)
33
+ when Decouplio::Steps::ResqPass,
34
+ Decouplio::Steps::ResqFail
35
+ validate_name(stp.name)
36
+ validate_name(stp.handler_method)
37
+ call(stp.step_to_resq, steps)
38
+ when Decouplio::Steps::ResqWithMappingPass,
39
+ Decouplio::Steps::ResqWithMappingFail
40
+ validate_name(stp.name)
41
+ stp.mappings.each do |class_to_handle, handler_method_name|
42
+ validate_symbol(handler_method_name)
43
+ validate_name(handler_method_name)
44
+ validate_class(class_to_handle, handler_method_name)
45
+ validate_exception_inheritance(class_to_handle)
46
+ end
47
+ call(stp.step_to_resq, steps)
48
+ when Decouplio::Steps::IfConditionPass,
49
+ Decouplio::Steps::IfConditionFail,
50
+ Decouplio::Steps::UnlessConditionPass,
51
+ Decouplio::Steps::UnlessConditionFail
52
+ validate_name(stp.condition_method)
53
+ end
54
+ end
55
+
56
+ def self.validate_step(stp, steps)
57
+ validate_finish_him(stp, Decouplio::Errors::StepFinishHimError)
58
+ validate_contraversal_key(stp, Decouplio::Errors::StepControversialKeysError)
59
+ validate_on_s(stp, steps, Decouplio::Errors::StepIsNotDefinedForStepError)
60
+ validate_on_f(stp, steps, Decouplio::Errors::StepIsNotDefinedForStepError)
61
+ validate_on_e(stp, steps, Decouplio::Errors::StepIsNotDefinedForStepError)
62
+ end
63
+
64
+ def self.validate_fail(stp, steps)
65
+ validate_finish_him_for_fail(stp, Decouplio::Errors::FailFinishHimError)
66
+ validate_contraversal_key(stp, Decouplio::Errors::FailControversialKeysError)
67
+ validate_on_s(stp, steps, Decouplio::Errors::StepIsNotDefinedForFailError)
68
+ validate_on_f(stp, steps, Decouplio::Errors::StepIsNotDefinedForFailError)
69
+ validate_on_e(stp, steps, Decouplio::Errors::StepIsNotDefinedForFailError)
70
+ end
71
+
72
+ def self.validate_pass(stp, steps)
73
+ validate_finish_him_for_pass(stp, Decouplio::Errors::PassFinishHimError)
74
+ validate_contraversal_key(stp, Decouplio::Errors::StepControversialKeysError)
75
+ validate_on_s(stp, steps, Decouplio::Errors::StepIsNotDefinedForPassError)
76
+ validate_on_f(stp, steps, Decouplio::Errors::StepIsNotDefinedForPassError)
77
+ validate_on_e(stp, steps, Decouplio::Errors::StepIsNotDefinedForPassError)
78
+ end
79
+
80
+ def self.validate_class(class_to_handle, handler_method_name)
81
+ return if class_to_handle.is_a?(Class)
82
+
83
+ raise Decouplio::Errors::ResqErrorClassError.new(
84
+ errored_option: class_to_handle,
85
+ details: handler_method_name
86
+ )
87
+ end
88
+
89
+ def self.validate_exception_inheritance(class_to_handle)
90
+ return if class_to_handle < Exception
91
+
92
+ raise Decouplio::Errors::InvalidErrorClassError.new(
93
+ errored_option: class_to_handle,
94
+ details: class_to_handle
95
+ )
96
+ end
97
+
98
+ def self.validate_symbol(stp_name)
99
+ return if stp_name.is_a?(Symbol)
100
+
101
+ raise Decouplio::Errors::ResqHandlerMethodError.new(
102
+ errored_option: stp_name
103
+ )
104
+ end
105
+
106
+ def self.validate_name(stp_name)
107
+ if Decouplio::Const::ReservedMethods::NAMES.include?(stp_name)
108
+ raise Decouplio::Errors::StepNameError.new(
109
+ errored_option: stp_name
110
+ )
111
+ end
112
+
113
+ unless stp_name.is_a?(Symbol) ||
114
+ (
115
+ (stp_name.is_a?(Class) && stp_name < Decouplio::Action) ||
116
+ (stp_name.is_a?(Class) && stp.respond_to?(:call))
117
+ )
118
+ raise Decouplio::Errors::StepDefinitionError.new(
119
+ errored_option: stp_name
120
+ )
121
+ end
122
+ end
123
+
124
+ def self.validate_on_s(stp, steps, exception_class)
125
+ return if [nil, :finish_him, :PASS, :FAIL].include?(stp.on_success)
126
+ return if steps.any? { |s| s.name == stp.on_success }
127
+
128
+ raise exception_class.new(
129
+ errored_option: { on_success: stp.on_success },
130
+ details: stp.on_success
131
+ )
132
+ end
133
+
134
+ def self.validate_on_f(stp, steps, exception_class)
135
+ return if [nil, :finish_him, :PASS, :FAIL].include?(stp.on_failure)
136
+ return if steps.any? { |s| s.name == stp.on_failure }
137
+
138
+ raise exception_class.new(
139
+ errored_option: { on_failure: stp.on_failure },
140
+ details: stp.on_failure
141
+ )
142
+ end
143
+
144
+ def self.validate_on_e(stp, steps, exception_class)
145
+ return if [nil, :finish_him, :PASS, :FAIL].include?(stp.on_error)
146
+ return if steps.any? { |s| s.name == stp.on_error }
147
+
148
+ raise exception_class.new(
149
+ errored_option: { on_error: stp.on_error },
150
+ details: stp.on_error
151
+ )
152
+ end
153
+
154
+ def self.validate_finish_him(stp, exception_class)
155
+ return if [nil, :on_success, :on_failure, :on_error].include?(stp.finish_him)
156
+
157
+ raise exception_class.new(
158
+ errored_option: { finish_him: stp.finish_him },
159
+ details: stp.finish_him
160
+ )
161
+ end
162
+
163
+ def self.validate_finish_him_for_fail(stp, exception_class)
164
+ return if [nil, true, :on_success, :on_failure, :on_error].include?(stp.finish_him)
165
+
166
+ raise exception_class.new(
167
+ errored_option: { finish_him: stp.finish_him },
168
+ details: stp.finish_him
169
+ )
170
+ end
171
+
172
+ def self.validate_finish_him_for_pass(stp, exception_class)
173
+ return if [nil, true, :on_error].include?(stp.finish_him)
174
+
175
+ raise exception_class.new(
176
+ errored_option: { finish_him: stp.finish_him },
177
+ details: stp.finish_him
178
+ )
179
+ end
180
+
181
+ def self.validate_contraversal_key(stp, exception_class)
182
+ if stp.on_success && stp.finish_him
183
+ raise exception_class.new(
184
+ errored_option: { on_success: stp.on_success, finish_him: stp.finish_him },
185
+ details: %i[on_success finish_him]
186
+ )
187
+ elsif stp.on_failure && stp.finish_him
188
+ raise exception_class.new(
189
+ errored_option: { on_failure: stp.on_failure, finish_him: stp.finish_him },
190
+ details: %i[on_failure finish_him]
191
+ )
192
+ elsif stp.on_error && stp.finish_him
193
+ raise exception_class.new(
194
+ errored_option: { on_error: stp.on_error, finish_him: stp.finish_him },
195
+ details: %i[on_error finish_him]
196
+ )
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decouplio
4
+ module Steps
5
+ class BaseCondition
6
+ attr_reader :condition_method
7
+
8
+ alias name condition_method
9
+
10
+ def initialize(condition_method)
11
+ @condition_method = condition_method
12
+ end
13
+
14
+ def _add_next_steps(steps)
15
+ @perform_condition_step, @skip_condition_step = steps
16
+ end
17
+
18
+ def _add_resolvers(_); end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decouplio
4
+ module Steps
5
+ class BaseIfCondition < Decouplio::Steps::BaseCondition
6
+ def process(instance)
7
+ instance.send(@condition_method) ? @perform_condition_step : @skip_condition_step
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decouplio
4
+ module Steps
5
+ class BaseInnerAction
6
+ attr_reader :name, :on_success, :on_failure, :on_error, :finish_him, :on_error_resolver
7
+
8
+ def initialize(name, action_class, on_success, on_failure, on_error, finish_him)
9
+ @name = name
10
+ @action_class = action_class
11
+ @on_success = on_success
12
+ @on_failure = on_failure
13
+ @on_error = on_error
14
+ @finish_him = finish_him
15
+ end
16
+
17
+ def process(instance)
18
+ instance.railway_flow << @name
19
+ result = @action_class.call(
20
+ _parent_meta_store: instance.ms,
21
+ _parent_railway_flow: instance.railway_flow,
22
+ _parent_ctx: instance.ctx
23
+ )
24
+ if result.success?
25
+ instance.success = @on_success_resolver
26
+ @on_success
27
+ else
28
+ instance.success = @on_failure_resolver
29
+ @on_failure
30
+ end
31
+ end
32
+
33
+ def _add_next_steps(steps)
34
+ @on_success, @on_failure, @on_error = steps
35
+ end
36
+
37
+ def _add_resolvers(resolvers)
38
+ @on_success_resolver, @on_failure_resolver = resolvers
39
+ end
40
+ end
41
+ end
42
+ end