cmdx 0.5.0 → 1.0.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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/rules/cursor-instructions.mdc +6 -0
  4. data/.rubocop.yml +19 -1
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +95 -28
  7. data/README.md +73 -25
  8. data/docs/ai_prompts.md +319 -0
  9. data/docs/basics/call.md +234 -14
  10. data/docs/basics/chain.md +280 -0
  11. data/docs/basics/context.md +241 -33
  12. data/docs/basics/setup.md +85 -12
  13. data/docs/callbacks.md +283 -0
  14. data/docs/configuration.md +155 -30
  15. data/docs/getting_started.md +145 -22
  16. data/docs/internationalization.md +148 -0
  17. data/docs/interruptions/exceptions.md +198 -11
  18. data/docs/interruptions/faults.md +196 -44
  19. data/docs/interruptions/halt.md +188 -35
  20. data/docs/logging.md +204 -53
  21. data/docs/middlewares.md +745 -0
  22. data/docs/outcomes/result.md +305 -10
  23. data/docs/outcomes/states.md +212 -31
  24. data/docs/outcomes/statuses.md +284 -30
  25. data/docs/parameters/coercions.md +411 -29
  26. data/docs/parameters/defaults.md +258 -25
  27. data/docs/parameters/definitions.md +247 -72
  28. data/docs/parameters/namespacing.md +259 -27
  29. data/docs/parameters/validations.md +173 -168
  30. data/docs/testing.md +560 -0
  31. data/docs/tips_and_tricks.md +103 -42
  32. data/docs/workflows.md +329 -0
  33. data/lib/cmdx/.DS_Store +0 -0
  34. data/lib/cmdx/callback.rb +69 -0
  35. data/lib/cmdx/callback_registry.rb +106 -0
  36. data/lib/cmdx/chain.rb +190 -0
  37. data/lib/cmdx/chain_inspector.rb +149 -0
  38. data/lib/cmdx/chain_serializer.rb +175 -0
  39. data/lib/cmdx/coercions/array.rb +37 -0
  40. data/lib/cmdx/coercions/big_decimal.rb +33 -0
  41. data/lib/cmdx/coercions/boolean.rb +41 -1
  42. data/lib/cmdx/coercions/complex.rb +31 -0
  43. data/lib/cmdx/coercions/date.rb +39 -0
  44. data/lib/cmdx/coercions/date_time.rb +39 -0
  45. data/lib/cmdx/coercions/float.rb +31 -0
  46. data/lib/cmdx/coercions/hash.rb +42 -0
  47. data/lib/cmdx/coercions/integer.rb +32 -0
  48. data/lib/cmdx/coercions/rational.rb +31 -0
  49. data/lib/cmdx/coercions/string.rb +31 -0
  50. data/lib/cmdx/coercions/time.rb +39 -0
  51. data/lib/cmdx/coercions/virtual.rb +31 -0
  52. data/lib/cmdx/configuration.rb +217 -9
  53. data/lib/cmdx/context.rb +173 -2
  54. data/lib/cmdx/core_ext/hash.rb +72 -0
  55. data/lib/cmdx/core_ext/module.rb +94 -0
  56. data/lib/cmdx/core_ext/object.rb +105 -0
  57. data/lib/cmdx/correlator.rb +217 -0
  58. data/lib/cmdx/error.rb +210 -8
  59. data/lib/cmdx/errors.rb +256 -1
  60. data/lib/cmdx/fault.rb +177 -2
  61. data/lib/cmdx/faults.rb +158 -2
  62. data/lib/cmdx/immutator.rb +121 -2
  63. data/lib/cmdx/lazy_struct.rb +261 -18
  64. data/lib/cmdx/log_formatters/json.rb +46 -0
  65. data/lib/cmdx/log_formatters/key_value.rb +46 -0
  66. data/lib/cmdx/log_formatters/line.rb +54 -0
  67. data/lib/cmdx/log_formatters/logstash.rb +64 -0
  68. data/lib/cmdx/log_formatters/pretty_json.rb +57 -0
  69. data/lib/cmdx/log_formatters/pretty_key_value.rb +51 -0
  70. data/lib/cmdx/log_formatters/pretty_line.rb +60 -0
  71. data/lib/cmdx/log_formatters/raw.rb +54 -0
  72. data/lib/cmdx/logger.rb +85 -0
  73. data/lib/cmdx/logger_ansi.rb +93 -7
  74. data/lib/cmdx/logger_serializer.rb +116 -0
  75. data/lib/cmdx/middleware.rb +74 -0
  76. data/lib/cmdx/middleware_registry.rb +106 -0
  77. data/lib/cmdx/middlewares/correlate.rb +266 -0
  78. data/lib/cmdx/middlewares/timeout.rb +232 -0
  79. data/lib/cmdx/parameter.rb +228 -1
  80. data/lib/cmdx/parameter_inspector.rb +61 -0
  81. data/lib/cmdx/parameter_registry.rb +125 -0
  82. data/lib/cmdx/parameter_serializer.rb +83 -0
  83. data/lib/cmdx/parameter_validator.rb +62 -0
  84. data/lib/cmdx/parameter_value.rb +109 -1
  85. data/lib/cmdx/parameters_inspector.rb +59 -0
  86. data/lib/cmdx/parameters_serializer.rb +102 -0
  87. data/lib/cmdx/railtie.rb +123 -3
  88. data/lib/cmdx/result.rb +367 -25
  89. data/lib/cmdx/result_ansi.rb +105 -9
  90. data/lib/cmdx/result_inspector.rb +76 -0
  91. data/lib/cmdx/result_logger.rb +90 -3
  92. data/lib/cmdx/result_serializer.rb +137 -0
  93. data/lib/cmdx/rspec/result_matchers.rb +917 -0
  94. data/lib/cmdx/rspec/task_matchers.rb +570 -0
  95. data/lib/cmdx/task.rb +405 -37
  96. data/lib/cmdx/task_serializer.rb +74 -2
  97. data/lib/cmdx/utils/ansi_color.rb +95 -0
  98. data/lib/cmdx/utils/log_timestamp.rb +48 -0
  99. data/lib/cmdx/utils/monotonic_runtime.rb +71 -4
  100. data/lib/cmdx/utils/name_affix.rb +78 -0
  101. data/lib/cmdx/validators/custom.rb +82 -0
  102. data/lib/cmdx/validators/exclusion.rb +94 -0
  103. data/lib/cmdx/validators/format.rb +102 -8
  104. data/lib/cmdx/validators/inclusion.rb +104 -0
  105. data/lib/cmdx/validators/length.rb +128 -0
  106. data/lib/cmdx/validators/numeric.rb +128 -0
  107. data/lib/cmdx/validators/presence.rb +93 -7
  108. data/lib/cmdx/version.rb +7 -1
  109. data/lib/cmdx/workflow.rb +394 -0
  110. data/lib/cmdx.rb +25 -64
  111. data/lib/generators/cmdx/install_generator.rb +37 -1
  112. data/lib/generators/cmdx/task_generator.rb +69 -1
  113. data/lib/generators/cmdx/templates/install.rb +43 -15
  114. data/lib/generators/cmdx/workflow_generator.rb +109 -0
  115. data/lib/locales/ar.yml +36 -0
  116. data/lib/locales/cs.yml +36 -0
  117. data/lib/locales/da.yml +36 -0
  118. data/lib/locales/de.yml +36 -0
  119. data/lib/locales/el.yml +36 -0
  120. data/lib/locales/en.yml +20 -20
  121. data/lib/locales/es.yml +20 -20
  122. data/lib/locales/fi.yml +36 -0
  123. data/lib/locales/fr.yml +36 -0
  124. data/lib/locales/he.yml +36 -0
  125. data/lib/locales/hi.yml +36 -0
  126. data/lib/locales/it.yml +36 -0
  127. data/lib/locales/ja.yml +36 -0
  128. data/lib/locales/ko.yml +36 -0
  129. data/lib/locales/nl.yml +36 -0
  130. data/lib/locales/no.yml +36 -0
  131. data/lib/locales/pl.yml +36 -0
  132. data/lib/locales/pt.yml +36 -0
  133. data/lib/locales/ru.yml +36 -0
  134. data/lib/locales/sv.yml +36 -0
  135. data/lib/locales/th.yml +36 -0
  136. data/lib/locales/tr.yml +36 -0
  137. data/lib/locales/vi.yml +36 -0
  138. data/lib/locales/zh.yml +36 -0
  139. metadata +77 -15
  140. data/docs/basics/run.md +0 -34
  141. data/docs/batch.md +0 -53
  142. data/docs/example.md +0 -82
  143. data/docs/hooks.md +0 -62
  144. data/lib/cmdx/batch.rb +0 -43
  145. data/lib/cmdx/parameters.rb +0 -35
  146. data/lib/cmdx/run.rb +0 -39
  147. data/lib/cmdx/run_inspector.rb +0 -26
  148. data/lib/cmdx/run_serializer.rb +0 -20
  149. data/lib/cmdx/task_hook.rb +0 -18
  150. data/lib/generators/cmdx/batch_generator.rb +0 -30
  151. /data/lib/generators/cmdx/templates/{batch.rb.tt → workflow.rb.tt} +0 -0
@@ -1,52 +1,434 @@
1
1
  # Parameters - Coercions
2
2
 
3
- Parameter values will be returned as given (`type: :virtual`) but can be coerced (typecast)
4
- to a specific type. This is useful for casting stringified parameter values.
3
+ Parameter coercions provide automatic type conversion for task arguments, enabling
4
+ flexible input handling while ensuring type safety within task execution. Coercions
5
+ transform raw input values into expected types, supporting everything from simple
6
+ string-to-integer conversion to complex JSON parsing and custom type handling.
5
7
 
6
- Supported coercions are: `:array`, `:big_decimal`, `:boolean`, `:complex`, `:datetime`, `:date`,
7
- `:float`, `:hash`, `:integer`, `:rational`, `:string`, `:time`, `:virtual`
8
+ ## Table of Contents
9
+
10
+ - [TLDR](#tldr)
11
+ - [Coercion Fundamentals](#coercion-fundamentals)
12
+ - [Available Coercion Types](#available-coercion-types)
13
+ - [Basic Type Coercion](#basic-type-coercion)
14
+ - [Multiple Type Coercion](#multiple-type-coercion)
15
+ - [Advanced Coercion Examples](#advanced-coercion-examples)
16
+ - [Array Coercion](#array-coercion)
17
+ - [Hash Coercion](#hash-coercion)
18
+ - [Boolean Coercion](#boolean-coercion)
19
+ - [Date and Time Coercion](#date-and-time-coercion)
20
+ - [Numeric Coercion](#numeric-coercion)
21
+ - [Coercion with Nested Parameters](#coercion-with-nested-parameters)
22
+ - [Coercion Error Handling](#coercion-error-handling)
23
+ - [Single Type Coercion Errors](#single-type-coercion-errors)
24
+ - [Multiple Type Coercion Errors](#multiple-type-coercion-errors)
25
+ - [Custom Coercion Options](#custom-coercion-options)
26
+ - [Date/Time Format Options](#datetime-format-options)
27
+ - [BigDecimal Precision Options](#bigdecimal-precision-options)
28
+
29
+ ## TLDR
30
+
31
+ - **Type coercion** - Automatic conversion using `type:` option (`:integer`, `:boolean`, `:array`, `:hash`, etc.)
32
+ - **Multiple types** - Fallback with `type: [:float, :integer]` - tries each until one succeeds
33
+ - **No conversion** - Default `:virtual` type returns values unchanged
34
+ - **Before validation** - Coercion happens automatically before parameter validation
35
+ - **Rich types** - Supports all Ruby built-ins plus JSON parsing for arrays/hashes
36
+
37
+ ## Coercion Fundamentals
38
+
39
+ > [!NOTE]
40
+ > By default, parameters use the `:virtual` type which returns values unchanged. Type coercion is specified using the `:type` option and occurs automatically during parameter value resolution, before validation.
41
+
42
+ ### Available Coercion Types
43
+
44
+ CMDx supports comprehensive type coercion for Ruby's built-in types:
45
+
46
+ | Type | Description | Example Input | Example Output |
47
+ |------|-------------|---------------|----------------|
48
+ | `:array` | Converts to Array, handles JSON strings | `"[1,2,3]"` | `[1, 2, 3]` |
49
+ | `:big_decimal` | High-precision decimal arithmetic | `"123.456"` | `BigDecimal("123.456")` |
50
+ | `:boolean` | True/false conversion with text patterns | `"true"`, `"yes"`, `"1"` | `true` |
51
+ | `:complex` | Complex number conversion | `"1+2i"` | `Complex(1, 2)` |
52
+ | `:date` | Date object conversion | `"2023-12-25"` | `Date.new(2023, 12, 25)` |
53
+ | `:datetime` | DateTime object conversion | `"2023-12-25 10:30"` | `DateTime` object |
54
+ | `:float` | Floating-point number conversion | `"123.45"` | `123.45` |
55
+ | `:hash` | Hash conversion, handles JSON strings | `'{"a":1}'` | `{"a" => 1}` |
56
+ | `:integer` | Integer conversion, handles various formats | `"123"`, `"0xFF"` | `123`, `255` |
57
+ | `:rational` | Rational number conversion | `"1/2"`, `0.5` | `Rational(1, 2)` |
58
+ | `:string` | String conversion for any object | `123`, `:symbol` | `"123"`, `"symbol"` |
59
+ | `:time` | Time object conversion | `"2023-12-25 10:30"` | `Time` object |
60
+ | `:virtual` | No conversion (default) | `anything` | `anything` |
61
+
62
+ ### Basic Type Coercion
8
63
 
9
64
  ```ruby
10
- class DetermineBoxSizeTask < CMDx::Task
65
+ class ProcessUserDataTask < CMDx::Task
11
66
 
12
- # Single type
13
- required :width, type: :string
67
+ required :user_id, type: :integer
68
+ required :order_total, type: :float
69
+ required :is_premium, type: :boolean
70
+ required :notes, type: :string
14
71
 
15
- # Multiple types
16
- optional :height, type: [:float, :integer]
72
+ optional :product_tags, type: :array, default: []
73
+ optional :preferences, type: :hash, default: {}
74
+ optional :created_at, type: :datetime
75
+ optional :delivery_date, type: :date
17
76
 
18
77
  def call
19
- width #=> "1"
20
- height #=> 2.3
78
+ user_id #=> 12345 (integer from "12345")
79
+ order_total #=> 299.99 (float from "299.99")
80
+ is_premium #=> true (boolean from "true")
81
+ notes #=> "Rush delivery" (string)
82
+ product_tags #=> ["electronics", "phone"] (array from JSON)
83
+ preferences #=> {"notifications" => true} (hash from JSON)
84
+ created_at #=> DateTime object
85
+ delivery_date #=> Date object
21
86
  end
22
87
 
23
88
  end
24
89
 
25
- # Coerced to value types
26
- DetermineBoxSizeTask.call(width: 1, height: "2.3")
90
+ # Coercion happens automatically
91
+ ProcessUserDataTask.call(
92
+ user_id: "12345",
93
+ order_total: "299.99",
94
+ is_premium: "yes",
95
+ notes: 67890,
96
+ product_tags: "[\"electronics\",\"phone\"]",
97
+ preferences: '{"notifications":true}',
98
+ created_at: "2023-12-25 14:30:00",
99
+ delivery_date: "2023-12-28"
100
+ )
27
101
  ```
28
102
 
29
- > [!NOTE]
30
- > When passing multiple type, coercions are done in the order they are passed. An example of
31
- > numeric casting would be to cast numbers with precision first: `[:float, :integer]`
103
+ ## Multiple Type Coercion
104
+
105
+ > [!TIP]
106
+ > Parameters can specify multiple types for fallback coercion, attempting each type in order until one succeeds. This provides flexible input handling while maintaining type safety.
107
+
108
+ ```ruby
109
+ class ProcessOrderDataTask < CMDx::Task
110
+
111
+ # Try float first for precise calculations, fall back to integer
112
+ required :amount, type: [:float, :integer]
113
+
114
+ # Try hash first for structured data, fall back to string for raw data
115
+ optional :shipping_info, type: [:hash, :string]
116
+
117
+ # Complex fallback for timestamps
118
+ optional :scheduled_at, type: [:datetime, :date, :string]
119
+
120
+ def call
121
+ amount #=> 149.99 (float) or 150 (integer) depending on input
122
+ shipping_info #=> {"address" => "123 Main St"} (hash) or "Express shipping" (string)
123
+ scheduled_at #=> DateTime, Date, or String depending on input format
124
+ end
125
+
126
+ end
127
+
128
+ # Different inputs produce different coerced types
129
+ ProcessOrderDataTask.call(amount: "149.99") # => 149.99 (float)
130
+ ProcessOrderDataTask.call(amount: "150") # => 150 (integer)
131
+ ProcessOrderDataTask.call(shipping_info: '{"address":"123 Main St"}') # => hash
132
+ ProcessOrderDataTask.call(shipping_info: "Express shipping") # => string
133
+ ```
134
+
135
+ ## Advanced Coercion Examples
136
+
137
+ ### Array Coercion
138
+
139
+ ```ruby
140
+ class ProcessOrderItemsTask < CMDx::Task
141
+
142
+ required :item_ids, type: :array
143
+ optional :quantities, type: :array, default: []
144
+
145
+ def call
146
+ item_ids #=> Array of product IDs
147
+ quantities #=> Array of quantities or empty array
148
+ end
149
+
150
+ end
151
+
152
+ # Array coercion handles multiple input formats
153
+ ProcessOrderItemsTask.call(item_ids: [101, 102, 103]) # => already array
154
+ ProcessOrderItemsTask.call(item_ids: "[101,102,103]") # => from JSON string
155
+ ProcessOrderItemsTask.call(item_ids: "101") # => ["101"] (wrapped)
156
+ ProcessOrderItemsTask.call(item_ids: nil) # => [] (nil to empty)
157
+ ```
32
158
 
33
- ## Results
159
+ ### Hash Coercion
34
160
 
35
- The following represents a result output example of a failed coercion.
161
+ ```ruby
162
+ class ProcessOrderConfigTask < CMDx::Task
163
+
164
+ required :shipping_config, type: :hash
165
+ optional :payment_options, type: :hash, default: {}
166
+
167
+ def call
168
+ shipping_config #=> Hash with shipping configuration
169
+ payment_options #=> Hash with payment options or empty hash
170
+ end
171
+
172
+ end
173
+
174
+ # Hash coercion supports multiple formats
175
+ ProcessOrderConfigTask.call(shipping_config: {carrier: "UPS", speed: "express"})
176
+ ProcessOrderConfigTask.call(shipping_config: '{"carrier":"UPS","speed":"express"}')
177
+ ProcessOrderConfigTask.call(shipping_config: [:carrier, "UPS", :speed, "express"])
178
+ ```
179
+
180
+ ### Boolean Coercion
181
+
182
+ ```ruby
183
+ class ValidateUserSettingsTask < CMDx::Task
184
+
185
+ required :email_notifications, type: :boolean
186
+ required :is_active, type: :boolean
187
+ optional :marketing_consent, type: :boolean, default: false
188
+
189
+ def call
190
+ email_notifications #=> true or false from various inputs
191
+ is_active #=> true or false
192
+ marketing_consent #=> true or false with default
193
+ end
194
+
195
+ end
196
+
197
+ # Boolean coercion recognizes many text patterns
198
+ ValidateUserSettingsTask.call(email_notifications: "true") # => true
199
+ ValidateUserSettingsTask.call(email_notifications: "yes") # => true
200
+ ValidateUserSettingsTask.call(email_notifications: "1") # => true
201
+ ValidateUserSettingsTask.call(email_notifications: "false") # => false
202
+ ValidateUserSettingsTask.call(email_notifications: "no") # => false
203
+ ValidateUserSettingsTask.call(email_notifications: "0") # => false
204
+ ```
205
+
206
+ ### Date and Time Coercion
207
+
208
+ ```ruby
209
+ class ProcessOrderScheduleTask < CMDx::Task
210
+
211
+ required :order_date, type: :date
212
+ required :created_at, type: :datetime
213
+ optional :updated_at, type: :time
214
+
215
+ # Custom format options for specific date/time formats
216
+ optional :delivery_date, type: :date, format: "%Y-%m-%d"
217
+ optional :pickup_time, type: :time, format: "%H:%M:%S"
218
+
219
+ def call
220
+ order_date #=> Date object
221
+ created_at #=> DateTime object
222
+ updated_at #=> Time object
223
+ delivery_date #=> Date parsed with custom format
224
+ pickup_time #=> Time parsed with custom format
225
+ end
226
+
227
+ end
228
+
229
+ ProcessOrderScheduleTask.call(
230
+ order_date: "2023-12-25",
231
+ created_at: "2023-12-25 10:30:00",
232
+ updated_at: "2023-12-25 10:30:00",
233
+ delivery_date: "2023-12-28",
234
+ pickup_time: "14:30:00"
235
+ )
236
+ ```
237
+
238
+ ### Numeric Coercion
36
239
 
37
240
  ```ruby
38
- result = DetermineBoxSizeTask.call
39
- result.state #=> "interrupted"
40
- result.status #=> "failed"
41
- result.metadata #=> {
42
- #=> reason: "height could not be coerced into one of: float, integer.",
43
- #=> messages: {
44
- #=> height: ["could not be coerced into one of: float, integer"]
45
- #=> }
46
- #=> }
241
+ class CalculateOrderTotalsTask < CMDx::Task
242
+
243
+ required :item_count, type: :integer
244
+ required :subtotal, type: :float
245
+ required :tax_rate, type: :float
246
+
247
+ # High-precision for financial calculations
248
+ optional :discount_amount, type: :big_decimal, precision: 4
249
+
250
+ # For specialized calculations
251
+ optional :shipping_ratio, type: :rational
252
+ optional :complex_calculation, type: :complex
253
+
254
+ def call
255
+ item_count #=> Integer from various formats
256
+ subtotal #=> Float for currency
257
+ tax_rate #=> Float for percentage
258
+ discount_amount #=> BigDecimal with specified precision
259
+ shipping_ratio #=> Rational number
260
+ complex_calculation #=> Complex number
261
+ end
262
+
263
+ end
264
+
265
+ CalculateOrderTotalsTask.call(
266
+ item_count: "5",
267
+ subtotal: "249.99",
268
+ tax_rate: "0.0875",
269
+ discount_amount: "25.0000",
270
+ shipping_ratio: "1/10",
271
+ complex_calculation: "1+2i"
272
+ )
273
+ ```
274
+
275
+ ## Coercion with Nested Parameters
276
+
277
+ > [!IMPORTANT]
278
+ > Coercion works seamlessly with nested parameter structures, applying type conversion at each level of the hierarchy.
279
+
280
+ ```ruby
281
+ class ProcessOrderDetailsTask < CMDx::Task
282
+
283
+ required :order, type: :hash do
284
+ required :id, type: :integer
285
+ required :total, type: :float
286
+ required :items, type: :array
287
+
288
+ optional :customer, type: :hash do
289
+ required :id, type: :integer
290
+ required :is_active, type: :boolean
291
+ optional :created_at, type: :datetime
292
+ end
293
+ end
294
+
295
+ def call
296
+ order #=> Hash (coerced from JSON string if needed)
297
+
298
+ # Nested coercions
299
+ id #=> Integer (from order.id)
300
+ total #=> Float (from order.total)
301
+ items #=> Array (from order.items)
302
+
303
+ # Deep nested coercions
304
+ if customer
305
+ customer_id = id # Integer (from order.customer.id)
306
+ active_status = is_active # Boolean (from order.customer.is_active)
307
+ created_time = created_at # DateTime (from order.customer.created_at)
308
+ end
309
+ end
310
+
311
+ end
312
+ ```
313
+
314
+ ## Coercion Error Handling
315
+
316
+ > [!WARNING]
317
+ > When coercion fails, CMDx provides detailed error information including the parameter name, attempted types, and specific failure reasons.
318
+
319
+ ### Single Type Coercion Errors
320
+
321
+ ```ruby
322
+ class ValidateUserProfileTask < CMDx::Task
323
+
324
+ required :age, type: :integer
325
+ required :salary, type: :float
326
+ required :is_employed, type: :boolean
327
+
328
+ def call
329
+ # Task logic here
330
+ end
331
+
332
+ end
333
+
334
+ # Invalid coercion inputs
335
+ result = ValidateUserProfileTask.call(
336
+ age: "not-a-number",
337
+ salary: "invalid-amount",
338
+ is_employed: "maybe"
339
+ )
340
+
341
+ result.failed? #=> true
342
+ result.metadata
343
+ #=> {
344
+ # reason: "age could not coerce into an integer. salary could not coerce into a float. is_employed could not coerce into a boolean.",
345
+ # messages: {
346
+ # age: ["could not coerce into an integer"],
347
+ # salary: ["could not coerce into a float"],
348
+ # is_employed: ["could not coerce into a boolean"]
349
+ # }
350
+ # }
351
+ ```
352
+
353
+ ### Multiple Type Coercion Errors
354
+
355
+ ```ruby
356
+ class ProcessFlexibleDataTask < CMDx::Task
357
+
358
+ required :order_value, type: [:float, :integer]
359
+ required :customer_data, type: [:hash, :array, :string]
360
+
361
+ def call
362
+ # Task logic here
363
+ end
364
+
365
+ end
366
+
367
+ # Failed coercion with multiple types
368
+ result = ProcessFlexibleDataTask.call(
369
+ order_value: "invalid-number",
370
+ customer_data: Object.new
371
+ )
372
+
373
+ result.failed? #=> true
374
+ result.metadata
375
+ #=> {
376
+ # reason: "order_value could not coerce into one of: float, integer. customer_data could not coerce into one of: hash, array, string.",
377
+ # messages: {
378
+ # order_value: ["could not coerce into one of: float, integer"],
379
+ # customer_data: ["could not coerce into one of: hash, array, string"]
380
+ # }
381
+ # }
382
+ ```
383
+
384
+ ## Custom Coercion Options
385
+
386
+ ### Date/Time Format Options
387
+
388
+ ```ruby
389
+ class ProcessCustomDateTask < CMDx::Task
390
+
391
+ # US date format
392
+ required :birth_date, type: :date, format: "%m/%d/%Y"
393
+
394
+ # ISO datetime with timezone
395
+ required :event_timestamp, type: :datetime, format: "%Y-%m-%d %H:%M:%S %Z"
396
+
397
+ # 24-hour time format
398
+ optional :meeting_time, type: :time, format: "%H:%M"
399
+
400
+ def call
401
+ birth_date #=> Date parsed with MM/DD/YYYY format
402
+ event_timestamp #=> DateTime with timezone
403
+ meeting_time #=> Time with hour:minute format
404
+ end
405
+
406
+ end
407
+
408
+ ProcessCustomDateTask.call(
409
+ birth_date: "12/25/1990",
410
+ event_timestamp: "2023-12-25 10:30:00 UTC",
411
+ meeting_time: "14:30"
412
+ )
413
+ ```
414
+
415
+ ### BigDecimal Precision Options
416
+
417
+ ```ruby
418
+ class CalculatePricingTask < CMDx::Task
419
+
420
+ required :base_price, type: :big_decimal
421
+ required :tax_rate, type: :big_decimal, precision: 6
422
+
423
+ def call
424
+ base_price #=> BigDecimal with default precision
425
+ tax_rate #=> BigDecimal with 6-digit precision
426
+ end
427
+
428
+ end
47
429
  ```
48
430
 
49
431
  ---
50
432
 
51
- - **Prev:** [Namespacing](https://github.com/drexed/cmdx/blob/main/docs/parameters/namespacing.md)
52
- - **Next:** [Validations](https://github.com/drexed/cmdx/blob/main/docs/parameters/validations.md)
433
+ - **Prev:** [Parameters - Namespacing](namespacing.md)
434
+ - **Next:** [Parameters - Validations](validations.md)