cmdx 1.1.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +4 -1
  4. data/.cursor/prompts/llms.md +20 -0
  5. data/.cursor/prompts/rspec.md +4 -1
  6. data/.cursor/prompts/yardoc.md +3 -2
  7. data/.cursor/rules/cursor-instructions.mdc +56 -1
  8. data/.irbrc +6 -0
  9. data/.rubocop.yml +29 -18
  10. data/CHANGELOG.md +5 -133
  11. data/LLM.md +3317 -0
  12. data/README.md +68 -44
  13. data/docs/attributes/coercions.md +162 -0
  14. data/docs/attributes/defaults.md +90 -0
  15. data/docs/attributes/definitions.md +281 -0
  16. data/docs/attributes/naming.md +78 -0
  17. data/docs/attributes/validations.md +309 -0
  18. data/docs/basics/chain.md +56 -249
  19. data/docs/basics/context.md +56 -289
  20. data/docs/basics/execution.md +114 -0
  21. data/docs/basics/setup.md +37 -334
  22. data/docs/callbacks.md +89 -467
  23. data/docs/deprecation.md +91 -174
  24. data/docs/getting_started.md +212 -202
  25. data/docs/internationalization.md +11 -647
  26. data/docs/interruptions/exceptions.md +23 -198
  27. data/docs/interruptions/faults.md +71 -151
  28. data/docs/interruptions/halt.md +109 -186
  29. data/docs/logging.md +44 -256
  30. data/docs/middlewares.md +113 -426
  31. data/docs/outcomes/result.md +81 -228
  32. data/docs/outcomes/states.md +33 -221
  33. data/docs/outcomes/statuses.md +21 -311
  34. data/docs/tips_and_tricks.md +120 -70
  35. data/docs/workflows.md +99 -283
  36. data/lib/cmdx/.DS_Store +0 -0
  37. data/lib/cmdx/attribute.rb +229 -0
  38. data/lib/cmdx/attribute_registry.rb +94 -0
  39. data/lib/cmdx/attribute_value.rb +193 -0
  40. data/lib/cmdx/callback_registry.rb +69 -77
  41. data/lib/cmdx/chain.rb +56 -73
  42. data/lib/cmdx/coercion_registry.rb +52 -68
  43. data/lib/cmdx/coercions/array.rb +19 -18
  44. data/lib/cmdx/coercions/big_decimal.rb +20 -24
  45. data/lib/cmdx/coercions/boolean.rb +26 -25
  46. data/lib/cmdx/coercions/complex.rb +21 -22
  47. data/lib/cmdx/coercions/date.rb +25 -23
  48. data/lib/cmdx/coercions/date_time.rb +24 -25
  49. data/lib/cmdx/coercions/float.rb +25 -22
  50. data/lib/cmdx/coercions/hash.rb +31 -32
  51. data/lib/cmdx/coercions/integer.rb +30 -24
  52. data/lib/cmdx/coercions/rational.rb +29 -24
  53. data/lib/cmdx/coercions/string.rb +19 -22
  54. data/lib/cmdx/coercions/symbol.rb +37 -0
  55. data/lib/cmdx/coercions/time.rb +26 -25
  56. data/lib/cmdx/configuration.rb +49 -108
  57. data/lib/cmdx/context.rb +222 -44
  58. data/lib/cmdx/deprecator.rb +61 -0
  59. data/lib/cmdx/errors.rb +42 -252
  60. data/lib/cmdx/exceptions.rb +39 -0
  61. data/lib/cmdx/faults.rb +78 -39
  62. data/lib/cmdx/freezer.rb +51 -0
  63. data/lib/cmdx/identifier.rb +30 -0
  64. data/lib/cmdx/locale.rb +52 -0
  65. data/lib/cmdx/log_formatters/json.rb +21 -22
  66. data/lib/cmdx/log_formatters/key_value.rb +20 -22
  67. data/lib/cmdx/log_formatters/line.rb +15 -22
  68. data/lib/cmdx/log_formatters/logstash.rb +22 -23
  69. data/lib/cmdx/log_formatters/raw.rb +16 -22
  70. data/lib/cmdx/middleware_registry.rb +70 -74
  71. data/lib/cmdx/middlewares/correlate.rb +90 -54
  72. data/lib/cmdx/middlewares/runtime.rb +58 -0
  73. data/lib/cmdx/middlewares/timeout.rb +48 -68
  74. data/lib/cmdx/railtie.rb +12 -45
  75. data/lib/cmdx/result.rb +229 -314
  76. data/lib/cmdx/task.rb +194 -366
  77. data/lib/cmdx/utils/call.rb +49 -0
  78. data/lib/cmdx/utils/condition.rb +71 -0
  79. data/lib/cmdx/utils/format.rb +61 -0
  80. data/lib/cmdx/validator_registry.rb +63 -72
  81. data/lib/cmdx/validators/exclusion.rb +38 -67
  82. data/lib/cmdx/validators/format.rb +48 -49
  83. data/lib/cmdx/validators/inclusion.rb +43 -74
  84. data/lib/cmdx/validators/length.rb +91 -154
  85. data/lib/cmdx/validators/numeric.rb +87 -162
  86. data/lib/cmdx/validators/presence.rb +37 -50
  87. data/lib/cmdx/version.rb +1 -1
  88. data/lib/cmdx/worker.rb +178 -0
  89. data/lib/cmdx/workflow.rb +85 -81
  90. data/lib/cmdx.rb +19 -13
  91. data/lib/generators/cmdx/install_generator.rb +14 -13
  92. data/lib/generators/cmdx/task_generator.rb +25 -50
  93. data/lib/generators/cmdx/templates/install.rb +11 -46
  94. data/lib/generators/cmdx/templates/task.rb.tt +3 -2
  95. data/lib/locales/en.yml +18 -4
  96. data/src/cmdx-logo.png +0 -0
  97. metadata +32 -116
  98. data/docs/ai_prompts.md +0 -393
  99. data/docs/basics/call.md +0 -317
  100. data/docs/configuration.md +0 -344
  101. data/docs/parameters/coercions.md +0 -396
  102. data/docs/parameters/defaults.md +0 -335
  103. data/docs/parameters/definitions.md +0 -446
  104. data/docs/parameters/namespacing.md +0 -378
  105. data/docs/parameters/validations.md +0 -405
  106. data/docs/testing.md +0 -553
  107. data/lib/cmdx/callback.rb +0 -53
  108. data/lib/cmdx/chain_inspector.rb +0 -56
  109. data/lib/cmdx/chain_serializer.rb +0 -63
  110. data/lib/cmdx/coercion.rb +0 -57
  111. data/lib/cmdx/coercions/virtual.rb +0 -29
  112. data/lib/cmdx/core_ext/hash.rb +0 -83
  113. data/lib/cmdx/core_ext/module.rb +0 -98
  114. data/lib/cmdx/core_ext/object.rb +0 -125
  115. data/lib/cmdx/correlator.rb +0 -122
  116. data/lib/cmdx/error.rb +0 -67
  117. data/lib/cmdx/fault.rb +0 -140
  118. data/lib/cmdx/immutator.rb +0 -52
  119. data/lib/cmdx/lazy_struct.rb +0 -246
  120. data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
  121. data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
  122. data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
  123. data/lib/cmdx/logger.rb +0 -49
  124. data/lib/cmdx/logger_ansi.rb +0 -68
  125. data/lib/cmdx/logger_serializer.rb +0 -116
  126. data/lib/cmdx/middleware.rb +0 -70
  127. data/lib/cmdx/parameter.rb +0 -312
  128. data/lib/cmdx/parameter_evaluator.rb +0 -231
  129. data/lib/cmdx/parameter_inspector.rb +0 -66
  130. data/lib/cmdx/parameter_registry.rb +0 -106
  131. data/lib/cmdx/parameter_serializer.rb +0 -59
  132. data/lib/cmdx/result_ansi.rb +0 -71
  133. data/lib/cmdx/result_inspector.rb +0 -71
  134. data/lib/cmdx/result_logger.rb +0 -59
  135. data/lib/cmdx/result_serializer.rb +0 -104
  136. data/lib/cmdx/rspec/matchers.rb +0 -28
  137. data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
  138. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
  139. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
  140. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
  141. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
  142. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
  143. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
  144. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
  145. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
  146. data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
  147. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
  148. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
  149. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
  150. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
  151. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
  152. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
  153. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
  154. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
  155. data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
  156. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
  157. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
  158. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
  159. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
  160. data/lib/cmdx/task_deprecator.rb +0 -58
  161. data/lib/cmdx/task_processor.rb +0 -246
  162. data/lib/cmdx/task_serializer.rb +0 -57
  163. data/lib/cmdx/utils/ansi_color.rb +0 -73
  164. data/lib/cmdx/utils/log_timestamp.rb +0 -36
  165. data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
  166. data/lib/cmdx/utils/name_affix.rb +0 -52
  167. data/lib/cmdx/validator.rb +0 -57
  168. data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
  169. data/lib/generators/cmdx/workflow_generator.rb +0 -84
  170. data/lib/locales/ar.yml +0 -35
  171. data/lib/locales/cs.yml +0 -35
  172. data/lib/locales/da.yml +0 -35
  173. data/lib/locales/de.yml +0 -35
  174. data/lib/locales/el.yml +0 -35
  175. data/lib/locales/es.yml +0 -35
  176. data/lib/locales/fi.yml +0 -35
  177. data/lib/locales/fr.yml +0 -35
  178. data/lib/locales/he.yml +0 -35
  179. data/lib/locales/hi.yml +0 -35
  180. data/lib/locales/it.yml +0 -35
  181. data/lib/locales/ja.yml +0 -35
  182. data/lib/locales/ko.yml +0 -35
  183. data/lib/locales/nl.yml +0 -35
  184. data/lib/locales/no.yml +0 -35
  185. data/lib/locales/pl.yml +0 -35
  186. data/lib/locales/pt.yml +0 -35
  187. data/lib/locales/ru.yml +0 -35
  188. data/lib/locales/sv.yml +0 -35
  189. data/lib/locales/th.yml +0 -35
  190. data/lib/locales/tr.yml +0 -35
  191. data/lib/locales/vi.yml +0 -35
  192. data/lib/locales/zh.yml +0 -35
@@ -1,231 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter evaluation system for task execution context.
5
- #
6
- # ParameterEvaluator processes parameter definitions by extracting values from
7
- # task context sources, applying type coercions, performing validations, and
8
- # handling optional parameters with default values. It ensures parameter values
9
- # meet the requirements defined in parameter specifications before task execution.
10
- class ParameterEvaluator
11
-
12
- cmdx_attr_delegator :parent, :method_source, :name, :options, :required?, :optional?, :type,
13
- to: :parameter,
14
- private: true
15
-
16
- # @return [CMDx::Task] The task instance being processed
17
- attr_reader :task
18
-
19
- # @return [CMDx::Parameter] The parameter definition being processed
20
- attr_reader :parameter
21
-
22
- # Creates a new parameter evaluator instance.
23
- #
24
- # @param task [CMDx::Task] the task instance containing parameter context
25
- # @param parameter [CMDx::Parameter] the parameter definition to evaluate
26
- #
27
- # @example Create evaluator for a task parameter
28
- # evaluator = ParameterEvaluator.new(task, parameter)
29
- def initialize(task, parameter)
30
- @task = task
31
- @parameter = parameter
32
- end
33
-
34
- # Evaluates a parameter by creating a new evaluator instance and calling it.
35
- #
36
- # @param task [CMDx::Task] the task instance containing parameter context
37
- # @param parameter [CMDx::Parameter] the parameter definition to evaluate
38
- #
39
- # @return [Object] the coerced and validated parameter value
40
- #
41
- # @raise [ValidationError] when parameter source is undefined or required parameter is missing
42
- # @raise [CoercionError] when parameter value cannot be coerced to expected type
43
- #
44
- # @example Evaluate a parameter value
45
- # value = ParameterEvaluator.call(task, parameter)
46
- def self.call(task, parameter)
47
- new(task, parameter).call
48
- end
49
-
50
- # Evaluates the parameter by applying coercion and validation.
51
- #
52
- # @return [Object] the coerced and validated parameter value
53
- #
54
- # @raise [ValidationError] when parameter source is undefined or required parameter is missing
55
- # @raise [CoercionError] when parameter value cannot be coerced to expected type
56
- #
57
- # @example Evaluate parameter with coercion and validation
58
- # evaluator = ParameterEvaluator.new(task, parameter)
59
- # value = evaluator.call
60
- def call
61
- coerce!.tap { validate! }
62
- end
63
-
64
- private
65
-
66
- # Checks if the parameter source method is defined on the task.
67
- #
68
- # @return [Boolean] true if the source method exists, false otherwise
69
- #
70
- # @example Check if parameter source is defined
71
- # evaluator.send(:source_defined?) #=> true
72
- def source_defined?
73
- task.respond_to?(method_source, true) || task.cmdx_try(method_source)
74
- end
75
-
76
- # Retrieves the parameter source object from the task.
77
- #
78
- # @return [Object] the source object containing parameter values
79
- #
80
- # @raise [ValidationError] when the source method is not defined on the task
81
- #
82
- # @example Get parameter source
83
- # evaluator.send(:source) #=> #<Context:...>
84
- def source
85
- return @source if defined?(@source)
86
-
87
- unless source_defined?
88
- raise ValidationError, I18n.t(
89
- "cmdx.parameters.undefined",
90
- default: "delegates to undefined method #{method_source}",
91
- source: method_source
92
- )
93
- end
94
-
95
- @source = task.cmdx_try(method_source)
96
- end
97
-
98
- # Checks if the parameter value exists in the source object.
99
- #
100
- # @return [Boolean] true if the parameter value exists, false otherwise
101
- #
102
- # @example Check if parameter value exists
103
- # evaluator.send(:source_value?) #=> true
104
- def source_value?
105
- return false if source.nil?
106
-
107
- source.cmdx_respond_to?(name, true)
108
- end
109
-
110
- # Checks if a required parameter value is missing from the source.
111
- #
112
- # @return [Boolean] true if required parameter is missing, false otherwise
113
- #
114
- # @example Check if required parameter is missing
115
- # evaluator.send(:source_value_required?) #=> false
116
- def source_value_required?
117
- return false if parent&.optional? && source.nil?
118
-
119
- required? && !source_value?
120
- end
121
-
122
- # Extracts the parameter value from the source with default handling.
123
- #
124
- # @return [Object] the parameter value or default value
125
- #
126
- # @raise [ValidationError] when a required parameter is missing
127
- #
128
- # @example Get parameter value with default
129
- # evaluator.send(:value) #=> "default_value"
130
- def value
131
- return @value if defined?(@value)
132
-
133
- if source_value_required?
134
- raise ValidationError, I18n.t(
135
- "cmdx.parameters.required",
136
- default: "is a required parameter"
137
- )
138
- end
139
-
140
- @value = source.cmdx_try(name)
141
- return @value unless @value.nil? && options.key?(:default)
142
-
143
- @value = task.cmdx_yield(options[:default])
144
- end
145
-
146
- # Applies type coercion to the parameter value.
147
- #
148
- # @return [Object] the coerced parameter value
149
- #
150
- # @raise [CoercionError] when value cannot be coerced to expected type
151
- #
152
- # @example Coerce parameter value
153
- # evaluator.send(:coerce!) #=> 42
154
- def coerce!
155
- types = Array(type)
156
- tsize = types.size - 1
157
-
158
- types.each_with_index do |key, i|
159
- break CMDx.configuration.coercions.call(task, key, value, options)
160
- rescue CoercionError => e
161
- next if tsize != i
162
-
163
- raise(e) if tsize.zero?
164
-
165
- values = types.map(&:to_s).join(", ")
166
- raise CoercionError, I18n.t(
167
- "cmdx.coercions.into_any",
168
- values:,
169
- default: "could not coerce into one of: #{values}"
170
- )
171
- end
172
- end
173
-
174
- # Checks if validations should be skipped for optional missing arguments.
175
- #
176
- # @return [Boolean] true if validations should be skipped, false otherwise
177
- #
178
- # @example Check if validations should be skipped
179
- # evaluator.send(:skip_validations_due_to_optional_missing_argument?) #=> false
180
- def skip_validations_due_to_optional_missing_argument?
181
- optional? && value.nil? && !source.nil? && !source.cmdx_respond_to?(name, true)
182
- end
183
-
184
- # Checks if validator should be skipped due to conditional options.
185
- #
186
- # @param opts [Hash] the validator options
187
- #
188
- # @return [Boolean] true if validator should be skipped, false otherwise
189
- #
190
- # @example Check if validator should be skipped
191
- # evaluator.send(:skip_validator_due_to_conditional?, :presence) #=> false
192
- def skip_validator_due_to_conditional?(opts)
193
- opts.is_a?(Hash) && !task.cmdx_eval(opts)
194
- end
195
-
196
- # Checks if validator should be skipped due to allow_nil option.
197
- #
198
- # @param opts [Symbol] the validator options
199
- #
200
- # @return [Boolean] true if validator should be skipped, false otherwise
201
- #
202
- # @example Check if validator should be skipped for nil
203
- # evaluator.send(:skip_validator_due_to_allow_nil?, :presence) #=> true
204
- def skip_validator_due_to_allow_nil?(opts)
205
- opts.is_a?(Hash) && opts[:allow_nil] && value.nil?
206
- end
207
-
208
- # Applies all configured validations to the parameter value.
209
- #
210
- # @return [void]
211
- #
212
- # @raise [ValidationError] when parameter value fails validation
213
- #
214
- # @example Validate parameter value
215
- # evaluator.send(:validate!)
216
- def validate!
217
- return if skip_validations_due_to_optional_missing_argument?
218
-
219
- types = CMDx.configuration.validators.registry.keys
220
-
221
- options.slice(*types).each_key do |key|
222
- opts = options[key]
223
- next if skip_validator_due_to_allow_nil?(opts)
224
- next if skip_validator_due_to_conditional?(opts)
225
-
226
- CMDx.configuration.validators.call(task, key, value, opts)
227
- end
228
- end
229
-
230
- end
231
- end
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Provides formatted inspection and display functionality for parameter objects.
5
- #
6
- # This module formats parameter information into human-readable string representations,
7
- # including nested parameter structures with proper indentation. It processes parameter
8
- # hashes in a consistent order and handles child parameter relationships for complex
9
- # parameter hierarchies.
10
- module ParameterInspector
11
-
12
- ORDERED_KEYS = %i[
13
- name type source required options children
14
- ].freeze
15
-
16
- module_function
17
-
18
- # Formats a parameter hash into a human-readable inspection string.
19
- #
20
- # Creates a formatted string representation of parameter information,
21
- # displaying attributes in a consistent order with proper indentation
22
- # for nested child parameters. The method recursively processes child
23
- # parameters with increased indentation depth for visual hierarchy.
24
- #
25
- # @param parameter [Hash] the parameter hash to format
26
- # @option parameter [Symbol, String] :name the parameter name
27
- # @option parameter [Symbol, Array<Symbol>] :type the parameter type(s)
28
- # @option parameter [Symbol] :source the parameter source context
29
- # @option parameter [Boolean] :required whether the parameter is required
30
- # @option parameter [Hash] :options additional parameter configuration options
31
- # @option parameter [Array<Hash>] :children nested child parameter definitions
32
- # @param depth [Integer] the indentation depth for nested parameters (defaults to 1)
33
- #
34
- # @return [String] formatted multi-line string representation of the parameter
35
- #
36
- # @example Format a simple parameter
37
- # parameter = { name: :user_id, type: :integer, required: true }
38
- # ParameterInspector.call(parameter)
39
- # #=> "Parameter: name=user_id type=integer required=true"
40
- #
41
- # @example Format a parameter with children
42
- # parameter = {
43
- # name: :payment,
44
- # type: :hash,
45
- # required: true,
46
- # children: [
47
- # { name: :amount, type: :big_decimal, required: true },
48
- # { name: :currency, type: :string, required: true }
49
- # ]
50
- # }
51
- # ParameterInspector.call(parameter)
52
- # #=> "Parameter: name=payment type=hash required=true
53
- # # ↳ Parameter: name=amount type=big_decimal required=true
54
- # # ↳ Parameter: name=currency type=string required=true"
55
- def call(parameter, depth = 1)
56
- ORDERED_KEYS.filter_map do |key|
57
- value = parameter[key]
58
- next "#{key}=#{value}" unless key == :children
59
-
60
- spaces = " " * (depth * 2)
61
- value.map { |h| "\n#{spaces}↳ #{call(h, depth + 1)}" }.join
62
- end.unshift("Parameter:").join(" ")
63
- end
64
-
65
- end
66
- end
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Registry for managing parameter definitions within tasks.
5
- #
6
- # This registry maintains a collection of parameter definitions and provides
7
- # validation functionality to ensure all parameters are properly configured
8
- # and accessible on their associated tasks. It supports both flat and nested
9
- # parameter structures through recursive validation.
10
- class ParameterRegistry
11
-
12
- # @return [Array<Parameter>] array containing parameter definition objects
13
- attr_reader :registry
14
-
15
- # Initializes a new parameter registry with an empty parameter collection.
16
- #
17
- # @return [ParameterRegistry] a new parameter registry instance
18
- #
19
- # @example Creating a new registry
20
- # registry = ParameterRegistry.new
21
- # registry.registry #=> []
22
- def initialize
23
- @registry = []
24
- end
25
-
26
- # Creates a duplicate of the parameter registry with deep-copied parameters.
27
- #
28
- # This method creates a new registry instance with duplicated parameter
29
- # definitions, ensuring changes to the duplicate don't affect the original.
30
- #
31
- # @return [ParameterRegistry] a new registry instance with duplicated parameters
32
- #
33
- # @example Duplicate a registry
34
- # original = ParameterRegistry.new
35
- # duplicate = original.dup
36
- # duplicate.object_id != original.object_id #=> true
37
- def dup
38
- new_registry = self.class.new
39
- new_registry.instance_variable_set(:@registry, registry.map(&:dup))
40
- new_registry
41
- end
42
-
43
- # Checks if all parameters in the registry are valid.
44
- #
45
- # @return [Boolean] true if all parameters are valid, false otherwise
46
- #
47
- # @example Check registry validity
48
- # registry.valid? #=> true
49
- def valid?
50
- registry.all?(&:valid?)
51
- end
52
-
53
- # Validates all parameters in the registry against a task instance.
54
- #
55
- # This method ensures that each parameter is properly defined and accessible
56
- # on the provided task, including nested parameters through recursive validation.
57
- #
58
- # @param task [Task] the task instance to validate parameters against
59
- #
60
- # @return [void]
61
- #
62
- # @raise [NoMethodError] if a parameter method is not defined on the task
63
- #
64
- # @example Validate parameters against a task
65
- # registry.validate!(task_instance)
66
- def validate!(task)
67
- registry.each { |p| recursive_validate!(task, p) }
68
- end
69
-
70
- # Converts the parameter registry to a hash representation.
71
- #
72
- # @return [Array<Hash>] array of parameter hash representations
73
- #
74
- # @example Convert registry to hash
75
- # registry.to_h #=> [{name: :user_id, type: :integer}, {name: :email, type: :string}]
76
- def to_h
77
- registry.map(&:to_h)
78
- end
79
-
80
- # Converts the parameter registry to a string representation.
81
- #
82
- # @return [String] string representation of all parameters, joined by newlines
83
- #
84
- # @example Convert registry to string
85
- # registry.to_s #=> "user_id: integer\nemail: string"
86
- def to_s
87
- registry.map(&:to_s).join("\n")
88
- end
89
-
90
- private
91
-
92
- # Recursively validates a parameter and its children against a task.
93
- #
94
- # @param task [Task] the task instance to validate the parameter against
95
- # @param parameter [Parameter] the parameter to validate
96
- #
97
- # @return [void]
98
- #
99
- # @raise [NoMethodError] if the parameter method is not defined on the task
100
- def recursive_validate!(task, parameter)
101
- task.send(parameter.method_name) # Make sure parameter is defined on task
102
- parameter.children.each { |child| recursive_validate!(task, child) }
103
- end
104
-
105
- end
106
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Parameter serialization utilities for converting parameter objects to hash representations.
5
- #
6
- # ParameterSerializer provides functionality to convert parameter definition objects
7
- # into structured hash format for serialization, introspection, and data exchange.
8
- # It extracts essential parameter metadata including source context, method names,
9
- # type information, requirement status, options, and nested child parameters.
10
- module ParameterSerializer
11
-
12
- module_function
13
-
14
- # Converts a parameter object into a hash representation for serialization.
15
- #
16
- # This method extracts key metadata from a parameter definition and structures
17
- # it into a hash format suitable for serialization, storage, or transmission.
18
- # Child parameters are recursively serialized to maintain nested structure.
19
- #
20
- # @param parameter [CMDx::Parameter] the parameter object to serialize
21
- #
22
- # @return [Hash] a hash containing the parameter's metadata and configuration
23
- # @option return [Symbol] :source the source context for parameter resolution
24
- # @option return [Symbol] :name the method name generated for this parameter
25
- # @option return [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
26
- # @option return [Boolean] :required whether the parameter is required for execution
27
- # @option return [Hash] :options the parameter configuration options
28
- # @option return [Array<Hash>] :children serialized child parameters for nested structures
29
- #
30
- # @example Serialize a nested parameter with children
31
- # user_param = Parameter.new(:user, klass: MyTask, type: :hash) do
32
- # required :name, type: :string
33
- # optional :age, type: :integer
34
- # end
35
- # ParameterSerializer.call(user_param)
36
- # #=> {
37
- # # source: :context,
38
- # # name: :user,
39
- # # type: :hash,
40
- # # required: false,
41
- # # options: {},
42
- # # children: [
43
- # # { source: :user, name: :name, type: :string, required: true, options: {}, children: [] },
44
- # # { source: :user, name: :age, type: :integer, required: false, options: {}, children: [] }
45
- # # ]
46
- # # }
47
- def call(parameter)
48
- {
49
- source: parameter.method_source,
50
- name: parameter.method_name,
51
- type: parameter.type,
52
- required: parameter.required?,
53
- options: parameter.options,
54
- children: parameter.children.map(&:to_h)
55
- }
56
- end
57
-
58
- end
59
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # ANSI color formatting utilities for result states and statuses.
5
- #
6
- # This module provides functionality to apply appropriate ANSI colors to
7
- # result states and statuses for enhanced terminal output visibility.
8
- # It maps different execution states and statuses to their corresponding
9
- # colors and delegates the actual color application to the AnsiColor utility.
10
- module ResultAnsi
11
-
12
- STATE_COLORS = {
13
- Result::INITIALIZED => :blue, # Initial state - blue
14
- Result::EXECUTING => :yellow, # Currently executing - yellow
15
- Result::COMPLETE => :green, # Successfully completed - green
16
- Result::INTERRUPTED => :red # Execution interrupted - red
17
- }.freeze
18
- STATUS_COLORS = {
19
- Result::SUCCESS => :green, # Successful completion - green
20
- Result::SKIPPED => :yellow, # Intentionally skipped - yellow
21
- Result::FAILED => :red # Failed execution - red
22
- }.freeze
23
-
24
- module_function
25
-
26
- # Applies ANSI color formatting to a result state or status string.
27
- #
28
- # Takes a result state or status string and applies the appropriate ANSI
29
- # color formatting using the predefined color mappings. This provides
30
- # visual distinction for different execution outcomes in terminal output.
31
- #
32
- # @param s [String] the result state or status string to colorize
33
- #
34
- # @return [String] the input string with ANSI color codes applied
35
- #
36
- # @example Colorize a success status
37
- # ResultAnsi.call("success") #=> "\e[0;32;49msuccess\e[0m" (green)
38
- #
39
- # @example Colorize a failed status
40
- # ResultAnsi.call("failed") #=> "\e[0;31;49mfailed\e[0m" (red)
41
- #
42
- # @example Colorize an executing state
43
- # ResultAnsi.call("executing") #=> "\e[0;33;49mexecuting\e[0m" (yellow)
44
- def call(s)
45
- Utils::AnsiColor.call(s, color: color(s))
46
- end
47
-
48
- # Determines the appropriate color for a result state or status.
49
- #
50
- # Looks up the color mapping for the given state or status string,
51
- # returning the corresponding color symbol or :default if no specific
52
- # mapping is found.
53
- #
54
- # @param s [String] the result state or status string to find color for
55
- #
56
- # @return [Symbol] the color symbol (:blue, :yellow, :green, :red, or :default)
57
- #
58
- # @example Get color for success status
59
- # ResultAnsi.color("success") #=> :green
60
- #
61
- # @example Get color for unknown value
62
- # ResultAnsi.color("unknown") #=> :default
63
- #
64
- # @example Get color for executing state
65
- # ResultAnsi.color("executing") #=> :yellow
66
- def color(s)
67
- STATE_COLORS[s] || STATUS_COLORS[s] || :default
68
- end
69
-
70
- end
71
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Result inspection and formatting utilities for readable result representation.
5
- #
6
- # This module provides functionality to format result metadata into human-readable
7
- # strings for debugging, logging, and introspection purposes. It processes result
8
- # hashes and displays essential result information in a structured, ordered format
9
- # that emphasizes the most important attributes first.
10
- module ResultInspector
11
-
12
- ORDERED_KEYS = %i[
13
- class type index id state status outcome metadata
14
- tags pid runtime caused_failure threw_failure
15
- ].freeze
16
-
17
- module_function
18
-
19
- # Formats a result hash into a human-readable string representation.
20
- #
21
- # This method converts result metadata into a structured string format that
22
- # displays key result information in a predefined order. It handles special
23
- # formatting for class names, failure references, and standard key-value pairs.
24
- # The method filters the result hash to only include keys defined in ORDERED_KEYS
25
- # and applies appropriate formatting based on the key type.
26
- #
27
- # @param result [Hash] the result hash to format
28
- # @option result [String] :class the class name of the task or workflow
29
- # @option result [String] :type the type identifier (e.g., "Task", "Workflow")
30
- # @option result [Integer] :index the position index in the execution chain
31
- # @option result [String] :id the unique identifier of the result
32
- # @option result [String] :state the execution state (e.g., "executed", "skipped")
33
- # @option result [String] :status the execution status (e.g., "success", "failure")
34
- # @option result [String] :outcome the overall outcome (e.g., "good", "bad")
35
- # @option result [Hash] :metadata additional metadata associated with the result
36
- # @option result [Array] :tags the tags associated with the result
37
- # @option result [Integer] :pid the process ID if applicable
38
- # @option result [Float] :runtime the execution runtime in seconds
39
- # @option result [Hash] :caused_failure reference to a failure this result caused
40
- # @option result [Hash] :threw_failure reference to a failure this result threw
41
- #
42
- # @return [String] a formatted string representation of the result with key information
43
- #
44
- # @example Format a successful task result
45
- # result = MyTask.call
46
- # ResultInspector.call(result)
47
- # #=> "MyTask: type=Task index=0 id=abc123 state=executed status=success outcome=good"
48
- #
49
- # @example Format a result with failure reference
50
- # result = MyTask.call
51
- # ResultInspector.call(result)
52
- # #=> "MyTask: index=1 state=executed status=failure caused_failure=<[2] ValidationError: def456>"
53
- def call(result)
54
- ORDERED_KEYS.filter_map do |key|
55
- next unless result.key?(key)
56
-
57
- value = result[key]
58
-
59
- case key
60
- when :class
61
- "#{value}:"
62
- when :caused_failure, :threw_failure
63
- "#{key}=<[#{value[:index]}] #{value[:class]}: #{value[:id]}>"
64
- else
65
- "#{key}=#{value}"
66
- end
67
- end.join(" ")
68
- end
69
-
70
- end
71
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CMDx
4
- # Logger utilities for task execution results.
5
- #
6
- # This module provides functionality to log task execution results with
7
- # appropriate severity levels based on the result status. It automatically
8
- # determines the correct log level (info, warn, error) based on whether
9
- # the task succeeded, was skipped, or failed, and delegates to the task's
10
- # configured logger instance.
11
- module ResultLogger
12
-
13
- STATUS_TO_SEVERITY = {
14
- Result::SUCCESS => :info, # Successful task completion
15
- Result::SKIPPED => :warn, # Task was skipped
16
- Result::FAILED => :error # Task execution failed
17
- }.freeze
18
-
19
- module_function
20
-
21
- # Logs a task execution result with the appropriate severity level.
22
- #
23
- # Retrieves the logger from the task instance and logs the result object
24
- # using the severity level determined by the result's status. If no logger
25
- # is configured for the task, the method returns early without logging.
26
- # The logger level is temporarily set to match the severity to ensure
27
- # the message is captured regardless of current log level configuration.
28
- #
29
- # @param result [CMDx::Result] the task execution result to log
30
- #
31
- # @return [void]
32
- #
33
- # @example Log a successful task result
34
- # task = ProcessDataTask.call(data: "input")
35
- # ResultLogger.call(task.result)
36
- # # Logs at :info level: "Result: ProcessDataTask completed successfully"
37
- #
38
- # @example Log a failed task result
39
- # task = ValidateDataTask.call(data: "invalid")
40
- # ResultLogger.call(task.result)
41
- # # Logs at :error level: "Result: ValidateDataTask failed with error"
42
- #
43
- # @example Log a skipped task result
44
- # task = ConditionalTask.call(condition: false)
45
- # ResultLogger.call(task.result)
46
- # # Logs at :warn level: "Result: ConditionalTask was skipped"
47
- def call(result)
48
- logger = result.task.send(:logger)
49
- return if logger.nil?
50
-
51
- severity = STATUS_TO_SEVERITY[result.status]
52
-
53
- logger.with_level(severity) do
54
- logger.send(severity) { result }
55
- end
56
- end
57
-
58
- end
59
- end