cmdx 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +21 -0
  4. data/.cursor/prompts/yardoc.md +13 -0
  5. data/.rubocop.yml +2 -0
  6. data/CHANGELOG.md +29 -3
  7. data/README.md +2 -1
  8. data/docs/ai_prompts.md +269 -195
  9. data/docs/basics/call.md +126 -60
  10. data/docs/basics/chain.md +190 -160
  11. data/docs/basics/context.md +242 -154
  12. data/docs/basics/setup.md +302 -32
  13. data/docs/callbacks.md +382 -119
  14. data/docs/configuration.md +211 -49
  15. data/docs/deprecation.md +245 -0
  16. data/docs/getting_started.md +161 -39
  17. data/docs/internationalization.md +590 -70
  18. data/docs/interruptions/exceptions.md +135 -118
  19. data/docs/interruptions/faults.md +152 -127
  20. data/docs/interruptions/halt.md +134 -80
  21. data/docs/logging.md +183 -120
  22. data/docs/middlewares.md +165 -392
  23. data/docs/outcomes/result.md +140 -112
  24. data/docs/outcomes/states.md +134 -99
  25. data/docs/outcomes/statuses.md +204 -146
  26. data/docs/parameters/coercions.md +251 -289
  27. data/docs/parameters/defaults.md +224 -169
  28. data/docs/parameters/definitions.md +289 -141
  29. data/docs/parameters/namespacing.md +250 -161
  30. data/docs/parameters/validations.md +247 -159
  31. data/docs/testing.md +196 -203
  32. data/docs/workflows.md +146 -101
  33. data/lib/cmdx/.DS_Store +0 -0
  34. data/lib/cmdx/callback.rb +39 -55
  35. data/lib/cmdx/callback_registry.rb +80 -73
  36. data/lib/cmdx/chain.rb +65 -122
  37. data/lib/cmdx/chain_inspector.rb +23 -116
  38. data/lib/cmdx/chain_serializer.rb +34 -146
  39. data/lib/cmdx/coercion.rb +57 -0
  40. data/lib/cmdx/coercion_registry.rb +113 -0
  41. data/lib/cmdx/coercions/array.rb +18 -36
  42. data/lib/cmdx/coercions/big_decimal.rb +21 -33
  43. data/lib/cmdx/coercions/boolean.rb +21 -40
  44. data/lib/cmdx/coercions/complex.rb +18 -31
  45. data/lib/cmdx/coercions/date.rb +20 -39
  46. data/lib/cmdx/coercions/date_time.rb +22 -39
  47. data/lib/cmdx/coercions/float.rb +19 -32
  48. data/lib/cmdx/coercions/hash.rb +22 -41
  49. data/lib/cmdx/coercions/integer.rb +20 -33
  50. data/lib/cmdx/coercions/rational.rb +20 -32
  51. data/lib/cmdx/coercions/string.rb +23 -31
  52. data/lib/cmdx/coercions/time.rb +24 -40
  53. data/lib/cmdx/coercions/virtual.rb +14 -31
  54. data/lib/cmdx/configuration.rb +101 -162
  55. data/lib/cmdx/context.rb +34 -166
  56. data/lib/cmdx/core_ext/hash.rb +42 -67
  57. data/lib/cmdx/core_ext/module.rb +35 -79
  58. data/lib/cmdx/core_ext/object.rb +63 -98
  59. data/lib/cmdx/correlator.rb +59 -154
  60. data/lib/cmdx/error.rb +37 -202
  61. data/lib/cmdx/errors.rb +153 -216
  62. data/lib/cmdx/fault.rb +68 -150
  63. data/lib/cmdx/faults.rb +26 -137
  64. data/lib/cmdx/immutator.rb +22 -110
  65. data/lib/cmdx/lazy_struct.rb +110 -186
  66. data/lib/cmdx/log_formatters/json.rb +14 -40
  67. data/lib/cmdx/log_formatters/key_value.rb +14 -40
  68. data/lib/cmdx/log_formatters/line.rb +14 -48
  69. data/lib/cmdx/log_formatters/logstash.rb +14 -57
  70. data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
  71. data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
  72. data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
  73. data/lib/cmdx/log_formatters/raw.rb +19 -49
  74. data/lib/cmdx/logger.rb +22 -79
  75. data/lib/cmdx/logger_ansi.rb +31 -72
  76. data/lib/cmdx/logger_serializer.rb +74 -103
  77. data/lib/cmdx/middleware.rb +56 -60
  78. data/lib/cmdx/middleware_registry.rb +82 -77
  79. data/lib/cmdx/middlewares/correlate.rb +41 -226
  80. data/lib/cmdx/middlewares/timeout.rb +46 -185
  81. data/lib/cmdx/parameter.rb +167 -183
  82. data/lib/cmdx/parameter_evaluator.rb +231 -0
  83. data/lib/cmdx/parameter_inspector.rb +37 -55
  84. data/lib/cmdx/parameter_registry.rb +65 -84
  85. data/lib/cmdx/parameter_serializer.rb +32 -76
  86. data/lib/cmdx/railtie.rb +24 -107
  87. data/lib/cmdx/result.rb +254 -259
  88. data/lib/cmdx/result_ansi.rb +28 -80
  89. data/lib/cmdx/result_inspector.rb +34 -70
  90. data/lib/cmdx/result_logger.rb +23 -77
  91. data/lib/cmdx/result_serializer.rb +59 -125
  92. data/lib/cmdx/rspec/matchers.rb +28 -0
  93. data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
  94. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
  95. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
  96. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
  97. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
  98. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
  99. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
  100. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
  101. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
  102. data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
  103. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
  104. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
  105. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
  106. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
  107. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
  108. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
  109. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
  110. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
  111. data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
  112. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
  113. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
  114. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
  115. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
  116. data/lib/cmdx/task.rb +336 -427
  117. data/lib/cmdx/task_deprecator.rb +52 -0
  118. data/lib/cmdx/task_processor.rb +246 -0
  119. data/lib/cmdx/task_serializer.rb +34 -69
  120. data/lib/cmdx/utils/ansi_color.rb +13 -89
  121. data/lib/cmdx/utils/log_timestamp.rb +13 -42
  122. data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
  123. data/lib/cmdx/utils/name_affix.rb +21 -71
  124. data/lib/cmdx/validator.rb +57 -0
  125. data/lib/cmdx/validator_registry.rb +108 -0
  126. data/lib/cmdx/validators/exclusion.rb +55 -94
  127. data/lib/cmdx/validators/format.rb +31 -85
  128. data/lib/cmdx/validators/inclusion.rb +65 -110
  129. data/lib/cmdx/validators/length.rb +117 -133
  130. data/lib/cmdx/validators/numeric.rb +123 -130
  131. data/lib/cmdx/validators/presence.rb +38 -79
  132. data/lib/cmdx/version.rb +1 -7
  133. data/lib/cmdx/workflow.rb +58 -330
  134. data/lib/cmdx.rb +1 -1
  135. data/lib/generators/cmdx/install_generator.rb +14 -31
  136. data/lib/generators/cmdx/task_generator.rb +39 -55
  137. data/lib/generators/cmdx/templates/install.rb +24 -6
  138. data/lib/generators/cmdx/workflow_generator.rb +41 -66
  139. data/lib/locales/ar.yml +0 -1
  140. data/lib/locales/cs.yml +0 -1
  141. data/lib/locales/da.yml +0 -1
  142. data/lib/locales/de.yml +0 -1
  143. data/lib/locales/el.yml +0 -1
  144. data/lib/locales/en.yml +0 -1
  145. data/lib/locales/es.yml +0 -1
  146. data/lib/locales/fi.yml +0 -1
  147. data/lib/locales/fr.yml +0 -1
  148. data/lib/locales/he.yml +0 -1
  149. data/lib/locales/hi.yml +0 -1
  150. data/lib/locales/it.yml +0 -1
  151. data/lib/locales/ja.yml +0 -1
  152. data/lib/locales/ko.yml +0 -1
  153. data/lib/locales/nl.yml +0 -1
  154. data/lib/locales/no.yml +0 -1
  155. data/lib/locales/pl.yml +0 -1
  156. data/lib/locales/pt.yml +0 -1
  157. data/lib/locales/ru.yml +0 -1
  158. data/lib/locales/sv.yml +0 -1
  159. data/lib/locales/th.yml +0 -1
  160. data/lib/locales/tr.yml +0 -1
  161. data/lib/locales/vi.yml +0 -1
  162. data/lib/locales/zh.yml +0 -1
  163. metadata +36 -8
  164. data/lib/cmdx/parameter_validator.rb +0 -81
  165. data/lib/cmdx/parameter_value.rb +0 -244
  166. data/lib/cmdx/parameters_inspector.rb +0 -72
  167. data/lib/cmdx/parameters_serializer.rb +0 -115
  168. data/lib/cmdx/rspec/result_matchers.rb +0 -917
  169. data/lib/cmdx/rspec/task_matchers.rb +0 -570
  170. data/lib/cmdx/validators/custom.rb +0 -102
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
@@ -186,6 +186,9 @@ extensions: []
186
186
  extra_rdoc_files: []
187
187
  files:
188
188
  - ".DS_Store"
189
+ - ".cursor/prompts/docs.md"
190
+ - ".cursor/prompts/rspec.md"
191
+ - ".cursor/prompts/yardoc.md"
189
192
  - ".cursor/rules/cursor-instructions.mdc"
190
193
  - ".rspec"
191
194
  - ".rubocop.yml"
@@ -202,6 +205,7 @@ files:
202
205
  - docs/basics/setup.md
203
206
  - docs/callbacks.md
204
207
  - docs/configuration.md
208
+ - docs/deprecation.md
205
209
  - docs/getting_started.md
206
210
  - docs/internationalization.md
207
211
  - docs/interruptions/exceptions.md
@@ -227,6 +231,8 @@ files:
227
231
  - lib/cmdx/chain.rb
228
232
  - lib/cmdx/chain_inspector.rb
229
233
  - lib/cmdx/chain_serializer.rb
234
+ - lib/cmdx/coercion.rb
235
+ - lib/cmdx/coercion_registry.rb
230
236
  - lib/cmdx/coercions/array.rb
231
237
  - lib/cmdx/coercions/big_decimal.rb
232
238
  - lib/cmdx/coercions/boolean.rb
@@ -268,28 +274,50 @@ files:
268
274
  - lib/cmdx/middlewares/correlate.rb
269
275
  - lib/cmdx/middlewares/timeout.rb
270
276
  - lib/cmdx/parameter.rb
277
+ - lib/cmdx/parameter_evaluator.rb
271
278
  - lib/cmdx/parameter_inspector.rb
272
279
  - lib/cmdx/parameter_registry.rb
273
280
  - lib/cmdx/parameter_serializer.rb
274
- - lib/cmdx/parameter_validator.rb
275
- - lib/cmdx/parameter_value.rb
276
- - lib/cmdx/parameters_inspector.rb
277
- - lib/cmdx/parameters_serializer.rb
278
281
  - lib/cmdx/railtie.rb
279
282
  - lib/cmdx/result.rb
280
283
  - lib/cmdx/result_ansi.rb
281
284
  - lib/cmdx/result_inspector.rb
282
285
  - lib/cmdx/result_logger.rb
283
286
  - lib/cmdx/result_serializer.rb
284
- - lib/cmdx/rspec/result_matchers.rb
285
- - lib/cmdx/rspec/task_matchers.rb
287
+ - lib/cmdx/rspec/matchers.rb
288
+ - lib/cmdx/rspec/result_matchers/be_executed.rb
289
+ - lib/cmdx/rspec/result_matchers/be_failed_task.rb
290
+ - lib/cmdx/rspec/result_matchers/be_skipped_task.rb
291
+ - lib/cmdx/rspec/result_matchers/be_state_matchers.rb
292
+ - lib/cmdx/rspec/result_matchers/be_status_matchers.rb
293
+ - lib/cmdx/rspec/result_matchers/be_successful_task.rb
294
+ - lib/cmdx/rspec/result_matchers/have_bad_outcome.rb
295
+ - lib/cmdx/rspec/result_matchers/have_caused_failure.rb
296
+ - lib/cmdx/rspec/result_matchers/have_chain_index.rb
297
+ - lib/cmdx/rspec/result_matchers/have_context.rb
298
+ - lib/cmdx/rspec/result_matchers/have_empty_metadata.rb
299
+ - lib/cmdx/rspec/result_matchers/have_good_outcome.rb
300
+ - lib/cmdx/rspec/result_matchers/have_metadata.rb
301
+ - lib/cmdx/rspec/result_matchers/have_preserved_context.rb
302
+ - lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb
303
+ - lib/cmdx/rspec/result_matchers/have_runtime.rb
304
+ - lib/cmdx/rspec/result_matchers/have_thrown_failure.rb
305
+ - lib/cmdx/rspec/task_matchers/be_well_formed_task.rb
306
+ - lib/cmdx/rspec/task_matchers/have_callback.rb
307
+ - lib/cmdx/rspec/task_matchers/have_cmd_setting.rb
308
+ - lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb
309
+ - lib/cmdx/rspec/task_matchers/have_middleware.rb
310
+ - lib/cmdx/rspec/task_matchers/have_parameter.rb
286
311
  - lib/cmdx/task.rb
312
+ - lib/cmdx/task_deprecator.rb
313
+ - lib/cmdx/task_processor.rb
287
314
  - lib/cmdx/task_serializer.rb
288
315
  - lib/cmdx/utils/ansi_color.rb
289
316
  - lib/cmdx/utils/log_timestamp.rb
290
317
  - lib/cmdx/utils/monotonic_runtime.rb
291
318
  - lib/cmdx/utils/name_affix.rb
292
- - lib/cmdx/validators/custom.rb
319
+ - lib/cmdx/validator.rb
320
+ - lib/cmdx/validator_registry.rb
293
321
  - lib/cmdx/validators/exclusion.rb
294
322
  - lib/cmdx/validators/format.rb
295
323
  - lib/cmdx/validators/inclusion.rb
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter validation orchestration module for CMDx tasks.
5
- #
6
- # The ParameterValidator module provides high-level parameter validation
7
- # coordination for task instances. It triggers validation of all task
8
- # parameters and handles validation failure by setting task failure state
9
- # with appropriate error messages.
10
- #
11
- # @example Basic parameter validation
12
- # class ProcessOrderTask < CMDx::Task
13
- # required :order_id, type: :integer
14
- # required :email, type: :string, format: { with: /@/ }
15
- # end
16
- #
17
- # task = ProcessOrderTask.new
18
- # ParameterValidator.call(task) # Validates all parameters
19
- # # If validation fails, task.failed? => true
20
- #
21
- # @example Validation with error handling
22
- # task = ProcessOrderTask.new
23
- # ParameterValidator.call(task)
24
- #
25
- # if task.failed?
26
- # puts task.result.metadata[:reason] # => "order_id is a required parameter. email is invalid"
27
- # puts task.errors.messages # => { order_id: ["is a required parameter"], email: ["is invalid"] }
28
- # end
29
- #
30
- # @example Successful validation
31
- # task = ProcessOrderTask.call(order_id: 123, email: "user@example.com")
32
- # # ParameterValidator runs automatically and validation passes
33
- # task.success? # => true
34
- #
35
- # @see CMDx::Parameters Parameter collection validation
36
- # @see CMDx::Parameter Individual parameter definitions
37
- # @see CMDx::Task Task execution and parameter integration
38
- module ParameterValidator
39
-
40
- module_function
41
-
42
- # Validates all parameters for a task instance.
43
- #
44
- # Triggers validation of all task parameters through the Parameters collection.
45
- # If any validation errors occur, sets the task to failed state with a
46
- # comprehensive error message and detailed error information.
47
- #
48
- # @param task [CMDx::Task] The task instance to validate parameters for
49
- # @return [void]
50
- #
51
- # @example Validating task parameters
52
- # task = MyTask.new
53
- # ParameterValidator.call(task)
54
- #
55
- # # If validation fails:
56
- # task.failed? # => true
57
- # task.result.metadata[:reason] # => "Combined error messages from all failed parameters"
58
- # task.errors.empty? # => false
59
- #
60
- # @example Validation success
61
- # task = MyTask.new # with valid parameters
62
- # ParameterValidator.call(task)
63
- #
64
- # task.errors.empty? # => true
65
- # # Task continues normal execution
66
- #
67
- # @note This method is typically called automatically during task execution
68
- # before the main task logic runs, ensuring parameter validation occurs
69
- # early in the task lifecycle.
70
- def call(task)
71
- task.class.cmd_parameters.validate!(task)
72
- return if task.errors.empty?
73
-
74
- task.fail!(
75
- reason: task.errors.full_messages.join(". "),
76
- messages: task.errors.messages
77
- )
78
- end
79
-
80
- end
81
- end
@@ -1,244 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter value resolution and processing class for CMDx tasks.
5
- #
6
- # The ParameterValue class handles the complete lifecycle of parameter value
7
- # processing including source resolution, type coercion, validation, and error
8
- # handling. It serves as the bridge between parameter definitions and their
9
- # actual values during task execution.
10
- #
11
- # @example Basic parameter value processing
12
- # task = ProcessOrderTask.new
13
- # parameter = Parameter.new(:order_id, klass: ProcessOrderTask, type: :integer)
14
- # value_processor = ParameterValue.new(task, parameter)
15
- # processed_value = value_processor.call # Resolves, coerces, and validates
16
- #
17
- # @example Parameter value with validation
18
- # parameter = Parameter.new(:email, klass: Task, type: :string,
19
- # format: { with: /@/ }, presence: true)
20
- # value_processor = ParameterValue.new(task, parameter)
21
- # value_processor.call # Validates email format and presence
22
- #
23
- # @example Parameter value with default
24
- # parameter = Parameter.new(:priority, klass: Task, default: "normal")
25
- # value_processor = ParameterValue.new(task, parameter)
26
- # value_processor.call # Returns "normal" if not provided
27
- #
28
- # @see CMDx::Parameter Parameter definition and configuration
29
- # @see CMDx::Coercions Type coercion modules
30
- # @see CMDx::Validators Parameter validation modules
31
- class ParameterValue
32
-
33
- __cmdx_attr_delegator :parent, :method_source, :name, :options, :required?, :optional?, :type,
34
- to: :parameter,
35
- private: true
36
-
37
- # @return [CMDx::Task] The task instance being processed
38
- # @return [CMDx::Parameter] The parameter definition being processed
39
- attr_reader :task, :parameter
40
-
41
- # Initializes a new ParameterValue processor.
42
- #
43
- # Creates a parameter value processor for resolving, coercing, and validating
44
- # a specific parameter value within the context of a task instance.
45
- #
46
- # @param task [CMDx::Task] The task instance containing the parameter source
47
- # @param parameter [CMDx::Parameter] The parameter definition to process
48
- #
49
- # @example Creating a parameter value processor
50
- # processor = ParameterValue.new(task_instance, parameter_definition)
51
- def initialize(task, parameter)
52
- @task = task
53
- @parameter = parameter
54
- end
55
-
56
- # Processes the parameter value through coercion and validation.
57
- #
58
- # Executes the complete parameter value processing pipeline:
59
- # 1. Resolves the raw value from the source
60
- # 2. Applies type coercion based on parameter type
61
- # 3. Runs all configured validations
62
- # 4. Returns the final processed value
63
- #
64
- # @return [Object] The processed and validated parameter value
65
- # @raise [CoercionError] If type coercion fails
66
- # @raise [ValidationError] If validation fails
67
- #
68
- # @example Processing a simple parameter
69
- # processor.call # => 42 (after coercion and validation)
70
- #
71
- # @example Processing with validation failure
72
- # processor.call # => raises ValidationError: "is not valid"
73
- def call
74
- coerce!.tap { validate! }
75
- end
76
-
77
- private
78
-
79
- # Checks if the parameter source method is defined on the task.
80
- #
81
- # @return [Boolean] true if source method exists, false otherwise
82
- def source_defined?
83
- task.respond_to?(method_source, true) || task.__cmdx_try(method_source)
84
- end
85
-
86
- # Resolves the source object that contains the parameter value.
87
- #
88
- # Gets the source object by calling the method_source on the task instance.
89
- # Raises ValidationError if the source method is not defined.
90
- #
91
- # @return [Object] The source object containing parameter values
92
- # @raise [ValidationError] If source method is undefined
93
- def source
94
- return @source if defined?(@source)
95
-
96
- unless source_defined?
97
- raise ValidationError, I18n.t(
98
- "cmdx.parameters.undefined",
99
- default: "delegates to undefined method #{method_source}",
100
- source: method_source
101
- )
102
- end
103
-
104
- @source = task.__cmdx_try(method_source)
105
- end
106
-
107
- # Checks if the source object has the parameter value.
108
- #
109
- # @return [Boolean] true if source responds to parameter name, false otherwise
110
- def source_value?
111
- return false if source.nil?
112
-
113
- source.__cmdx_respond_to?(name, true)
114
- end
115
-
116
- # Checks if a required parameter value is missing from the source.
117
- #
118
- # @return [Boolean] true if required parameter is missing, false otherwise
119
- def source_value_required?
120
- return false if parent&.optional? && source.nil?
121
-
122
- required? && !source_value?
123
- end
124
-
125
- # Resolves the raw parameter value from the source.
126
- #
127
- # Gets the parameter value from the source object, handling required
128
- # parameter validation and default value resolution.
129
- #
130
- # @return [Object] The raw parameter value
131
- # @raise [ValidationError] If required parameter is missing
132
- def value
133
- return @value if defined?(@value)
134
-
135
- if source_value_required?
136
- raise ValidationError, I18n.t(
137
- "cmdx.parameters.required",
138
- default: "is a required parameter"
139
- )
140
- end
141
-
142
- @value = source.__cmdx_try(name)
143
- return @value unless @value.nil? && options.key?(:default)
144
-
145
- @value = task.__cmdx_yield(options[:default])
146
- end
147
-
148
- # Applies type coercion to the parameter value.
149
- #
150
- # Attempts to coerce the value to each specified type in order,
151
- # supporting multiple type fallbacks for flexible coercion.
152
- #
153
- # @return [Object] The coerced parameter value
154
- # @raise [CoercionError] If all coercion attempts fail
155
- # @raise [UnknownCoercionError] If an unknown type is specified
156
- def coerce!
157
- types = Array(type)
158
- tsize = types.size - 1
159
-
160
- types.each_with_index do |t, i|
161
- break case t.to_sym
162
- when :array then Coercions::Array
163
- when :big_decimal then Coercions::BigDecimal
164
- when :boolean then Coercions::Boolean
165
- when :complex then Coercions::Complex
166
- when :date then Coercions::Date
167
- when :datetime then Coercions::DateTime
168
- when :float then Coercions::Float
169
- when :hash then Coercions::Hash
170
- when :integer then Coercions::Integer
171
- when :rational then Coercions::Rational
172
- when :string then Coercions::String
173
- when :time then Coercion::Time
174
- when :virtual then Coercions::Virtual
175
- else raise UnknownCoercionError, "unknown coercion #{t}"
176
- end.call(value, options)
177
- rescue CoercionError => e
178
- next if tsize != i
179
-
180
- raise(e) if tsize.zero?
181
-
182
- values = types.map(&:to_s).join(", ")
183
- raise CoercionError, I18n.t(
184
- "cmdx.coercions.into_any",
185
- values:,
186
- default: "could not coerce into one of: #{values}"
187
- )
188
- end
189
- end
190
-
191
- # Checks if validations should be skipped for optional missing arguments.
192
- #
193
- # @return [Boolean] true if validations should be skipped, false otherwise
194
- def skip_validations_due_to_optional_missing_argument?
195
- optional? && value.nil? && !source.nil? && !source.__cmdx_respond_to?(name, true)
196
- end
197
-
198
- # Checks if a specific validator should be skipped due to conditional logic.
199
- #
200
- # @param key [Symbol] The validator key to check
201
- # @return [Boolean] true if validator should be skipped, false otherwise
202
- def skip_validator_due_to_conditional?(key)
203
- opts = options[key]
204
- opts.is_a?(Hash) && !task.__cmdx_eval(opts)
205
- end
206
-
207
- # Checks if a specific validator should be skipped due to allow_nil option.
208
- #
209
- # @param key [Symbol] The validator key to check
210
- # @return [Boolean] true if validator should be skipped, false otherwise
211
- def skip_validator_due_to_allow_nil?(key)
212
- opts = options[key]
213
- opts.is_a?(Hash) && opts[:allow_nil] && value.nil?
214
- end
215
-
216
- # Runs all configured validations on the parameter value.
217
- #
218
- # Iterates through all validation options and applies the appropriate
219
- # validators, respecting skip conditions for optional parameters,
220
- # conditional validations, and allow_nil settings.
221
- #
222
- # @return [void]
223
- # @raise [ValidationError] If any validation fails
224
- def validate!
225
- return if skip_validations_due_to_optional_missing_argument?
226
-
227
- options.each_key do |key|
228
- next if skip_validator_due_to_allow_nil?(key)
229
- next if skip_validator_due_to_conditional?(key)
230
-
231
- case key.to_sym
232
- when :custom then Validators::Custom
233
- when :exclusion then Validators::Exclusion
234
- when :format then Validators::Format
235
- when :inclusion then Validators::Inclusion
236
- when :length then Validators::Length
237
- when :numeric then Validators::Numeric
238
- when :presence then Validators::Presence
239
- end&.call(value, options)
240
- end
241
- end
242
-
243
- end
244
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter collection inspection utility for generating human-readable descriptions.
5
- #
6
- # The ParametersInspector module provides functionality to convert collections
7
- # of parameters into formatted, human-readable string representations. It
8
- # coordinates with ParameterInspector to format individual parameters and
9
- # combines them into a cohesive multi-parameter description.
10
- #
11
- # @example Basic parameters collection inspection
12
- # parameter_registry = ParameterRegistry.new
13
- # parameter_registry << Parameter.new(:user_id, klass: Task, type: :integer, required: true)
14
- # parameter_registry << Parameter.new(:email, klass: Task, type: :string, required: false)
15
- #
16
- # ParametersInspector.call(parameter_registry)
17
- # # => "Parameter: name=user_id type=integer source=context required=true options={}
18
- # # Parameter: name=email type=string source=context required=false options={}"
19
- #
20
- # @example Empty parameters collection
21
- # empty_parameter_registry = ParameterRegistry.new
22
- # ParametersInspector.call(empty_parameter_registry)
23
- # # => ""
24
- #
25
- # @example Parameters with validation options
26
- # parameter_registry = ParameterRegistry.new
27
- # parameter_registry << Parameter.new(:age, klass: Task, type: :integer,
28
- # numeric: { within: 18..120 }, required: true)
29
- # parameter_registry << Parameter.new(:website, klass: Task, type: :string,
30
- # format: { with: /^https?:\/\// }, required: false)
31
- #
32
- # ParametersInspector.call(parameter_registry)
33
- # # => "Parameter: name=age type=integer source=context required=true options={numeric: {within: 18..120}}
34
- # # Parameter: name=website type=string source=context required=false options={format: {with: /^https?:\/\//}}"
35
- #
36
- # @see CMDx::ParameterRegistry Parameter collection management
37
- # @see CMDx::ParameterInspector Individual parameter inspection
38
- # @see CMDx::Parameter Parameter definition and configuration
39
- module ParametersInspector
40
-
41
- module_function
42
-
43
- # Converts a Parameters collection to a human-readable string representation.
44
- #
45
- # Iterates through all parameters in the collection and formats each one
46
- # using ParameterInspector, then joins them with newlines to create a
47
- # comprehensive multi-parameter description.
48
- #
49
- # @param parameters [CMDx::ParameterRegistry] The parameters collection to inspect
50
- # @return [String] Multi-line formatted parameter descriptions
51
- #
52
- # @example Inspecting multiple parameters
53
- # ParametersInspector.call(parameters_collection)
54
- # # => "Parameter: name=user_id type=integer source=context required=true
55
- # # Parameter: name=email type=string source=context required=false
56
- # # Parameter: name=age type=integer source=context required=true"
57
- #
58
- # @example Inspecting empty collection
59
- # ParametersInspector.call(ParameterRegistry.new)
60
- # # => ""
61
- #
62
- # @example Inspecting single parameter collection
63
- # single_param_collection = ParameterRegistry.new
64
- # single_param_collection << Parameter.new(:name, klass: Task)
65
- # ParametersInspector.call(single_param_collection)
66
- # # => "Parameter: name=name type=virtual source=context required=false options={}"
67
- def call(parameters)
68
- parameters.map(&:to_s).join("\n")
69
- end
70
-
71
- end
72
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter collection serialization utility for converting Parameters to hash arrays.
5
- #
6
- # The ParametersSerializer module provides functionality to serialize collections
7
- # of Parameter instances into structured array representations. Each parameter
8
- # in the collection is converted to its hash representation, creating a
9
- # comprehensive data structure suitable for inspection, logging, and data interchange.
10
- #
11
- # @example Basic parameters collection serialization
12
- # parameter_registry = ParameterRegistry.new
13
- # parameter_registry << Parameter.new(:user_id, klass: Task, type: :integer, required: true)
14
- # parameters << Parameter.new(:email, klass: Task, type: :string, required: false)
15
- #
16
- # ParametersSerializer.call(parameters)
17
- # # => [
18
- # # {
19
- # # source: :context,
20
- # # name: :user_id,
21
- # # type: :integer,
22
- # # required: true,
23
- # # options: {},
24
- # # children: []
25
- # # },
26
- # # {
27
- # # source: :context,
28
- # # name: :email,
29
- # # type: :string,
30
- # # required: false,
31
- # # options: {},
32
- # # children: []
33
- # # }
34
- # # ]
35
- #
36
- # @example Empty parameters collection
37
- # empty_parameter_registry = ParameterRegistry.new
38
- # ParametersSerializer.call(empty_parameter_registry)
39
- # # => []
40
- #
41
- # @example Parameters with validation and nested structures
42
- # parameter_registry = ParameterRegistry.new
43
- # parameter_registry << Parameter.new(:age, klass: Task, type: :integer,
44
- # numeric: { within: 18..120 }, required: true)
45
- #
46
- # address_param = Parameter.new(:address, klass: Task) do
47
- # required :street, :city
48
- # optional :apartment
49
- # end
50
- # parameter_registry << address_param
51
- #
52
- # ParametersSerializer.call(parameter_registry)
53
- # # => [
54
- # # {
55
- # # source: :context,
56
- # # name: :age,
57
- # # type: :integer,
58
- # # required: true,
59
- # # options: { numeric: { within: 18..120 } },
60
- # # children: []
61
- # # },
62
- # # {
63
- # # source: :context,
64
- # # name: :address,
65
- # # type: :virtual,
66
- # # required: false,
67
- # # options: {},
68
- # # children: [
69
- # # { source: :address, name: :street, type: :virtual, required: true, options: {}, children: [] },
70
- # # { source: :address, name: :city, type: :virtual, required: true, options: {}, children: [] },
71
- # # { source: :address, name: :apartment, type: :virtual, required: false, options: {}, children: [] }
72
- # # ]
73
- # # }
74
- # # ]
75
- #
76
- # @see CMDx::ParameterRegistry Parameter collection management
77
- # @see CMDx::ParameterSerializer Individual parameter serialization
78
- # @see CMDx::Parameter Parameter definition and configuration
79
- module ParametersSerializer
80
-
81
- module_function
82
-
83
- # Converts a Parameters collection to an array of hash representations.
84
- #
85
- # Iterates through all parameters in the collection and converts each one
86
- # to its hash representation using the Parameter#to_h method, which delegates
87
- # to ParameterSerializer.
88
- #
89
- # @param parameters [CMDx::ParameterRegistry] The parameters collection to serialize
90
- # @return [Array<Hash>] Array of serialized parameter data structures
91
- #
92
- # @example Serializing multiple parameters
93
- # ParametersSerializer.call(parameters_collection)
94
- # # => [
95
- # # { source: :context, name: :user_id, type: :integer, required: true, options: {}, children: [] },
96
- # # { source: :context, name: :email, type: :string, required: false, options: {}, children: [] }
97
- # # ]
98
- #
99
- # @example Serializing empty collection
100
- # ParametersSerializer.call(ParameterRegistry.new)
101
- # # => []
102
- #
103
- # @example Serializing single parameter collection
104
- # single_param_collection = ParameterRegistry.new
105
- # single_param_collection << Parameter.new(:name, klass: Task, type: :string)
106
- # ParametersSerializer.call(single_param_collection)
107
- # # => [
108
- # # { source: :context, name: :name, type: :string, required: false, options: {}, children: [] }
109
- # # ]
110
- def call(parameters)
111
- parameters.map(&:to_h)
112
- end
113
-
114
- end
115
- end