cmdx 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +21 -0
- data/.cursor/prompts/yardoc.md +13 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +29 -3
- data/README.md +2 -1
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +126 -60
- 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 +382 -119
- data/docs/configuration.md +211 -49
- 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 +152 -127
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +183 -120
- data/docs/middlewares.md +165 -392
- 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 +251 -289
- 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 +247 -159
- data/docs/testing.md +196 -203
- data/docs/workflows.md +146 -101
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +39 -55
- data/lib/cmdx/callback_registry.rb +80 -73
- data/lib/cmdx/chain.rb +65 -122
- data/lib/cmdx/chain_inspector.rb +23 -116
- data/lib/cmdx/chain_serializer.rb +34 -146
- data/lib/cmdx/coercion.rb +57 -0
- data/lib/cmdx/coercion_registry.rb +113 -0
- data/lib/cmdx/coercions/array.rb +18 -36
- data/lib/cmdx/coercions/big_decimal.rb +21 -33
- data/lib/cmdx/coercions/boolean.rb +21 -40
- data/lib/cmdx/coercions/complex.rb +18 -31
- data/lib/cmdx/coercions/date.rb +20 -39
- data/lib/cmdx/coercions/date_time.rb +22 -39
- data/lib/cmdx/coercions/float.rb +19 -32
- data/lib/cmdx/coercions/hash.rb +22 -41
- data/lib/cmdx/coercions/integer.rb +20 -33
- data/lib/cmdx/coercions/rational.rb +20 -32
- data/lib/cmdx/coercions/string.rb +23 -31
- data/lib/cmdx/coercions/time.rb +24 -40
- data/lib/cmdx/coercions/virtual.rb +14 -31
- data/lib/cmdx/configuration.rb +101 -162
- data/lib/cmdx/context.rb +34 -166
- data/lib/cmdx/core_ext/hash.rb +42 -67
- data/lib/cmdx/core_ext/module.rb +35 -79
- data/lib/cmdx/core_ext/object.rb +63 -98
- data/lib/cmdx/correlator.rb +59 -154
- data/lib/cmdx/error.rb +37 -202
- data/lib/cmdx/errors.rb +153 -216
- data/lib/cmdx/fault.rb +68 -150
- data/lib/cmdx/faults.rb +26 -137
- data/lib/cmdx/immutator.rb +22 -110
- data/lib/cmdx/lazy_struct.rb +110 -186
- data/lib/cmdx/log_formatters/json.rb +14 -40
- data/lib/cmdx/log_formatters/key_value.rb +14 -40
- data/lib/cmdx/log_formatters/line.rb +14 -48
- data/lib/cmdx/log_formatters/logstash.rb +14 -57
- data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
- data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
- data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
- data/lib/cmdx/log_formatters/raw.rb +19 -49
- data/lib/cmdx/logger.rb +22 -79
- data/lib/cmdx/logger_ansi.rb +31 -72
- data/lib/cmdx/logger_serializer.rb +74 -103
- data/lib/cmdx/middleware.rb +56 -60
- data/lib/cmdx/middleware_registry.rb +82 -77
- data/lib/cmdx/middlewares/correlate.rb +41 -226
- data/lib/cmdx/middlewares/timeout.rb +46 -185
- data/lib/cmdx/parameter.rb +167 -183
- data/lib/cmdx/parameter_evaluator.rb +231 -0
- data/lib/cmdx/parameter_inspector.rb +37 -55
- data/lib/cmdx/parameter_registry.rb +65 -84
- data/lib/cmdx/parameter_serializer.rb +32 -76
- data/lib/cmdx/railtie.rb +24 -107
- data/lib/cmdx/result.rb +254 -259
- data/lib/cmdx/result_ansi.rb +28 -80
- data/lib/cmdx/result_inspector.rb +34 -70
- data/lib/cmdx/result_logger.rb +23 -77
- data/lib/cmdx/result_serializer.rb +59 -125
- data/lib/cmdx/rspec/matchers.rb +28 -0
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
- data/lib/cmdx/task.rb +336 -427
- data/lib/cmdx/task_deprecator.rb +52 -0
- data/lib/cmdx/task_processor.rb +246 -0
- data/lib/cmdx/task_serializer.rb +34 -69
- data/lib/cmdx/utils/ansi_color.rb +13 -89
- data/lib/cmdx/utils/log_timestamp.rb +13 -42
- data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
- data/lib/cmdx/utils/name_affix.rb +21 -71
- data/lib/cmdx/validator.rb +57 -0
- data/lib/cmdx/validator_registry.rb +108 -0
- data/lib/cmdx/validators/exclusion.rb +55 -94
- data/lib/cmdx/validators/format.rb +31 -85
- data/lib/cmdx/validators/inclusion.rb +65 -110
- data/lib/cmdx/validators/length.rb +117 -133
- data/lib/cmdx/validators/numeric.rb +123 -130
- data/lib/cmdx/validators/presence.rb +38 -79
- data/lib/cmdx/version.rb +1 -7
- data/lib/cmdx/workflow.rb +58 -330
- data/lib/cmdx.rb +1 -1
- data/lib/generators/cmdx/install_generator.rb +14 -31
- data/lib/generators/cmdx/task_generator.rb +39 -55
- data/lib/generators/cmdx/templates/install.rb +24 -6
- data/lib/generators/cmdx/workflow_generator.rb +41 -66
- data/lib/locales/ar.yml +0 -1
- data/lib/locales/cs.yml +0 -1
- data/lib/locales/da.yml +0 -1
- data/lib/locales/de.yml +0 -1
- data/lib/locales/el.yml +0 -1
- data/lib/locales/en.yml +0 -1
- data/lib/locales/es.yml +0 -1
- data/lib/locales/fi.yml +0 -1
- data/lib/locales/fr.yml +0 -1
- data/lib/locales/he.yml +0 -1
- data/lib/locales/hi.yml +0 -1
- data/lib/locales/it.yml +0 -1
- data/lib/locales/ja.yml +0 -1
- data/lib/locales/ko.yml +0 -1
- data/lib/locales/nl.yml +0 -1
- data/lib/locales/no.yml +0 -1
- data/lib/locales/pl.yml +0 -1
- data/lib/locales/pt.yml +0 -1
- data/lib/locales/ru.yml +0 -1
- data/lib/locales/sv.yml +0 -1
- data/lib/locales/th.yml +0 -1
- data/lib/locales/tr.yml +0 -1
- data/lib/locales/vi.yml +0 -1
- data/lib/locales/zh.yml +0 -1
- metadata +36 -8
- data/lib/cmdx/parameter_validator.rb +0 -81
- data/lib/cmdx/parameter_value.rb +0 -244
- data/lib/cmdx/parameters_inspector.rb +0 -72
- data/lib/cmdx/parameters_serializer.rb +0 -115
- data/lib/cmdx/rspec/result_matchers.rb +0 -917
- data/lib/cmdx/rspec/task_matchers.rb +0 -570
- data/lib/cmdx/validators/custom.rb +0 -102
data/lib/cmdx/parameter.rb
CHANGED
@@ -1,95 +1,70 @@
|
|
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
|
-
#
|
10
|
-
#
|
11
|
-
# class ProcessOrderTask < CMDx::Task
|
12
|
-
# required :order_id
|
13
|
-
# optional :priority
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# @example Parameter with type coercion and validation
|
17
|
-
# class ProcessUserTask < CMDx::Task
|
18
|
-
# required :age, type: :integer, numeric: { min: 18, max: 120 }
|
19
|
-
# required :email, type: :string, format: { with: /@/ }
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# @example Nested parameters
|
23
|
-
# class ProcessOrderTask < CMDx::Task
|
24
|
-
# required :shipping_address do
|
25
|
-
# required :street, :city, :state
|
26
|
-
# optional :apartment
|
27
|
-
# end
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# @example Parameter with custom source
|
31
|
-
# class ProcessUserTask < CMDx::Task
|
32
|
-
# required :name, source: :user
|
33
|
-
# required :company_name, source: -> { user.company }
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# @example Parameter with default values
|
37
|
-
# class ProcessOrderTask < CMDx::Task
|
38
|
-
# optional :priority, default: "normal"
|
39
|
-
# optional :notification, default: -> { user.preferences.notify? }
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# @see CMDx::Task Task parameter integration
|
43
|
-
# @see CMDx::ParameterValue Parameter value resolution and validation
|
44
|
-
# @see CMDx::Parameters Parameter collection management
|
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.
|
45
11
|
class Parameter
|
46
12
|
|
47
|
-
|
48
|
-
|
13
|
+
cmdx_attr_delegator :invalid?, :valid?,
|
14
|
+
to: :errors
|
49
15
|
|
50
16
|
# @return [CMDx::Task] The task class this parameter belongs to
|
51
17
|
attr_accessor :task
|
52
18
|
|
53
19
|
# @return [Class] The task class this parameter is defined in
|
20
|
+
attr_reader :klass
|
21
|
+
|
54
22
|
# @return [Parameter, nil] The parent parameter for nested parameters
|
23
|
+
attr_reader :parent
|
24
|
+
|
55
25
|
# @return [Symbol] The parameter name
|
26
|
+
attr_reader :name
|
27
|
+
|
56
28
|
# @return [Symbol, Array<Symbol>] The parameter type(s) for coercion
|
29
|
+
attr_reader :type
|
30
|
+
|
57
31
|
# @return [Hash] The parameter configuration options
|
32
|
+
attr_reader :options
|
33
|
+
|
58
34
|
# @return [Array<Parameter>] Child parameters for nested parameter definitions
|
35
|
+
attr_reader :children
|
36
|
+
|
59
37
|
# @return [CMDx::Errors] Validation errors for this parameter
|
60
|
-
attr_reader :
|
38
|
+
attr_reader :errors
|
61
39
|
|
62
|
-
#
|
63
|
-
#
|
64
|
-
# Creates a parameter definition with the specified configuration options.
|
65
|
-
# Automatically defines accessor methods on the task class and processes
|
66
|
-
# any nested parameter definitions provided via block.
|
40
|
+
# Creates a new parameter definition with the specified configuration.
|
67
41
|
#
|
68
|
-
# @param name [Symbol]
|
69
|
-
# @param options [Hash]
|
70
|
-
# @option options [Class] :klass
|
71
|
-
# @option options [Parameter] :parent
|
72
|
-
# @option options [Symbol, Array<Symbol>] :type
|
73
|
-
# @option options [Boolean] :required
|
74
|
-
# @option options [
|
75
|
-
# @option options [Symbol,
|
76
|
-
# @option options [Hash]
|
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
|
77
53
|
#
|
78
|
-
# @
|
54
|
+
# @return [Parameter] a new parameter instance
|
79
55
|
#
|
80
|
-
# @raise [KeyError]
|
56
|
+
# @raise [KeyError] if the :klass option is not provided
|
81
57
|
#
|
82
|
-
# @example
|
58
|
+
# @example Create a simple required parameter
|
83
59
|
# Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
84
60
|
#
|
85
|
-
# @example
|
86
|
-
# Parameter.new(:email, klass: MyTask, type: :string,
|
87
|
-
# format: { with: /@/ }, presence: true)
|
61
|
+
# @example Create parameter with validation
|
62
|
+
# Parameter.new(:email, klass: MyTask, type: :string, validates: { format: /@/ })
|
88
63
|
#
|
89
|
-
# @example
|
90
|
-
# Parameter.new(:
|
91
|
-
# required :
|
92
|
-
# optional :
|
64
|
+
# @example Create nested parameter with children
|
65
|
+
# Parameter.new(:user, klass: MyTask, type: :hash) do
|
66
|
+
# required :name, type: :string
|
67
|
+
# optional :age, type: :integer
|
93
68
|
# end
|
94
69
|
def initialize(name, **options, &)
|
95
70
|
@klass = options.delete(:klass) || raise(KeyError, "klass option required")
|
@@ -108,26 +83,32 @@ module CMDx
|
|
108
83
|
|
109
84
|
class << self
|
110
85
|
|
111
|
-
#
|
86
|
+
# Creates one or more optional parameter definitions.
|
112
87
|
#
|
113
|
-
#
|
114
|
-
#
|
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
|
115
98
|
#
|
116
|
-
# @
|
117
|
-
# @param options [Hash] Parameter configuration options
|
118
|
-
# @yield Optional block for nested parameter definitions
|
99
|
+
# @return [Array<Parameter>] array of created optional parameter instances
|
119
100
|
#
|
120
|
-
# @
|
121
|
-
# @raise [ArgumentError]
|
101
|
+
# @raise [ArgumentError] if no parameter names are provided
|
102
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
122
103
|
#
|
123
|
-
# @example
|
124
|
-
# Parameter.optional(:
|
104
|
+
# @example Define single optional parameter
|
105
|
+
# Parameter.optional(:description, klass: MyTask, type: :string)
|
125
106
|
#
|
126
|
-
# @example
|
127
|
-
# Parameter.optional(:
|
107
|
+
# @example Define multiple optional parameters
|
108
|
+
# Parameter.optional(:name, :email, klass: MyTask, type: :string)
|
128
109
|
#
|
129
|
-
# @example
|
130
|
-
# Parameter.optional(:
|
110
|
+
# @example Define optional parameter with custom name
|
111
|
+
# Parameter.optional(:user_id, klass: MyTask, type: :integer, as: :current_user_id)
|
131
112
|
def optional(*names, **options, &)
|
132
113
|
if names.none?
|
133
114
|
raise ArgumentError, "no parameters given"
|
@@ -138,187 +119,190 @@ module CMDx
|
|
138
119
|
names.filter_map { |n| new(n, **options, &) }
|
139
120
|
end
|
140
121
|
|
141
|
-
#
|
122
|
+
# Creates one or more required parameter definitions.
|
142
123
|
#
|
143
|
-
#
|
144
|
-
#
|
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
|
145
134
|
#
|
146
|
-
# @
|
147
|
-
# @param options [Hash] Parameter configuration options
|
148
|
-
# @yield Optional block for nested parameter definitions
|
135
|
+
# @return [Array<Parameter>] array of created required parameter instances
|
149
136
|
#
|
150
|
-
# @
|
151
|
-
# @raise [ArgumentError]
|
137
|
+
# @raise [ArgumentError] if no parameter names are provided
|
138
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
152
139
|
#
|
153
|
-
# @example
|
154
|
-
# Parameter.required(:user_id, type: :integer)
|
140
|
+
# @example Define single required parameter
|
141
|
+
# Parameter.required(:user_id, klass: MyTask, type: :integer)
|
155
142
|
#
|
156
|
-
# @example
|
157
|
-
# Parameter.required(:
|
143
|
+
# @example Define multiple required parameters
|
144
|
+
# Parameter.required(:name, :email, klass: MyTask, type: :string)
|
158
145
|
#
|
159
|
-
# @example
|
160
|
-
# Parameter.required(:
|
146
|
+
# @example Define required parameter with validation
|
147
|
+
# Parameter.required(:email, klass: MyTask, type: :string, validates: { format: /@/ })
|
161
148
|
def required(*names, **options, &)
|
162
149
|
optional(*names, **options.merge(required: true), &)
|
163
150
|
end
|
164
151
|
|
165
152
|
end
|
166
153
|
|
167
|
-
# Defines
|
168
|
-
#
|
169
|
-
# Creates child parameter definitions that inherit this parameter as their source.
|
170
|
-
# Child parameters are only validated if the parent parameter is provided.
|
154
|
+
# Defines optional child parameters for nested parameter structures.
|
171
155
|
#
|
172
|
-
# @param names [Array<Symbol>]
|
173
|
-
# @param options [Hash]
|
174
|
-
# @
|
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
|
175
164
|
#
|
176
|
-
# @return [Array<Parameter>]
|
165
|
+
# @return [Array<Parameter>] array of created optional child parameter instances
|
177
166
|
#
|
178
|
-
# @
|
179
|
-
#
|
167
|
+
# @raise [ArgumentError] if no parameter names are provided
|
168
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
180
169
|
#
|
181
|
-
# @example
|
182
|
-
# user_param.
|
170
|
+
# @example Define optional child parameters
|
171
|
+
# user_param = Parameter.new(:user, klass: MyTask, type: :hash)
|
172
|
+
# user_param.optional(:description, :bio, type: :string)
|
183
173
|
def optional(*names, **options, &)
|
184
174
|
parameters = Parameter.optional(*names, **options.merge(klass: @klass, parent: self), &)
|
185
175
|
children.concat(parameters)
|
186
176
|
end
|
187
177
|
|
188
|
-
# Defines
|
178
|
+
# Defines required child parameters for nested parameter structures.
|
189
179
|
#
|
190
|
-
#
|
191
|
-
#
|
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
|
192
188
|
#
|
193
|
-
# @
|
194
|
-
# @param options [Hash] Parameter configuration options
|
195
|
-
# @yield Optional block for further nested parameter definitions
|
189
|
+
# @return [Array<Parameter>] array of created required child parameter instances
|
196
190
|
#
|
197
|
-
# @
|
191
|
+
# @raise [ArgumentError] if no parameter names are provided
|
192
|
+
# @raise [ArgumentError] if :as option is used with multiple parameter names
|
198
193
|
#
|
199
|
-
# @example
|
200
|
-
#
|
201
|
-
#
|
202
|
-
# @example Nested parameter with validation
|
203
|
-
# payment_param.required(:amount, type: :float, numeric: { min: 0.01 })
|
194
|
+
# @example Define required child parameters
|
195
|
+
# user_param = Parameter.new(:user, klass: MyTask, type: :hash)
|
196
|
+
# user_param.required(:name, :email, type: :string)
|
204
197
|
def required(*names, **options, &)
|
205
198
|
parameters = Parameter.required(*names, **options.merge(klass: @klass, parent: self), &)
|
206
199
|
children.concat(parameters)
|
207
200
|
end
|
208
201
|
|
209
|
-
# Checks if
|
202
|
+
# Checks if the parameter is marked as required for task execution.
|
210
203
|
#
|
211
|
-
# @return [Boolean] true if parameter is required, false otherwise
|
204
|
+
# @return [Boolean] true if the parameter is required, false otherwise
|
212
205
|
#
|
213
|
-
# @example
|
214
|
-
#
|
215
|
-
#
|
206
|
+
# @example Check if parameter is required
|
207
|
+
# param = Parameter.new(:name, klass: MyTask, required: true)
|
208
|
+
# param.required? #=> true
|
216
209
|
def required?
|
217
210
|
!!@required
|
218
211
|
end
|
219
212
|
|
220
|
-
# Checks if
|
213
|
+
# Checks if the parameter is marked as optional for task execution.
|
221
214
|
#
|
222
|
-
# @return [Boolean] true if parameter is optional, false otherwise
|
215
|
+
# @return [Boolean] true if the parameter is optional, false otherwise
|
223
216
|
#
|
224
|
-
# @example
|
225
|
-
#
|
226
|
-
#
|
217
|
+
# @example Check if parameter is optional
|
218
|
+
# param = Parameter.new(:description, klass: MyTask, required: false)
|
219
|
+
# param.optional? #=> true
|
227
220
|
def optional?
|
228
221
|
!required?
|
229
222
|
end
|
230
223
|
|
231
|
-
#
|
232
|
-
#
|
233
|
-
# The method name is generated using NameAffix utility and can be customized
|
234
|
-
# with :as, :prefix, and :suffix options.
|
224
|
+
# Generates the method name that will be created on the task class for this parameter.
|
235
225
|
#
|
236
|
-
# @return [Symbol]
|
226
|
+
# @return [Symbol] the method name with any configured prefix, suffix, or custom naming
|
237
227
|
#
|
238
|
-
# @example
|
239
|
-
# Parameter.new(:user_id, klass:
|
228
|
+
# @example Get method name for simple parameter
|
229
|
+
# param = Parameter.new(:user_id, klass: MyTask)
|
230
|
+
# param.method_name #=> :user_id
|
240
231
|
#
|
241
|
-
# @example
|
242
|
-
# Parameter.new(:
|
243
|
-
#
|
244
|
-
# @example Method name with prefix
|
245
|
-
# Parameter.new(:name, klass: Task, prefix: "get_").method_name # => :get_name
|
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
|
246
235
|
def method_name
|
247
236
|
@method_name ||= Utils::NameAffix.call(name, method_source, options)
|
248
237
|
end
|
249
238
|
|
250
|
-
#
|
251
|
-
#
|
252
|
-
# Determines where the parameter value should be retrieved from, defaulting
|
253
|
-
# to :context or inheriting from parent parameter.
|
254
|
-
#
|
255
|
-
# @return [Symbol] The source method name
|
239
|
+
# Determines the source context for parameter resolution and method name generation.
|
256
240
|
#
|
257
|
-
# @
|
258
|
-
# Parameter.new(:user_id, klass: Task).method_source # => :context
|
241
|
+
# @return [Symbol] the source identifier used for parameter resolution
|
259
242
|
#
|
260
|
-
# @example
|
261
|
-
# Parameter.new(:
|
243
|
+
# @example Get method source for simple parameter
|
244
|
+
# param = Parameter.new(:user_id, klass: MyTask)
|
245
|
+
# param.method_source #=> :context
|
262
246
|
#
|
263
|
-
# @example
|
264
|
-
#
|
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
|
265
251
|
def method_source
|
266
252
|
@method_source ||= options[:source] || parent&.method_name || :context
|
267
253
|
end
|
268
254
|
|
269
|
-
# Converts the parameter to a hash representation.
|
255
|
+
# Converts the parameter to a hash representation for serialization.
|
270
256
|
#
|
271
|
-
# @return [Hash]
|
257
|
+
# @return [Hash] hash containing all parameter metadata and configuration
|
272
258
|
#
|
273
|
-
# @example
|
259
|
+
# @example Convert parameter to hash
|
260
|
+
# param = Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
274
261
|
# param.to_h
|
275
|
-
#
|
276
|
-
# # source: :context,
|
277
|
-
# # name: :user_id,
|
278
|
-
# # type: :integer,
|
279
|
-
# # required: true,
|
280
|
-
# # options: { numeric: { min: 1 } },
|
281
|
-
# # children: []
|
282
|
-
# # }
|
262
|
+
# #=> { name: :user_id, type: :integer, required: true, ... }
|
283
263
|
def to_h
|
284
264
|
ParameterSerializer.call(self)
|
285
265
|
end
|
286
266
|
|
287
|
-
# Converts the parameter to a string representation for inspection.
|
267
|
+
# Converts the parameter to a formatted string representation for inspection.
|
288
268
|
#
|
289
|
-
# @return [String]
|
269
|
+
# @return [String] human-readable string representation of the parameter
|
290
270
|
#
|
291
|
-
# @example
|
271
|
+
# @example Convert parameter to string
|
272
|
+
# param = Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
|
292
273
|
# param.to_s
|
293
|
-
#
|
274
|
+
# #=> "Parameter: name=user_id type=integer required=true ..."
|
294
275
|
def to_s
|
295
276
|
ParameterInspector.call(to_h)
|
296
277
|
end
|
297
278
|
|
298
279
|
private
|
299
280
|
|
300
|
-
#
|
281
|
+
# Dynamically defines a method on the task class for parameter value access.
|
301
282
|
#
|
302
|
-
#
|
303
|
-
# type coercion, validation, and error handling with caching.
|
283
|
+
# @param parameter [Parameter] the parameter to create a method for
|
304
284
|
#
|
305
|
-
# @param parameter [Parameter] The parameter to define method for
|
306
285
|
# @return [void]
|
286
|
+
#
|
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
|
307
290
|
def define_attribute(parameter)
|
308
291
|
klass.send(:define_method, parameter.method_name) do
|
309
|
-
@
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
292
|
+
@cmd_parameter_value_cache ||= {}
|
293
|
+
|
294
|
+
unless @cmd_parameter_value_cache.key?(parameter.method_name)
|
295
|
+
begin
|
296
|
+
parameter_value = ParameterEvaluator.call(self, parameter)
|
297
|
+
rescue CoercionError, ValidationError => e
|
298
|
+
parameter.errors.add(parameter.method_name, e.message)
|
299
|
+
errors.merge!(parameter.errors.to_hash)
|
300
|
+
ensure
|
301
|
+
@cmd_parameter_value_cache[parameter.method_name] = parameter_value
|
302
|
+
end
|
319
303
|
end
|
320
304
|
|
321
|
-
@
|
305
|
+
@cmd_parameter_value_cache[parameter.method_name]
|
322
306
|
end
|
323
307
|
|
324
308
|
klass.send(:private, parameter.method_name)
|