cmdx 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +21 -0
  4. data/.cursor/prompts/yardoc.md +13 -0
  5. data/.rubocop.yml +2 -0
  6. data/CHANGELOG.md +29 -3
  7. data/README.md +2 -1
  8. data/docs/ai_prompts.md +269 -195
  9. data/docs/basics/call.md +126 -60
  10. data/docs/basics/chain.md +190 -160
  11. data/docs/basics/context.md +242 -154
  12. data/docs/basics/setup.md +302 -32
  13. data/docs/callbacks.md +382 -119
  14. data/docs/configuration.md +211 -49
  15. data/docs/deprecation.md +245 -0
  16. data/docs/getting_started.md +161 -39
  17. data/docs/internationalization.md +590 -70
  18. data/docs/interruptions/exceptions.md +135 -118
  19. data/docs/interruptions/faults.md +152 -127
  20. data/docs/interruptions/halt.md +134 -80
  21. data/docs/logging.md +183 -120
  22. data/docs/middlewares.md +165 -392
  23. data/docs/outcomes/result.md +140 -112
  24. data/docs/outcomes/states.md +134 -99
  25. data/docs/outcomes/statuses.md +204 -146
  26. data/docs/parameters/coercions.md +251 -289
  27. data/docs/parameters/defaults.md +224 -169
  28. data/docs/parameters/definitions.md +289 -141
  29. data/docs/parameters/namespacing.md +250 -161
  30. data/docs/parameters/validations.md +247 -159
  31. data/docs/testing.md +196 -203
  32. data/docs/workflows.md +146 -101
  33. data/lib/cmdx/.DS_Store +0 -0
  34. data/lib/cmdx/callback.rb +39 -55
  35. data/lib/cmdx/callback_registry.rb +80 -73
  36. data/lib/cmdx/chain.rb +65 -122
  37. data/lib/cmdx/chain_inspector.rb +23 -116
  38. data/lib/cmdx/chain_serializer.rb +34 -146
  39. data/lib/cmdx/coercion.rb +57 -0
  40. data/lib/cmdx/coercion_registry.rb +113 -0
  41. data/lib/cmdx/coercions/array.rb +18 -36
  42. data/lib/cmdx/coercions/big_decimal.rb +21 -33
  43. data/lib/cmdx/coercions/boolean.rb +21 -40
  44. data/lib/cmdx/coercions/complex.rb +18 -31
  45. data/lib/cmdx/coercions/date.rb +20 -39
  46. data/lib/cmdx/coercions/date_time.rb +22 -39
  47. data/lib/cmdx/coercions/float.rb +19 -32
  48. data/lib/cmdx/coercions/hash.rb +22 -41
  49. data/lib/cmdx/coercions/integer.rb +20 -33
  50. data/lib/cmdx/coercions/rational.rb +20 -32
  51. data/lib/cmdx/coercions/string.rb +23 -31
  52. data/lib/cmdx/coercions/time.rb +24 -40
  53. data/lib/cmdx/coercions/virtual.rb +14 -31
  54. data/lib/cmdx/configuration.rb +101 -162
  55. data/lib/cmdx/context.rb +34 -166
  56. data/lib/cmdx/core_ext/hash.rb +42 -67
  57. data/lib/cmdx/core_ext/module.rb +35 -79
  58. data/lib/cmdx/core_ext/object.rb +63 -98
  59. data/lib/cmdx/correlator.rb +59 -154
  60. data/lib/cmdx/error.rb +37 -202
  61. data/lib/cmdx/errors.rb +153 -216
  62. data/lib/cmdx/fault.rb +68 -150
  63. data/lib/cmdx/faults.rb +26 -137
  64. data/lib/cmdx/immutator.rb +22 -110
  65. data/lib/cmdx/lazy_struct.rb +110 -186
  66. data/lib/cmdx/log_formatters/json.rb +14 -40
  67. data/lib/cmdx/log_formatters/key_value.rb +14 -40
  68. data/lib/cmdx/log_formatters/line.rb +14 -48
  69. data/lib/cmdx/log_formatters/logstash.rb +14 -57
  70. data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
  71. data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
  72. data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
  73. data/lib/cmdx/log_formatters/raw.rb +19 -49
  74. data/lib/cmdx/logger.rb +22 -79
  75. data/lib/cmdx/logger_ansi.rb +31 -72
  76. data/lib/cmdx/logger_serializer.rb +74 -103
  77. data/lib/cmdx/middleware.rb +56 -60
  78. data/lib/cmdx/middleware_registry.rb +82 -77
  79. data/lib/cmdx/middlewares/correlate.rb +41 -226
  80. data/lib/cmdx/middlewares/timeout.rb +46 -185
  81. data/lib/cmdx/parameter.rb +167 -183
  82. data/lib/cmdx/parameter_evaluator.rb +231 -0
  83. data/lib/cmdx/parameter_inspector.rb +37 -55
  84. data/lib/cmdx/parameter_registry.rb +65 -84
  85. data/lib/cmdx/parameter_serializer.rb +32 -76
  86. data/lib/cmdx/railtie.rb +24 -107
  87. data/lib/cmdx/result.rb +254 -259
  88. data/lib/cmdx/result_ansi.rb +28 -80
  89. data/lib/cmdx/result_inspector.rb +34 -70
  90. data/lib/cmdx/result_logger.rb +23 -77
  91. data/lib/cmdx/result_serializer.rb +59 -125
  92. data/lib/cmdx/rspec/matchers.rb +28 -0
  93. data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
  94. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
  95. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
  96. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
  97. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
  98. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
  99. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
  100. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
  101. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
  102. data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
  103. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
  104. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
  105. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
  106. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
  107. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
  108. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
  109. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
  110. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
  111. data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
  112. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
  113. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
  114. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
  115. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
  116. data/lib/cmdx/task.rb +336 -427
  117. data/lib/cmdx/task_deprecator.rb +52 -0
  118. data/lib/cmdx/task_processor.rb +246 -0
  119. data/lib/cmdx/task_serializer.rb +34 -69
  120. data/lib/cmdx/utils/ansi_color.rb +13 -89
  121. data/lib/cmdx/utils/log_timestamp.rb +13 -42
  122. data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
  123. data/lib/cmdx/utils/name_affix.rb +21 -71
  124. data/lib/cmdx/validator.rb +57 -0
  125. data/lib/cmdx/validator_registry.rb +108 -0
  126. data/lib/cmdx/validators/exclusion.rb +55 -94
  127. data/lib/cmdx/validators/format.rb +31 -85
  128. data/lib/cmdx/validators/inclusion.rb +65 -110
  129. data/lib/cmdx/validators/length.rb +117 -133
  130. data/lib/cmdx/validators/numeric.rb +123 -130
  131. data/lib/cmdx/validators/presence.rb +38 -79
  132. data/lib/cmdx/version.rb +1 -7
  133. data/lib/cmdx/workflow.rb +58 -330
  134. data/lib/cmdx.rb +1 -1
  135. data/lib/generators/cmdx/install_generator.rb +14 -31
  136. data/lib/generators/cmdx/task_generator.rb +39 -55
  137. data/lib/generators/cmdx/templates/install.rb +24 -6
  138. data/lib/generators/cmdx/workflow_generator.rb +41 -66
  139. data/lib/locales/ar.yml +0 -1
  140. data/lib/locales/cs.yml +0 -1
  141. data/lib/locales/da.yml +0 -1
  142. data/lib/locales/de.yml +0 -1
  143. data/lib/locales/el.yml +0 -1
  144. data/lib/locales/en.yml +0 -1
  145. data/lib/locales/es.yml +0 -1
  146. data/lib/locales/fi.yml +0 -1
  147. data/lib/locales/fr.yml +0 -1
  148. data/lib/locales/he.yml +0 -1
  149. data/lib/locales/hi.yml +0 -1
  150. data/lib/locales/it.yml +0 -1
  151. data/lib/locales/ja.yml +0 -1
  152. data/lib/locales/ko.yml +0 -1
  153. data/lib/locales/nl.yml +0 -1
  154. data/lib/locales/no.yml +0 -1
  155. data/lib/locales/pl.yml +0 -1
  156. data/lib/locales/pt.yml +0 -1
  157. data/lib/locales/ru.yml +0 -1
  158. data/lib/locales/sv.yml +0 -1
  159. data/lib/locales/th.yml +0 -1
  160. data/lib/locales/tr.yml +0 -1
  161. data/lib/locales/vi.yml +0 -1
  162. data/lib/locales/zh.yml +0 -1
  163. metadata +36 -8
  164. data/lib/cmdx/parameter_validator.rb +0 -81
  165. data/lib/cmdx/parameter_value.rb +0 -244
  166. data/lib/cmdx/parameters_inspector.rb +0 -72
  167. data/lib/cmdx/parameters_serializer.rb +0 -115
  168. data/lib/cmdx/rspec/result_matchers.rb +0 -917
  169. data/lib/cmdx/rspec/task_matchers.rb +0 -570
  170. data/lib/cmdx/validators/custom.rb +0 -102
@@ -1,95 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Parameter definition class for CMDx task parameter management.
4
+ # Parameter definition and management for task attribute configuration.
5
5
  #
6
- # The Parameter class represents individual parameter definitions within CMDx tasks.
7
- # It handles parameter configuration, validation rules, type coercion, nested parameters,
8
- # and method generation for accessing parameter values within task instances.
9
- #
10
- # @example Basic parameter definition
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
- __cmdx_attr_delegator :invalid?, :valid?,
48
- to: :errors
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 :klass, :parent, :name, :type, :options, :children, :errors
38
+ attr_reader :errors
61
39
 
62
- # Initializes a new Parameter instance.
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] The parameter name
69
- # @param options [Hash] Parameter configuration options
70
- # @option options [Class] :klass The task class (required)
71
- # @option options [Parameter] :parent Parent parameter for nesting
72
- # @option options [Symbol, Array<Symbol>] :type (:virtual) Type(s) for coercion
73
- # @option options [Boolean] :required (false) Whether parameter is required
74
- # @option options [Object, Proc] :default Default value or callable
75
- # @option options [Symbol, Proc] :source (:context) Parameter value source
76
- # @option options [Hash] :* Validation options (presence, format, etc.)
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
- # @yield Optional block for defining nested parameters
54
+ # @return [Parameter] a new parameter instance
79
55
  #
80
- # @raise [KeyError] If :klass option is not provided
56
+ # @raise [KeyError] if the :klass option is not provided
81
57
  #
82
- # @example Basic parameter creation
58
+ # @example Create a simple required parameter
83
59
  # Parameter.new(:user_id, klass: MyTask, type: :integer, required: true)
84
60
  #
85
- # @example Parameter with validation
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 Nested parameter with block
90
- # Parameter.new(:address, klass: MyTask) do
91
- # required :street, :city
92
- # optional :apartment
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
- # Defines one or more optional parameters.
86
+ # Creates one or more optional parameter definitions.
112
87
  #
113
- # Creates parameter definitions that are not required for task execution.
114
- # Optional parameters return nil if not provided in the call arguments.
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
- # @param names [Array<Symbol>] Parameter names to define
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
- # @return [Array<Parameter>] Created parameter instances
121
- # @raise [ArgumentError] If no parameter names provided or :as option used with multiple names
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 Single optional parameter
124
- # Parameter.optional(:priority, type: :string, default: "normal")
104
+ # @example Define single optional parameter
105
+ # Parameter.optional(:description, klass: MyTask, type: :string)
125
106
  #
126
- # @example Multiple optional parameters
127
- # Parameter.optional(:width, :height, type: :integer, numeric: { min: 0 })
107
+ # @example Define multiple optional parameters
108
+ # Parameter.optional(:name, :email, klass: MyTask, type: :string)
128
109
  #
129
- # @example Optional parameter with validation
130
- # Parameter.optional(:email, type: :string, format: { with: /@/ })
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
- # Defines one or more required parameters.
122
+ # Creates one or more required parameter definitions.
142
123
  #
143
- # Creates parameter definitions that must be provided for task execution.
144
- # Missing required parameters will cause task validation to fail.
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
- # @param names [Array<Symbol>] Parameter names to define
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
- # @return [Array<Parameter>] Created parameter instances
151
- # @raise [ArgumentError] If no parameter names provided or :as option 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
152
139
  #
153
- # @example Single required parameter
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 Multiple required parameters
157
- # Parameter.required(:first_name, :last_name, type: :string, presence: true)
143
+ # @example Define multiple required parameters
144
+ # Parameter.required(:name, :email, klass: MyTask, type: :string)
158
145
  #
159
- # @example Required parameter with complex validation
160
- # Parameter.required(:age, type: :integer, numeric: { within: 18..120 })
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 nested optional parameters within this parameter.
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>] Child parameter names to define
173
- # @param options [Hash] Parameter configuration options
174
- # @yield Optional block for further nested parameter definitions
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>] Created child parameter instances
165
+ # @return [Array<Parameter>] array of created optional child parameter instances
177
166
  #
178
- # @example Nested optional parameters
179
- # address_param.optional(:apartment, :unit, type: :string)
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 Nested parameter with validation
182
- # user_param.optional(:age, type: :integer, numeric: { min: 0 })
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 nested required parameters within this parameter.
178
+ # Defines required child parameters for nested parameter structures.
189
179
  #
190
- # Creates child parameter definitions that are required if the parent parameter
191
- # is provided. Child parameters inherit this parameter as their source.
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
- # @param names [Array<Symbol>] Child parameter names to define
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
- # @return [Array<Parameter>] Created child parameter instances
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 Nested required parameters
200
- # address_param.required(:street, :city, :state, type: :string)
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 this parameter is required.
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
- # required_param.required? # => true
215
- # optional_param.required? # => false
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 this parameter is optional.
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
- # required_param.optional? # => false
226
- # optional_param.optional? # => true
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
- # Gets the method name that will be defined on the task class.
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] The generated method name
226
+ # @return [Symbol] the method name with any configured prefix, suffix, or custom naming
237
227
  #
238
- # @example Default method name
239
- # Parameter.new(:user_id, klass: Task).method_name # => :user_id
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 Custom method name
242
- # Parameter.new(:id, klass: Task, as: :user_id).method_name # => :user_id
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
- # Gets the source object/method that provides the parameter value.
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
- # @example Default source
258
- # Parameter.new(:user_id, klass: Task).method_source # => :context
241
+ # @return [Symbol] the source identifier used for parameter resolution
259
242
  #
260
- # @example Custom source
261
- # Parameter.new(:name, klass: Task, source: :user).method_source # => :user
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 Inherited source from parent
264
- # child_param.method_source # => parent parameter's method_name
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] Serialized parameter data including configuration and children
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] Human-readable parameter description
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
- # # => "Parameter: name=user_id type=integer source=context required=true options={numeric: {min: 1}}"
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
- # Defines the accessor method on the task class for this parameter.
281
+ # Dynamically defines a method on the task class for parameter value access.
301
282
  #
302
- # Creates a private method that handles parameter value resolution,
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
- @parameters_cache ||= {}
310
- return @parameters_cache[parameter.method_name] if @parameters_cache.key?(parameter.method_name)
311
-
312
- begin
313
- parameter_value = ParameterValue.new(self, parameter).call
314
- rescue CoercionError, ValidationError => e
315
- parameter.errors.add(parameter.method_name, e.message)
316
- errors.merge!(parameter.errors.to_hash)
317
- ensure
318
- @parameters_cache[parameter.method_name] = parameter_value
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
- @parameters_cache[parameter.method_name]
305
+ @cmd_parameter_value_cache[parameter.method_name]
322
306
  end
323
307
 
324
308
  klass.send(:private, parameter.method_name)