cmdx 1.1.2 → 1.5.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.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +4 -1
- data/.cursor/prompts/llms.md +20 -0
- data/.cursor/prompts/rspec.md +4 -1
- data/.cursor/prompts/yardoc.md +3 -2
- data/.cursor/rules/cursor-instructions.mdc +55 -1
- data/.irbrc +6 -0
- data/.rubocop.yml +29 -18
- data/CHANGELOG.md +11 -132
- data/LLM.md +3317 -0
- data/README.md +68 -44
- data/docs/attributes/coercions.md +162 -0
- data/docs/attributes/defaults.md +90 -0
- data/docs/attributes/definitions.md +281 -0
- data/docs/attributes/naming.md +78 -0
- data/docs/attributes/validations.md +309 -0
- data/docs/basics/chain.md +56 -249
- data/docs/basics/context.md +56 -289
- data/docs/basics/execution.md +114 -0
- data/docs/basics/setup.md +37 -334
- data/docs/callbacks.md +89 -467
- data/docs/deprecation.md +91 -174
- data/docs/getting_started.md +212 -202
- data/docs/internationalization.md +11 -647
- data/docs/interruptions/exceptions.md +23 -198
- data/docs/interruptions/faults.md +71 -151
- data/docs/interruptions/halt.md +109 -186
- data/docs/logging.md +44 -256
- data/docs/middlewares.md +113 -426
- data/docs/outcomes/result.md +81 -228
- data/docs/outcomes/states.md +33 -221
- data/docs/outcomes/statuses.md +21 -311
- data/docs/tips_and_tricks.md +120 -70
- data/docs/workflows.md +99 -283
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/attribute.rb +229 -0
- data/lib/cmdx/attribute_registry.rb +94 -0
- data/lib/cmdx/attribute_value.rb +193 -0
- data/lib/cmdx/callback_registry.rb +69 -77
- data/lib/cmdx/chain.rb +56 -73
- data/lib/cmdx/coercion_registry.rb +52 -68
- data/lib/cmdx/coercions/array.rb +19 -18
- data/lib/cmdx/coercions/big_decimal.rb +20 -24
- data/lib/cmdx/coercions/boolean.rb +26 -25
- data/lib/cmdx/coercions/complex.rb +21 -22
- data/lib/cmdx/coercions/date.rb +25 -23
- data/lib/cmdx/coercions/date_time.rb +24 -25
- data/lib/cmdx/coercions/float.rb +25 -22
- data/lib/cmdx/coercions/hash.rb +31 -32
- data/lib/cmdx/coercions/integer.rb +30 -24
- data/lib/cmdx/coercions/rational.rb +29 -24
- data/lib/cmdx/coercions/string.rb +19 -22
- data/lib/cmdx/coercions/symbol.rb +37 -0
- data/lib/cmdx/coercions/time.rb +26 -25
- data/lib/cmdx/configuration.rb +49 -108
- data/lib/cmdx/context.rb +222 -44
- data/lib/cmdx/deprecator.rb +61 -0
- data/lib/cmdx/errors.rb +42 -252
- data/lib/cmdx/exceptions.rb +39 -0
- data/lib/cmdx/faults.rb +78 -39
- data/lib/cmdx/freezer.rb +51 -0
- data/lib/cmdx/identifier.rb +30 -0
- data/lib/cmdx/locale.rb +52 -0
- data/lib/cmdx/log_formatters/json.rb +21 -22
- data/lib/cmdx/log_formatters/key_value.rb +20 -22
- data/lib/cmdx/log_formatters/line.rb +15 -22
- data/lib/cmdx/log_formatters/logstash.rb +22 -23
- data/lib/cmdx/log_formatters/raw.rb +16 -22
- data/lib/cmdx/middleware_registry.rb +70 -74
- data/lib/cmdx/middlewares/correlate.rb +90 -54
- data/lib/cmdx/middlewares/runtime.rb +58 -0
- data/lib/cmdx/middlewares/timeout.rb +48 -68
- data/lib/cmdx/railtie.rb +12 -45
- data/lib/cmdx/result.rb +229 -314
- data/lib/cmdx/task.rb +194 -366
- data/lib/cmdx/utils/call.rb +49 -0
- data/lib/cmdx/utils/condition.rb +71 -0
- data/lib/cmdx/utils/format.rb +61 -0
- data/lib/cmdx/validator_registry.rb +63 -72
- data/lib/cmdx/validators/exclusion.rb +38 -67
- data/lib/cmdx/validators/format.rb +48 -49
- data/lib/cmdx/validators/inclusion.rb +43 -74
- data/lib/cmdx/validators/length.rb +101 -162
- data/lib/cmdx/validators/numeric.rb +95 -170
- data/lib/cmdx/validators/presence.rb +37 -50
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/worker.rb +178 -0
- data/lib/cmdx/workflow.rb +85 -81
- data/lib/cmdx.rb +19 -13
- data/lib/generators/cmdx/install_generator.rb +14 -13
- data/lib/generators/cmdx/task_generator.rb +25 -50
- data/lib/generators/cmdx/templates/install.rb +11 -46
- data/lib/generators/cmdx/templates/task.rb.tt +3 -2
- data/lib/locales/en.yml +18 -4
- data/src/cmdx-logo.png +0 -0
- metadata +32 -116
- data/docs/ai_prompts.md +0 -393
- data/docs/basics/call.md +0 -317
- data/docs/configuration.md +0 -344
- data/docs/parameters/coercions.md +0 -396
- data/docs/parameters/defaults.md +0 -335
- data/docs/parameters/definitions.md +0 -446
- data/docs/parameters/namespacing.md +0 -378
- data/docs/parameters/validations.md +0 -405
- data/docs/testing.md +0 -553
- data/lib/cmdx/callback.rb +0 -53
- data/lib/cmdx/chain_inspector.rb +0 -56
- data/lib/cmdx/chain_serializer.rb +0 -63
- data/lib/cmdx/coercion.rb +0 -57
- data/lib/cmdx/coercions/virtual.rb +0 -29
- data/lib/cmdx/core_ext/hash.rb +0 -83
- data/lib/cmdx/core_ext/module.rb +0 -98
- data/lib/cmdx/core_ext/object.rb +0 -125
- data/lib/cmdx/correlator.rb +0 -122
- data/lib/cmdx/error.rb +0 -67
- data/lib/cmdx/fault.rb +0 -140
- data/lib/cmdx/immutator.rb +0 -52
- data/lib/cmdx/lazy_struct.rb +0 -246
- data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
- data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
- data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
- data/lib/cmdx/logger.rb +0 -49
- data/lib/cmdx/logger_ansi.rb +0 -68
- data/lib/cmdx/logger_serializer.rb +0 -116
- data/lib/cmdx/middleware.rb +0 -70
- data/lib/cmdx/parameter.rb +0 -312
- data/lib/cmdx/parameter_evaluator.rb +0 -231
- data/lib/cmdx/parameter_inspector.rb +0 -66
- data/lib/cmdx/parameter_registry.rb +0 -106
- data/lib/cmdx/parameter_serializer.rb +0 -59
- data/lib/cmdx/result_ansi.rb +0 -71
- data/lib/cmdx/result_inspector.rb +0 -71
- data/lib/cmdx/result_logger.rb +0 -59
- data/lib/cmdx/result_serializer.rb +0 -104
- data/lib/cmdx/rspec/matchers.rb +0 -28
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
- data/lib/cmdx/task_deprecator.rb +0 -58
- data/lib/cmdx/task_processor.rb +0 -246
- data/lib/cmdx/task_serializer.rb +0 -57
- data/lib/cmdx/utils/ansi_color.rb +0 -73
- data/lib/cmdx/utils/log_timestamp.rb +0 -36
- data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
- data/lib/cmdx/utils/name_affix.rb +0 -52
- data/lib/cmdx/validator.rb +0 -57
- data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
- data/lib/generators/cmdx/workflow_generator.rb +0 -84
- data/lib/locales/ar.yml +0 -35
- data/lib/locales/cs.yml +0 -35
- data/lib/locales/da.yml +0 -35
- data/lib/locales/de.yml +0 -35
- data/lib/locales/el.yml +0 -35
- data/lib/locales/es.yml +0 -35
- data/lib/locales/fi.yml +0 -35
- data/lib/locales/fr.yml +0 -35
- data/lib/locales/he.yml +0 -35
- data/lib/locales/hi.yml +0 -35
- data/lib/locales/it.yml +0 -35
- data/lib/locales/ja.yml +0 -35
- data/lib/locales/ko.yml +0 -35
- data/lib/locales/nl.yml +0 -35
- data/lib/locales/no.yml +0 -35
- data/lib/locales/pl.yml +0 -35
- data/lib/locales/pt.yml +0 -35
- data/lib/locales/ru.yml +0 -35
- data/lib/locales/sv.yml +0 -35
- data/lib/locales/th.yml +0 -35
- data/lib/locales/tr.yml +0 -35
- data/lib/locales/vi.yml +0 -35
- 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
|
data/lib/cmdx/result_ansi.rb
DELETED
@@ -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
|
data/lib/cmdx/result_logger.rb
DELETED
@@ -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
|