cmdx 0.4.0 → 1.0.0

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