cmdx 1.1.0 → 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.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- data/docs/basics/chain.md +190 -160
- data/docs/basics/context.md +242 -154
- data/docs/basics/setup.md +302 -32
- data/docs/callbacks.md +390 -94
- data/docs/configuration.md +181 -65
- data/docs/deprecation.md +245 -0
- data/docs/getting_started.md +161 -39
- data/docs/internationalization.md +590 -70
- data/docs/interruptions/exceptions.md +135 -118
- data/docs/interruptions/faults.md +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- data/docs/outcomes/result.md +140 -112
- data/docs/outcomes/states.md +134 -99
- data/docs/outcomes/statuses.md +204 -146
- data/docs/parameters/coercions.md +232 -281
- data/docs/parameters/defaults.md +224 -169
- data/docs/parameters/definitions.md +289 -141
- data/docs/parameters/namespacing.md +250 -161
- data/docs/parameters/validations.md +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
data/lib/cmdx/parameter.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Parameter definition
|
4
|
+
# Parameter definition and management for task attribute configuration.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# optional
|
6
|
+
# Parameter provides a flexible system for defining, validating, and managing
|
7
|
+
# task parameters with support for type coercion, nested parameter structures,
|
8
|
+
# validation rules, and dynamic attribute generation. Parameters can be defined
|
9
|
+
# as required or optional with various configuration options including custom
|
10
|
+
# naming, source specification, and child parameter definitions.
|
10
11
|
class Parameter
|
11
12
|
|
12
13
|
cmdx_attr_delegator :invalid?, :valid?,
|
@@ -36,22 +37,31 @@ module CMDx
|
|
36
37
|
# @return [CMDx::Errors] Validation errors for this parameter
|
37
38
|
attr_reader :errors
|
38
39
|
|
39
|
-
# Creates a new parameter definition with the
|
40
|
+
# Creates a new parameter definition with the specified configuration.
|
40
41
|
#
|
41
|
-
# @param name [Symbol]
|
42
|
-
# @param options [Hash]
|
43
|
-
# @option options [Class] :klass
|
44
|
-
# @option options [Parameter] :parent
|
45
|
-
# @option options [Symbol, Array<Symbol>] :type
|
46
|
-
# @option options [Boolean] :required
|
47
|
-
# @
|
48
|
-
# @
|
49
|
-
# @
|
42
|
+
# @param name [Symbol, String] the parameter name
|
43
|
+
# @param options [Hash] parameter configuration options
|
44
|
+
# @option options [Class] :klass the task class this parameter belongs to (required)
|
45
|
+
# @option options [Parameter] :parent the parent parameter for nested definitions
|
46
|
+
# @option options [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
|
47
|
+
# @option options [Boolean] :required whether the parameter is required for task execution
|
48
|
+
# @option options [Symbol] :source the source context for parameter resolution
|
49
|
+
# @option options [Symbol, String] :as custom method name for the parameter
|
50
|
+
# @option options [Hash] :validates validation rules to apply to the parameter
|
51
|
+
# @option options [Object] :default default value when parameter is not provided
|
52
|
+
# @param block [Proc] optional block for defining nested parameters
|
50
53
|
#
|
51
|
-
# @
|
52
|
-
# Parameter.new(:name, klass: MyTask, type: :string, required: true)
|
54
|
+
# @return [Parameter] a new parameter instance
|
53
55
|
#
|
54
|
-
# @
|
56
|
+
# @raise [KeyError] if the :klass option is not provided
|
57
|
+
#
|
58
|
+
# @example Create a simple required parameter
|
59
|
+
# Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
60
|
+
#
|
61
|
+
# @example Create parameter with validation
|
62
|
+
# Parameter.new(:email, klass: MyTask, type: :string, validates: { format: /@/ })
|
63
|
+
#
|
64
|
+
# @example Create nested parameter with children
|
55
65
|
# Parameter.new(:user, klass: MyTask, type: :hash) do
|
56
66
|
# required :name, type: :string
|
57
67
|
# optional :age, type: :integer
|
@@ -73,21 +83,32 @@ module CMDx
|
|
73
83
|
|
74
84
|
class << self
|
75
85
|
|
76
|
-
# Creates one or more optional
|
86
|
+
# Creates one or more optional parameter definitions.
|
87
|
+
#
|
88
|
+
# @param names [Array<Symbol>] parameter names to define as optional
|
89
|
+
# @param options [Hash] parameter configuration options
|
90
|
+
# @option options [Class] :klass the task class this parameter belongs to
|
91
|
+
# @option options [Parameter] :parent the parent parameter for nested definitions
|
92
|
+
# @option options [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
|
93
|
+
# @option options [Symbol] :source the source context for parameter resolution
|
94
|
+
# @option options [Symbol, String] :as custom method name (only allowed for single parameter)
|
95
|
+
# @option options [Hash] :validates validation rules to apply to the parameter
|
96
|
+
# @option options [Object] :default default value when parameter is not provided
|
97
|
+
# @param block [Proc] optional block for defining nested parameters
|
77
98
|
#
|
78
|
-
# @
|
79
|
-
# @param options [Hash] Configuration options for all parameters
|
80
|
-
# @param block [Proc] Optional block for defining nested parameters
|
81
|
-
# @return [Array<Parameter>] The created optional parameters
|
82
|
-
# @raise [ArgumentError] If no parameters are given or :as option is used with multiple names
|
99
|
+
# @return [Array<Parameter>] array of created optional parameter instances
|
83
100
|
#
|
84
|
-
# @
|
85
|
-
#
|
101
|
+
# @raise [ArgumentError] if no parameter names are provided
|
102
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
86
103
|
#
|
87
|
-
# @example
|
88
|
-
# Parameter.optional(:
|
89
|
-
#
|
90
|
-
#
|
104
|
+
# @example Define single optional parameter
|
105
|
+
# Parameter.optional(:description, klass: MyTask, type: :string)
|
106
|
+
#
|
107
|
+
# @example Define multiple optional parameters
|
108
|
+
# Parameter.optional(:name, :email, klass: MyTask, type: :string)
|
109
|
+
#
|
110
|
+
# @example Define optional parameter with custom name
|
111
|
+
# Parameter.optional(:user_id, klass: MyTask, type: :integer, as: :current_user_id)
|
91
112
|
def optional(*names, **options, &)
|
92
113
|
if names.none?
|
93
114
|
raise ArgumentError, "no parameters given"
|
@@ -98,133 +119,174 @@ module CMDx
|
|
98
119
|
names.filter_map { |n| new(n, **options, &) }
|
99
120
|
end
|
100
121
|
|
101
|
-
# Creates one or more required
|
122
|
+
# Creates one or more required parameter definitions.
|
123
|
+
#
|
124
|
+
# @param names [Array<Symbol>] parameter names to define as required
|
125
|
+
# @param options [Hash] parameter configuration options
|
126
|
+
# @option options [Class] :klass the task class this parameter belongs to
|
127
|
+
# @option options [Parameter] :parent the parent parameter for nested definitions
|
128
|
+
# @option options [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
|
129
|
+
# @option options [Symbol] :source the source context for parameter resolution
|
130
|
+
# @option options [Symbol, String] :as custom method name (only allowed for single parameter)
|
131
|
+
# @option options [Hash] :validates validation rules to apply to the parameter
|
132
|
+
# @option options [Object] :default default value when parameter is not provided
|
133
|
+
# @param block [Proc] optional block for defining nested parameters
|
134
|
+
#
|
135
|
+
# @return [Array<Parameter>] array of created required parameter instances
|
102
136
|
#
|
103
|
-
# @
|
104
|
-
# @
|
105
|
-
# @param block [Proc] Optional block for defining nested parameters
|
106
|
-
# @return [Array<Parameter>] The created required parameters
|
107
|
-
# @raise [ArgumentError] If no parameters are given or :as option is used with multiple names
|
137
|
+
# @raise [ArgumentError] if no parameter names are provided
|
138
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
108
139
|
#
|
109
|
-
# @example
|
110
|
-
# Parameter.required(:
|
140
|
+
# @example Define single required parameter
|
141
|
+
# Parameter.required(:user_id, klass: MyTask, type: :integer)
|
111
142
|
#
|
112
|
-
# @example
|
113
|
-
# Parameter.required(:
|
143
|
+
# @example Define multiple required parameters
|
144
|
+
# Parameter.required(:name, :email, klass: MyTask, type: :string)
|
145
|
+
#
|
146
|
+
# @example Define required parameter with validation
|
147
|
+
# Parameter.required(:email, klass: MyTask, type: :string, validates: { format: /@/ })
|
114
148
|
def required(*names, **options, &)
|
115
149
|
optional(*names, **options.merge(required: true), &)
|
116
150
|
end
|
117
151
|
|
118
152
|
end
|
119
153
|
|
120
|
-
#
|
154
|
+
# Defines optional child parameters for nested parameter structures.
|
121
155
|
#
|
122
|
-
# @param names [Array<Symbol>]
|
123
|
-
# @param options [Hash]
|
124
|
-
# @
|
125
|
-
# @
|
156
|
+
# @param names [Array<Symbol>] parameter names to define as optional children
|
157
|
+
# @param options [Hash] parameter configuration options
|
158
|
+
# @option options [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
|
159
|
+
# @option options [Symbol] :source the source context for parameter resolution
|
160
|
+
# @option options [Symbol, String] :as custom method name (only allowed for single parameter)
|
161
|
+
# @option options [Hash] :validates validation rules to apply to the parameter
|
162
|
+
# @option options [Object] :default default value when parameter is not provided
|
163
|
+
# @param block [Proc] optional block for defining nested parameters
|
126
164
|
#
|
127
|
-
# @
|
128
|
-
# user_param.optional(:nickname, :bio, type: :string)
|
165
|
+
# @return [Array<Parameter>] array of created optional child parameter instances
|
129
166
|
#
|
130
|
-
# @
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
167
|
+
# @raise [ArgumentError] if no parameter names are provided
|
168
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
169
|
+
#
|
170
|
+
# @example Define optional child parameters
|
171
|
+
# user_param = Parameter.new(:user, klass: MyTask, type: :hash)
|
172
|
+
# user_param.optional(:description, :bio, type: :string)
|
134
173
|
def optional(*names, **options, &)
|
135
174
|
parameters = Parameter.optional(*names, **options.merge(klass: @klass, parent: self), &)
|
136
175
|
children.concat(parameters)
|
137
176
|
end
|
138
177
|
|
139
|
-
#
|
178
|
+
# Defines required child parameters for nested parameter structures.
|
179
|
+
#
|
180
|
+
# @param names [Array<Symbol>] parameter names to define as required children
|
181
|
+
# @param options [Hash] parameter configuration options
|
182
|
+
# @option options [Symbol, Array<Symbol>] :type the parameter type(s) for coercion
|
183
|
+
# @option options [Symbol] :source the source context for parameter resolution
|
184
|
+
# @option options [Symbol, String] :as custom method name (only allowed for single parameter)
|
185
|
+
# @option options [Hash] :validates validation rules to apply to the parameter
|
186
|
+
# @option options [Object] :default default value when parameter is not provided
|
187
|
+
# @param block [Proc] optional block for defining nested parameters
|
140
188
|
#
|
141
|
-
# @
|
142
|
-
# @param options [Hash] Configuration options for all parameters
|
143
|
-
# @param block [Proc] Optional block for defining nested parameters
|
144
|
-
# @return [Array<Parameter>] The created required child parameters
|
189
|
+
# @return [Array<Parameter>] array of created required child parameter instances
|
145
190
|
#
|
146
|
-
# @
|
147
|
-
#
|
191
|
+
# @raise [ArgumentError] if no parameter names are provided
|
192
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
148
193
|
#
|
149
|
-
# @example
|
150
|
-
# user_param.
|
194
|
+
# @example Define required child parameters
|
195
|
+
# user_param = Parameter.new(:user, klass: MyTask, type: :hash)
|
196
|
+
# user_param.required(:name, :email, type: :string)
|
151
197
|
def required(*names, **options, &)
|
152
198
|
parameters = Parameter.required(*names, **options.merge(klass: @klass, parent: self), &)
|
153
199
|
children.concat(parameters)
|
154
200
|
end
|
155
201
|
|
156
|
-
# Checks if
|
202
|
+
# Checks if the parameter is marked as required for task execution.
|
157
203
|
#
|
158
|
-
# @return [Boolean]
|
204
|
+
# @return [Boolean] true if the parameter is required, false otherwise
|
159
205
|
#
|
160
206
|
# @example Check if parameter is required
|
161
|
-
# param.
|
207
|
+
# param = Parameter.new(:name, klass: MyTask, required: true)
|
208
|
+
# param.required? #=> true
|
162
209
|
def required?
|
163
210
|
!!@required
|
164
211
|
end
|
165
212
|
|
166
|
-
# Checks if
|
213
|
+
# Checks if the parameter is marked as optional for task execution.
|
167
214
|
#
|
168
|
-
# @return [Boolean]
|
215
|
+
# @return [Boolean] true if the parameter is optional, false otherwise
|
169
216
|
#
|
170
217
|
# @example Check if parameter is optional
|
171
|
-
# param.
|
218
|
+
# param = Parameter.new(:description, klass: MyTask, required: false)
|
219
|
+
# param.optional? #=> true
|
172
220
|
def optional?
|
173
221
|
!required?
|
174
222
|
end
|
175
223
|
|
176
|
-
#
|
224
|
+
# Generates the method name that will be created on the task class for this parameter.
|
177
225
|
#
|
178
|
-
# @return [Symbol]
|
226
|
+
# @return [Symbol] the method name with any configured prefix, suffix, or custom naming
|
179
227
|
#
|
180
|
-
# @example Get method name
|
181
|
-
# param
|
228
|
+
# @example Get method name for simple parameter
|
229
|
+
# param = Parameter.new(:user_id, klass: MyTask)
|
230
|
+
# param.method_name #=> :user_id
|
231
|
+
#
|
232
|
+
# @example Get method name with custom naming
|
233
|
+
# param = Parameter.new(:user_id, klass: MyTask, as: :current_user_id)
|
234
|
+
# param.method_name #=> :current_user_id
|
182
235
|
def method_name
|
183
236
|
@method_name ||= Utils::NameAffix.call(name, method_source, options)
|
184
237
|
end
|
185
238
|
|
186
|
-
#
|
239
|
+
# Determines the source context for parameter resolution and method name generation.
|
240
|
+
#
|
241
|
+
# @return [Symbol] the source identifier used for parameter resolution
|
187
242
|
#
|
188
|
-
# @
|
243
|
+
# @example Get method source for simple parameter
|
244
|
+
# param = Parameter.new(:user_id, klass: MyTask)
|
245
|
+
# param.method_source #=> :context
|
189
246
|
#
|
190
|
-
# @example Get method source
|
191
|
-
#
|
247
|
+
# @example Get method source for nested parameter
|
248
|
+
# parent = Parameter.new(:user, klass: MyTask)
|
249
|
+
# child = Parameter.new(:name, klass: MyTask, parent: parent)
|
250
|
+
# child.method_source #=> :user
|
192
251
|
def method_source
|
193
252
|
@method_source ||= options[:source] || parent&.method_name || :context
|
194
253
|
end
|
195
254
|
|
196
|
-
# Converts the parameter to a hash representation.
|
255
|
+
# Converts the parameter to a hash representation for serialization.
|
197
256
|
#
|
198
|
-
# @return [Hash]
|
257
|
+
# @return [Hash] hash containing all parameter metadata and configuration
|
199
258
|
#
|
200
|
-
# @example Convert to hash
|
201
|
-
# param
|
259
|
+
# @example Convert parameter to hash
|
260
|
+
# param = Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
261
|
+
# param.to_h
|
262
|
+
# #=> { name: :user_id, type: :integer, required: true, ... }
|
202
263
|
def to_h
|
203
264
|
ParameterSerializer.call(self)
|
204
265
|
end
|
205
266
|
|
206
|
-
# Converts the parameter to a string representation.
|
267
|
+
# Converts the parameter to a formatted string representation for inspection.
|
207
268
|
#
|
208
|
-
# @return [String]
|
269
|
+
# @return [String] human-readable string representation of the parameter
|
209
270
|
#
|
210
|
-
# @example Convert to string
|
211
|
-
# param
|
271
|
+
# @example Convert parameter to string
|
272
|
+
# param = Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
273
|
+
# param.to_s
|
274
|
+
# #=> "Parameter: name=user_id type=integer required=true ..."
|
212
275
|
def to_s
|
213
276
|
ParameterInspector.call(to_h)
|
214
277
|
end
|
215
278
|
|
216
279
|
private
|
217
280
|
|
218
|
-
#
|
219
|
-
#
|
281
|
+
# Dynamically defines a method on the task class for parameter value access.
|
282
|
+
#
|
283
|
+
# @param parameter [Parameter] the parameter to create a method for
|
220
284
|
#
|
221
|
-
# @param parameter [Parameter] The parameter to define the method for
|
222
285
|
# @return [void]
|
223
|
-
# @raise [CoercionError] If parameter value cannot be coerced to the expected type
|
224
|
-
# @raise [ValidationError] If parameter value fails validation
|
225
286
|
#
|
226
|
-
# @example Define parameter method
|
227
|
-
#
|
287
|
+
# @example Define parameter method on task class
|
288
|
+
# # Creates a private method that evaluates and caches parameter values
|
289
|
+
# # with automatic error handling for coercion and validation failures
|
228
290
|
def define_attribute(parameter)
|
229
291
|
klass.send(:define_method, parameter.method_name) do
|
230
292
|
@cmd_parameter_value_cache ||= {}
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
#
|
4
|
+
# Provides formatted inspection and display functionality for parameter objects.
|
5
5
|
#
|
6
|
-
# This module
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
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
10
|
module ParameterInspector
|
11
11
|
|
12
12
|
ORDERED_KEYS = %i[
|
@@ -15,30 +15,43 @@ module CMDx
|
|
15
15
|
|
16
16
|
module_function
|
17
17
|
|
18
|
-
# Formats a parameter hash into a human-readable string
|
18
|
+
# Formats a parameter hash into a human-readable inspection string.
|
19
19
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# indentation
|
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
24
|
#
|
25
25
|
# @param parameter [Hash] the parameter hash to format
|
26
|
-
# @
|
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)
|
27
33
|
#
|
28
|
-
# @return [String]
|
34
|
+
# @return [String] formatted multi-line string representation of the parameter
|
29
35
|
#
|
30
|
-
# @example Format a parameter
|
31
|
-
#
|
32
|
-
#
|
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,
|
33
46
|
# children: [
|
34
|
-
# { name: :
|
35
|
-
# { name: :
|
47
|
+
# { name: :amount, type: :big_decimal, required: true },
|
48
|
+
# { name: :currency, type: :string, required: true }
|
36
49
|
# ]
|
37
50
|
# }
|
38
|
-
# ParameterInspector.call(
|
39
|
-
#
|
40
|
-
# #
|
41
|
-
# #
|
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"
|
42
55
|
def call(parameter, depth = 1)
|
43
56
|
ORDERED_KEYS.filter_map do |key|
|
44
57
|
value = parameter[key]
|
@@ -1,34 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Registry for managing parameter definitions
|
4
|
+
# Registry for managing parameter definitions within tasks.
|
5
5
|
#
|
6
|
-
# This registry
|
7
|
-
#
|
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.
|
8
10
|
class ParameterRegistry
|
9
11
|
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# @return [Array] array containing parameter definition objects
|
12
|
+
# @return [Array<Parameter>] array containing parameter definition objects
|
13
13
|
attr_reader :registry
|
14
14
|
|
15
|
-
# Initializes a new parameter registry.
|
15
|
+
# Initializes a new parameter registry with an empty parameter collection.
|
16
16
|
#
|
17
17
|
# @return [ParameterRegistry] a new parameter registry instance
|
18
18
|
#
|
19
|
-
# @example Creating
|
20
|
-
# ParameterRegistry.new
|
19
|
+
# @example Creating a new registry
|
20
|
+
# registry = ParameterRegistry.new
|
21
|
+
# registry.registry #=> []
|
21
22
|
def initialize
|
22
23
|
@registry = []
|
23
24
|
end
|
24
25
|
|
25
|
-
# Creates a
|
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.
|
26
30
|
#
|
27
31
|
# @return [ParameterRegistry] a new registry instance with duplicated parameters
|
28
32
|
#
|
29
|
-
# @example
|
33
|
+
# @example Duplicate a registry
|
30
34
|
# original = ParameterRegistry.new
|
31
|
-
#
|
35
|
+
# duplicate = original.dup
|
36
|
+
# duplicate.object_id != original.object_id #=> true
|
32
37
|
def dup
|
33
38
|
new_registry = self.class.new
|
34
39
|
new_registry.instance_variable_set(:@registry, registry.map(&:dup))
|
@@ -39,43 +44,45 @@ module CMDx
|
|
39
44
|
#
|
40
45
|
# @return [Boolean] true if all parameters are valid, false otherwise
|
41
46
|
#
|
42
|
-
# @example
|
43
|
-
# registry.valid?
|
44
|
-
# # => true
|
47
|
+
# @example Check registry validity
|
48
|
+
# registry.valid? #=> true
|
45
49
|
def valid?
|
46
50
|
registry.all?(&:valid?)
|
47
51
|
end
|
48
52
|
|
49
53
|
# Validates all parameters in the registry against a task instance.
|
50
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
|
+
#
|
51
58
|
# @param task [Task] the task instance to validate parameters against
|
52
59
|
#
|
53
60
|
# @return [void]
|
54
61
|
#
|
55
|
-
# @
|
56
|
-
#
|
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)
|
57
66
|
def validate!(task)
|
58
67
|
registry.each { |p| recursive_validate!(task, p) }
|
59
68
|
end
|
60
69
|
|
61
|
-
#
|
70
|
+
# Converts the parameter registry to a hash representation.
|
62
71
|
#
|
63
|
-
# @return [Hash]
|
72
|
+
# @return [Array<Hash>] array of parameter hash representations
|
64
73
|
#
|
65
|
-
# @example
|
66
|
-
# registry.to_h
|
67
|
-
# # => { name: { type: :string, required: true }, age: { type: :integer } }
|
74
|
+
# @example Convert registry to hash
|
75
|
+
# registry.to_h #=> [{name: :user_id, type: :integer}, {name: :email, type: :string}]
|
68
76
|
def to_h
|
69
77
|
registry.map(&:to_h)
|
70
78
|
end
|
71
79
|
|
72
|
-
#
|
80
|
+
# Converts the parameter registry to a string representation.
|
73
81
|
#
|
74
|
-
# @return [String]
|
82
|
+
# @return [String] string representation of all parameters, joined by newlines
|
75
83
|
#
|
76
|
-
# @example
|
77
|
-
# registry.to_s
|
78
|
-
# # => "name (string, required), age (integer)"
|
84
|
+
# @example Convert registry to string
|
85
|
+
# registry.to_s #=> "user_id: integer\nemail: string"
|
79
86
|
def to_s
|
80
87
|
registry.map(&:to_s).join("\n")
|
81
88
|
end
|
@@ -84,13 +91,12 @@ module CMDx
|
|
84
91
|
|
85
92
|
# Recursively validates a parameter and its children against a task.
|
86
93
|
#
|
87
|
-
# @param task [Task] the task instance to validate against
|
94
|
+
# @param task [Task] the task instance to validate the parameter against
|
88
95
|
# @param parameter [Parameter] the parameter to validate
|
89
96
|
#
|
90
97
|
# @return [void]
|
91
98
|
#
|
92
|
-
# @
|
93
|
-
# recursive_validate!(task, parameter)
|
99
|
+
# @raise [NoMethodError] if the parameter method is not defined on the task
|
94
100
|
def recursive_validate!(task, parameter)
|
95
101
|
task.send(parameter.method_name) # Make sure parameter is defined on task
|
96
102
|
parameter.children.each { |child| recursive_validate!(task, child) }
|
@@ -1,32 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Parameter serialization
|
4
|
+
# Parameter serialization utilities for converting parameter objects to hash representations.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# logging, and introspection purposes.
|
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.
|
11
10
|
module ParameterSerializer
|
12
11
|
|
13
12
|
module_function
|
14
13
|
|
15
|
-
#
|
14
|
+
# Converts a parameter object into a hash representation for serialization.
|
16
15
|
#
|
17
|
-
#
|
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.
|
18
19
|
#
|
19
|
-
# @
|
20
|
+
# @param parameter [CMDx::Parameter] the parameter object to serialize
|
20
21
|
#
|
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
|
22
29
|
#
|
23
|
-
# @example Serialize a parameter with
|
24
|
-
#
|
30
|
+
# @example Serialize a nested parameter with children
|
31
|
+
# user_param = Parameter.new(:user, klass: MyTask, type: :hash) do
|
25
32
|
# required :name, type: :string
|
26
33
|
# optional :age, type: :integer
|
27
34
|
# end
|
28
|
-
# ParameterSerializer.call(
|
29
|
-
#
|
35
|
+
# ParameterSerializer.call(user_param)
|
36
|
+
# #=> {
|
30
37
|
# # source: :context,
|
31
38
|
# # name: :user,
|
32
39
|
# # type: :hash,
|