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/docs/basics/setup.md
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# Basics - Setup
|
2
2
|
|
3
|
-
A task represents a unit of work to execute. Tasks are the core building blocks
|
4
|
-
of CMDx, encapsulating business logic within a structured, reusable object. While
|
5
|
-
CMDx offers extensive features like parameter validation, callbacks, and state tracking,
|
6
|
-
only a `call` method is required to create a functional task.
|
3
|
+
A task represents a unit of work to execute. Tasks are the core building blocks of CMDx, encapsulating business logic within a structured, reusable object. While CMDx offers extensive features like parameter validation, callbacks, and state tracking, only a `call` method is required to create a functional task.
|
7
4
|
|
8
5
|
## Table of Contents
|
9
6
|
|
@@ -13,57 +10,197 @@ only a `call` method is required to create a functional task.
|
|
13
10
|
- [Inheritance and Application Tasks](#inheritance-and-application-tasks)
|
14
11
|
- [Generator](#generator)
|
15
12
|
- [Task Lifecycle](#task-lifecycle)
|
13
|
+
- [Error Handling](#error-handling)
|
16
14
|
|
17
15
|
## TLDR
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
```ruby
|
18
|
+
# Minimal task - only call method required
|
19
|
+
class ProcessOrderTask < CMDx::Task
|
20
|
+
def call
|
21
|
+
context.result = "Order processed"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Execute and access results
|
26
|
+
result = ProcessOrderTask.call(order_id: 123)
|
27
|
+
result.success? # → true
|
28
|
+
result.context.result # → "Order processed"
|
29
|
+
|
30
|
+
# With parameters and validation
|
31
|
+
class UpdateUserTask < CMDx::Task
|
32
|
+
required :user_id, type: :integer
|
33
|
+
required :email, type: :string
|
34
|
+
|
35
|
+
def call
|
36
|
+
user = User.find(context.user_id)
|
37
|
+
user.update!(email: context.email)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Generator for quick scaffolding
|
42
|
+
rails g cmdx:task ProcessPayment # Creates structured template
|
43
|
+
```
|
24
44
|
|
25
45
|
## Basic Task Structure
|
26
46
|
|
47
|
+
> [!NOTE]
|
48
|
+
> Tasks are Ruby classes that inherit from `CMDx::Task`. Only the `call` method is required - all other features are optional and can be added as needed.
|
49
|
+
|
50
|
+
### Minimal Task
|
51
|
+
|
27
52
|
```ruby
|
28
53
|
class ProcessUserOrderTask < CMDx::Task
|
29
|
-
|
30
54
|
def call
|
31
55
|
# Your business logic here
|
32
56
|
context.order = Order.find(context.order_id)
|
33
57
|
context.order.process!
|
34
58
|
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
### Complete Task Structure
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
class ProcessPaymentTask < CMDx::Task
|
66
|
+
# Parameter definitions (optional)
|
67
|
+
required :amount, type: :float
|
68
|
+
required :user_id, type: :integer
|
69
|
+
optional :currency, type: :string, default: "USD"
|
70
|
+
|
71
|
+
# Callbacks (optional)
|
72
|
+
before_call :validate_user
|
73
|
+
after_call :send_notification
|
74
|
+
|
75
|
+
def call
|
76
|
+
# Core business logic
|
77
|
+
user = User.find(context.user_id)
|
78
|
+
payment = Payment.create!(
|
79
|
+
user: user,
|
80
|
+
amount: context.amount,
|
81
|
+
currency: context.currency
|
82
|
+
)
|
83
|
+
|
84
|
+
context.payment = payment
|
85
|
+
context.success_message = "Payment processed successfully"
|
86
|
+
end
|
35
87
|
|
36
88
|
private
|
37
89
|
|
38
|
-
|
90
|
+
def validate_user
|
91
|
+
# Validation logic
|
92
|
+
end
|
39
93
|
|
94
|
+
def send_notification
|
95
|
+
# Notification logic
|
96
|
+
end
|
40
97
|
end
|
41
98
|
```
|
42
99
|
|
43
100
|
## Task Execution
|
44
101
|
|
102
|
+
> [!IMPORTANT]
|
103
|
+
> Tasks return a `CMDx::Result` object that contains execution state, context data, and metadata. Always check the result status before accessing context data.
|
104
|
+
|
105
|
+
### Basic Execution
|
106
|
+
|
45
107
|
```ruby
|
46
108
|
# Execute a task
|
47
109
|
result = ProcessUserOrderTask.call(order_id: 123)
|
48
110
|
|
49
|
-
#
|
50
|
-
result.success?
|
51
|
-
result.
|
111
|
+
# Check execution status
|
112
|
+
result.success? # → true/false
|
113
|
+
result.failed? # → true/false
|
114
|
+
|
115
|
+
# Access context data
|
116
|
+
result.context.order # → <Order id: 123>
|
117
|
+
|
118
|
+
# Access execution metadata
|
119
|
+
result.status # → :success, :failure, etc.
|
120
|
+
result.state # → :executed, :skipped, etc.
|
121
|
+
result.runtime # → 0.1234 (seconds)
|
122
|
+
```
|
123
|
+
|
124
|
+
### Handling Different Outcomes
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
result = ProcessPaymentTask.call(
|
128
|
+
amount: 99.99,
|
129
|
+
user_id: 12345,
|
130
|
+
currency: "EUR"
|
131
|
+
)
|
132
|
+
|
133
|
+
case result.status
|
134
|
+
when :success
|
135
|
+
payment = result.context.payment
|
136
|
+
puts result.context.success_message
|
137
|
+
when :failure
|
138
|
+
puts "Payment failed: #{result.metadata[:reason]}"
|
139
|
+
when :halt
|
140
|
+
puts "Payment halted: #{result.metadata[:reason]}"
|
141
|
+
end
|
52
142
|
```
|
53
143
|
|
54
144
|
## Inheritance and Application Tasks
|
55
145
|
|
56
|
-
|
146
|
+
> [!TIP]
|
147
|
+
> In Rails applications, create an `ApplicationTask` base class to share common configuration, middleware, and functionality across all your tasks.
|
148
|
+
|
149
|
+
### Application Base Class
|
57
150
|
|
58
151
|
```ruby
|
59
152
|
# app/tasks/application_task.rb
|
60
153
|
class ApplicationTask < CMDx::Task
|
61
|
-
# Shared configuration
|
154
|
+
# Shared configuration
|
155
|
+
use :middleware, AuthenticateUserMiddleware
|
156
|
+
use :middleware, LogExecutionMiddleware
|
157
|
+
|
158
|
+
# Common callbacks
|
159
|
+
before_call :set_correlation_id
|
160
|
+
after_call :cleanup_temp_data
|
161
|
+
|
162
|
+
# Shared parameter definitions
|
163
|
+
optional :current_user, type: :virtual
|
164
|
+
optional :request_id, type: :string
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def set_correlation_id
|
169
|
+
context.correlation_id ||= SecureRandom.uuid
|
170
|
+
end
|
171
|
+
|
172
|
+
def cleanup_temp_data
|
173
|
+
# Cleanup logic
|
174
|
+
end
|
62
175
|
end
|
176
|
+
```
|
177
|
+
|
178
|
+
### Task Implementation
|
63
179
|
|
180
|
+
```ruby
|
64
181
|
# app/tasks/process_user_order_task.rb
|
65
182
|
class ProcessUserOrderTask < ApplicationTask
|
183
|
+
required :order_id, type: :integer
|
184
|
+
required :payment_method, type: :string
|
185
|
+
|
66
186
|
def call
|
187
|
+
# Inherits all ApplicationTask functionality
|
188
|
+
order = Order.find(context.order_id)
|
189
|
+
|
190
|
+
# Business logic specific to this task
|
191
|
+
process_order(order)
|
192
|
+
charge_payment(order, context.payment_method)
|
193
|
+
|
194
|
+
context.order = order
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def process_order(order)
|
200
|
+
# Implementation
|
201
|
+
end
|
202
|
+
|
203
|
+
def charge_payment(order, method)
|
67
204
|
# Implementation
|
68
205
|
end
|
69
206
|
end
|
@@ -71,33 +208,166 @@ end
|
|
71
208
|
|
72
209
|
## Generator
|
73
210
|
|
74
|
-
|
211
|
+
> [!NOTE]
|
212
|
+
> Rails applications can use the built-in generator to create consistent task templates with proper structure and naming conventions.
|
213
|
+
|
214
|
+
### Basic Task Generation
|
75
215
|
|
76
216
|
```bash
|
217
|
+
# Generate a basic task
|
77
218
|
rails g cmdx:task ProcessUserOrder
|
78
219
|
```
|
79
220
|
|
80
|
-
This creates `app/tasks/process_user_order_task.rb
|
81
|
-
- Proper inheritance from `ApplicationTask` (if available) or `CMDx::Task`
|
82
|
-
- Basic structure with parameter definitions
|
83
|
-
- Template implementation
|
221
|
+
This creates `app/tasks/process_user_order_task.rb`:
|
84
222
|
|
85
|
-
|
86
|
-
|
223
|
+
```ruby
|
224
|
+
class ProcessUserOrderTask < ApplicationTask
|
225
|
+
# Define required parameters
|
226
|
+
# required :param_name, type: :string
|
87
227
|
|
88
|
-
|
228
|
+
# Define optional parameters
|
229
|
+
# optional :param_name, type: :string, default: "default_value"
|
230
|
+
|
231
|
+
def call
|
232
|
+
# Implement your task logic here
|
233
|
+
# Access parameters via context.param_name
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
89
237
|
|
90
|
-
|
238
|
+
# Add private methods for supporting logic
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
### Advanced Generation Options
|
243
|
+
|
244
|
+
```bash
|
245
|
+
# Generate with workflow
|
246
|
+
rails g cmdx:workflow ProcessOrder
|
247
|
+
|
248
|
+
# Generate with specific namespace
|
249
|
+
rails g cmdx:task Billing::ProcessPayment
|
250
|
+
```
|
91
251
|
|
92
|
-
|
93
|
-
2. **Validation** - Parameters validated against definitions
|
94
|
-
3. **Execution** - The `call` method runs business logic
|
95
|
-
4. **Completion** - Result finalized with state and status
|
96
|
-
5. **Freezing** - Task becomes immutable after execution
|
252
|
+
## Task Lifecycle
|
97
253
|
|
98
254
|
> [!IMPORTANT]
|
99
|
-
>
|
100
|
-
|
255
|
+
> Understanding the task lifecycle is crucial for proper error handling and debugging. Tasks follow a predictable execution pattern with specific states and status transitions.
|
256
|
+
|
257
|
+
### Lifecycle Stages
|
258
|
+
|
259
|
+
| Stage | Description | State | Possible Statuses |
|
260
|
+
|-------|-------------|--------|-------------------|
|
261
|
+
| **Instantiation** | Task object created with context | `:initialized` | `:pending` |
|
262
|
+
| **Pre-validation** | Before callbacks and middleware run | `:executing` | `:pending` |
|
263
|
+
| **Validation** | Parameters validated against definitions | `:executing` | `:pending`, `:failure` |
|
264
|
+
| **Execution** | The `call` method runs business logic | `:executing` | `:pending`, `:halt` |
|
265
|
+
| **Post-execution** | After callbacks run | `:executing` | `:success`, `:failure` |
|
266
|
+
| **Completion** | Result finalized with final state | `:executed` | `:success`, `:failure` |
|
267
|
+
| **Freezing** | Task becomes immutable | `:executed` | Final status |
|
268
|
+
|
269
|
+
### Lifecycle Example
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
class ExampleTask < CMDx::Task
|
273
|
+
required :data, type: :string
|
274
|
+
|
275
|
+
before_call :log_start
|
276
|
+
after_call :log_completion
|
277
|
+
|
278
|
+
def call
|
279
|
+
# Main logic
|
280
|
+
context.processed_data = context.data.upcase
|
281
|
+
end
|
282
|
+
|
283
|
+
private
|
284
|
+
|
285
|
+
def log_start
|
286
|
+
puts "Task starting with data: #{context.data}"
|
287
|
+
end
|
288
|
+
|
289
|
+
def log_completion
|
290
|
+
puts "Task completed: #{context.processed_data}"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Execution trace
|
295
|
+
result = ExampleTask.call(data: "hello")
|
296
|
+
# Output:
|
297
|
+
# Task starting with data: hello
|
298
|
+
# Task completed: HELLO
|
299
|
+
|
300
|
+
result.state # → :executed
|
301
|
+
result.status # → :success
|
302
|
+
```
|
303
|
+
|
304
|
+
> [!WARNING]
|
305
|
+
> Tasks are single-use objects. Once executed, they are frozen and cannot be called again. Attempting to call a frozen task will raise an error.
|
306
|
+
|
307
|
+
```ruby
|
308
|
+
task = ProcessOrderTask.new(order_id: 123)
|
309
|
+
result1 = task.call # ✓ Works
|
310
|
+
result2 = task.call # ✗ Raises FrozenError
|
311
|
+
|
312
|
+
# Create new instances for each execution
|
313
|
+
result1 = ProcessOrderTask.call(order_id: 123)
|
314
|
+
result2 = ProcessOrderTask.call(order_id: 456) # ✓ Works
|
315
|
+
```
|
316
|
+
|
317
|
+
## Error Handling
|
318
|
+
|
319
|
+
> [!NOTE]
|
320
|
+
> CMDx provides comprehensive error handling with detailed metadata about failures, including parameter validation errors, execution exceptions, and halt conditions.
|
321
|
+
|
322
|
+
### Parameter Validation Errors
|
323
|
+
|
324
|
+
```ruby
|
325
|
+
class ProcessOrderTask < CMDx::Task
|
326
|
+
required :order_id, type: :integer
|
327
|
+
required :amount, type: :float
|
328
|
+
|
329
|
+
def call
|
330
|
+
# Task logic
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# Invalid parameters
|
335
|
+
result = ProcessOrderTask.call(
|
336
|
+
order_id: "not-a-number",
|
337
|
+
amount: "invalid"
|
338
|
+
)
|
339
|
+
|
340
|
+
result.failed? # → true
|
341
|
+
result.status # → :failure
|
342
|
+
result.metadata
|
343
|
+
# {
|
344
|
+
# reason: "order_id could not coerce into an integer. amount could not coerce into a float.",
|
345
|
+
# messages: {
|
346
|
+
# order_id: ["could not coerce into an integer"],
|
347
|
+
# amount: ["could not coerce into a float"]
|
348
|
+
# }
|
349
|
+
# }
|
350
|
+
```
|
351
|
+
|
352
|
+
### Runtime Exceptions
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
class ProcessOrderTask < CMDx::Task
|
356
|
+
required :order_id, type: :integer
|
357
|
+
|
358
|
+
def call
|
359
|
+
order = Order.find(context.order_id) # May raise ActiveRecord::RecordNotFound
|
360
|
+
order.process!
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# Order not found
|
365
|
+
result = ProcessOrderTask.call(order_id: 99999)
|
366
|
+
|
367
|
+
result.failed? # → true
|
368
|
+
result.status # → :failure
|
369
|
+
result.metadata[:reason] # → "ActiveRecord::RecordNotFound: Couldn't find Order..."
|
370
|
+
```
|
101
371
|
|
102
372
|
---
|
103
373
|
|