cmdx 1.1.0 → 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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +13 -12
  4. data/.cursor/prompts/yardoc.md +11 -6
  5. data/CHANGELOG.md +13 -2
  6. data/README.md +1 -0
  7. data/docs/ai_prompts.md +269 -195
  8. data/docs/basics/call.md +124 -58
  9. data/docs/basics/chain.md +190 -160
  10. data/docs/basics/context.md +242 -154
  11. data/docs/basics/setup.md +302 -32
  12. data/docs/callbacks.md +390 -94
  13. data/docs/configuration.md +181 -65
  14. data/docs/deprecation.md +245 -0
  15. data/docs/getting_started.md +161 -39
  16. data/docs/internationalization.md +590 -70
  17. data/docs/interruptions/exceptions.md +135 -118
  18. data/docs/interruptions/faults.md +150 -125
  19. data/docs/interruptions/halt.md +134 -80
  20. data/docs/logging.md +181 -118
  21. data/docs/middlewares.md +150 -377
  22. data/docs/outcomes/result.md +140 -112
  23. data/docs/outcomes/states.md +134 -99
  24. data/docs/outcomes/statuses.md +204 -146
  25. data/docs/parameters/coercions.md +232 -281
  26. data/docs/parameters/defaults.md +224 -169
  27. data/docs/parameters/definitions.md +289 -141
  28. data/docs/parameters/namespacing.md +250 -161
  29. data/docs/parameters/validations.md +260 -133
  30. data/docs/testing.md +191 -197
  31. data/docs/workflows.md +143 -98
  32. data/lib/cmdx/callback.rb +23 -19
  33. data/lib/cmdx/callback_registry.rb +1 -3
  34. data/lib/cmdx/chain_inspector.rb +23 -23
  35. data/lib/cmdx/chain_serializer.rb +38 -19
  36. data/lib/cmdx/coercion.rb +20 -12
  37. data/lib/cmdx/coercion_registry.rb +51 -32
  38. data/lib/cmdx/configuration.rb +84 -31
  39. data/lib/cmdx/context.rb +32 -21
  40. data/lib/cmdx/core_ext/hash.rb +13 -13
  41. data/lib/cmdx/core_ext/module.rb +1 -1
  42. data/lib/cmdx/core_ext/object.rb +12 -12
  43. data/lib/cmdx/correlator.rb +60 -39
  44. data/lib/cmdx/errors.rb +105 -131
  45. data/lib/cmdx/fault.rb +66 -45
  46. data/lib/cmdx/immutator.rb +20 -21
  47. data/lib/cmdx/lazy_struct.rb +78 -70
  48. data/lib/cmdx/log_formatters/json.rb +1 -1
  49. data/lib/cmdx/log_formatters/key_value.rb +1 -1
  50. data/lib/cmdx/log_formatters/line.rb +1 -1
  51. data/lib/cmdx/log_formatters/logstash.rb +1 -1
  52. data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
  53. data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
  54. data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
  55. data/lib/cmdx/log_formatters/raw.rb +2 -2
  56. data/lib/cmdx/logger.rb +19 -14
  57. data/lib/cmdx/logger_ansi.rb +33 -17
  58. data/lib/cmdx/logger_serializer.rb +85 -24
  59. data/lib/cmdx/middleware.rb +39 -21
  60. data/lib/cmdx/middleware_registry.rb +4 -3
  61. data/lib/cmdx/parameter.rb +151 -89
  62. data/lib/cmdx/parameter_inspector.rb +34 -21
  63. data/lib/cmdx/parameter_registry.rb +36 -30
  64. data/lib/cmdx/parameter_serializer.rb +21 -14
  65. data/lib/cmdx/result.rb +136 -135
  66. data/lib/cmdx/result_ansi.rb +31 -17
  67. data/lib/cmdx/result_inspector.rb +32 -27
  68. data/lib/cmdx/result_logger.rb +23 -14
  69. data/lib/cmdx/result_serializer.rb +65 -27
  70. data/lib/cmdx/task.rb +234 -113
  71. data/lib/cmdx/task_deprecator.rb +22 -25
  72. data/lib/cmdx/task_processor.rb +89 -88
  73. data/lib/cmdx/task_serializer.rb +27 -14
  74. data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
  75. data/lib/cmdx/validator.rb +25 -16
  76. data/lib/cmdx/validator_registry.rb +53 -31
  77. data/lib/cmdx/validators/exclusion.rb +1 -1
  78. data/lib/cmdx/validators/format.rb +2 -2
  79. data/lib/cmdx/validators/inclusion.rb +2 -2
  80. data/lib/cmdx/validators/length.rb +2 -2
  81. data/lib/cmdx/validators/numeric.rb +3 -3
  82. data/lib/cmdx/validators/presence.rb +2 -2
  83. data/lib/cmdx/version.rb +1 -1
  84. data/lib/cmdx/workflow.rb +54 -33
  85. data/lib/generators/cmdx/task_generator.rb +6 -6
  86. data/lib/generators/cmdx/workflow_generator.rb +6 -6
  87. metadata +3 -1
@@ -18,15 +18,31 @@ CMDx provides a flexible configuration system that allows customization at both
18
18
  - [Configuration Management](#configuration-management)
19
19
  - [Accessing Configuration](#accessing-configuration)
20
20
  - [Resetting Configuration](#resetting-configuration)
21
+ - [Error Handling](#error-handling)
21
22
 
22
23
  ## TLDR
23
24
 
24
- - **Hierarchy** - Global → Task Settings → Runtime (each level overrides previous)
25
- - **Global config** - Framework-wide defaults via `CMDx.configure`
26
- - **Task settings** - Class-level overrides using `cmd_settings!`
27
- - **Key options** - `task_halt`, `workflow_halt`, `logger`, `middlewares`, `callbacks`
28
- - **Generator** - Use `rails g cmdx:install` to create configuration file
29
- - **Inheritance** - Settings are inherited from parent classes
25
+ ```ruby
26
+ # Generate configuration file
27
+ rails g cmdx:install
28
+
29
+ # Global configuration
30
+ CMDx.configure do |config|
31
+ config.task_halt = ["failed", "skipped"] # Multiple halt statuses
32
+ config.logger = Rails.logger # Custom logger
33
+ config.middlewares.use TimeoutMiddleware # Global middleware
34
+ config.callbacks.register :on_failure, :log # Global callback
35
+ end
36
+
37
+ # Task-level overrides
38
+ class PaymentTask < CMDx::Task
39
+ cmd_settings!(task_halt: "failed", tags: ["payments"])
40
+
41
+ def call
42
+ halt_on = cmd_setting(:task_halt) # Access settings
43
+ end
44
+ end
45
+ ```
30
46
 
31
47
  ## Configuration Hierarchy
32
48
 
@@ -47,7 +63,7 @@ Generate a configuration file using the Rails generator:
47
63
  rails g cmdx:install
48
64
  ```
49
65
 
50
- This creates `config/initializers/cmdx.rb` with default settings.
66
+ This creates `config/initializers/cmdx.rb` with sensible defaults.
51
67
 
52
68
  ### Configuration Options
53
69
 
@@ -63,102 +79,112 @@ This creates `config/initializers/cmdx.rb` with default settings.
63
79
 
64
80
  ### Global Middlewares
65
81
 
66
- Configure middlewares that automatically apply to all tasks in your application:
82
+ Configure middlewares that automatically apply to all tasks:
67
83
 
68
84
  ```ruby
69
85
  CMDx.configure do |config|
70
- # Add middlewares without arguments
86
+ # Simple middleware registration
71
87
  config.middlewares.use CMDx::Middlewares::Timeout
72
88
 
73
- # Add middlewares with arguments
89
+ # Middleware with configuration
74
90
  config.middlewares.use CMDx::Middlewares::Timeout, seconds: 30
75
91
 
76
- # Add middleware instances
77
- config.middlewares.use CMDx::Middlewares::Timeout.new(seconds: 30)
92
+ # Multiple middlewares
93
+ config.middlewares.use AuthenticationMiddleware
94
+ config.middlewares.use LoggingMiddleware, level: :debug
95
+ config.middlewares.use MetricsMiddleware, namespace: "app.tasks"
78
96
  end
79
97
  ```
80
98
 
99
+ > [!NOTE]
100
+ > Middlewares are executed in registration order. Each middleware wraps the next, creating an execution chain around task logic.
101
+
81
102
  ### Global Callbacks
82
103
 
83
- Configure callbacks that automatically apply to all tasks in your application:
104
+ Configure callbacks that automatically apply to all tasks:
84
105
 
85
106
  ```ruby
86
107
  CMDx.configure do |config|
87
- # Add method callbacks
88
- config.callbacks.register :before_execution, :log_task_start
89
-
90
- # Add callback instances
91
- config.callbacks.register :on_success, NotificationCallback.new([:slack])
108
+ # Method callbacks
109
+ config.callbacks.register :before_execution, :setup_request_context
110
+ config.callbacks.register :after_execution, :cleanup_temp_files
92
111
 
93
- # Add conditional callbacks
94
- config.callbacks.register :on_failure, :page_admin, if: :production?
112
+ # Conditional callbacks
113
+ config.callbacks.register :on_failure, :notify_admin, if: :production?
114
+ config.callbacks.register :on_success, :update_metrics, unless: :test?
95
115
 
96
- # Add proc callbacks
116
+ # Proc callbacks with context
97
117
  config.callbacks.register :on_complete, proc { |task, type|
98
- Metrics.increment("task.#{task.class.name.underscore}.completed")
118
+ duration = task.metadata[:runtime]
119
+ StatsD.histogram("task.duration", duration, tags: ["class:#{task.class.name}"])
99
120
  }
100
121
  end
101
122
  ```
102
123
 
103
124
  ### Global Coercions
104
125
 
105
- Configure custom coercions that automatically apply to all tasks in your application:
126
+ Configure custom coercions for domain-specific types:
106
127
 
107
128
  ```ruby
108
129
  CMDx.configure do |config|
109
- # Add custom coercion classes
130
+ # Simple coercion classes
110
131
  config.coercions.register :money, MoneyCoercion
132
+ config.coercions.register :email, EmailCoercion
111
133
 
112
- # Add complex coercions with options support
113
- config.coercions.register :tags, proc { |value, options|
134
+ # Complex coercions with options
135
+ config.coercions.register :csv_array, proc { |value, options|
114
136
  separator = options[:separator] || ','
115
- max_tags = options[:max_tags] || 10
137
+ max_items = options[:max_items] || 100
116
138
 
117
- tags = value.to_s.split(separator).map(&:strip).reject(&:empty?)
118
- tags = tags.first(max_tags) if max_tags
119
- tags.uniq
139
+ items = value.to_s.split(separator).map(&:strip).reject(&:empty?)
140
+ items.first(max_items)
120
141
  }
121
142
  end
122
143
  ```
123
144
 
124
145
  ### Global Validators
125
146
 
126
- Configure validators that automatically apply to all tasks in your application:
147
+ Configure custom validators for parameter validation:
127
148
 
128
149
  ```ruby
129
150
  CMDx.configure do |config|
130
- # Add validator classes
151
+ # Validator classes
131
152
  config.validators.register :email, EmailValidator
153
+ config.validators.register :phone, PhoneValidator
132
154
 
133
- # Add complex validators with options support
134
- config.validators.register :phone, proc { |value, options|
135
- country = options.dig(:phone, :country) || "US"
136
- case country
137
- when "US"
138
- value.match?(/\A\d{3}-\d{3}-\d{4}\z/)
139
- else
140
- value.match?(/\A\+?\d{10,15}\z/)
141
- end
155
+ # Proc validators with options
156
+ config.validators.register :api_key, proc { |value, options|
157
+ required_prefix = options.dig(:api_key, :prefix) || "sk_"
158
+ min_length = options.dig(:api_key, :min_length) || 32
159
+
160
+ value.start_with?(required_prefix) && value.length >= min_length
142
161
  }
143
162
  end
144
163
  ```
145
164
 
146
165
  ## Task Settings
147
166
 
148
- Override global configuration for specific tasks or workflows using `cmd_settings!`:
167
+ Override global configuration for specific tasks using `cmd_settings!`:
149
168
 
150
169
  ```ruby
151
170
  class ProcessPaymentTask < CMDx::Task
152
171
  cmd_settings!(
153
- task_halt: ["failed"], # Only halt on failures
154
- tags: ["payments", "critical"], # Add logging tags
155
- logger: Rails.logger, # Use Rails logger
156
- log_level: :info, # Set log level
157
- log_formatter: CMDx::LogFormatters::Json.new # JSON formatter
172
+ task_halt: ["failed"], # Only halt on failures
173
+ tags: ["payments", "critical"], # Logging tags
174
+ logger: PaymentLogger.new, # Custom logger
175
+ log_level: :info, # Log level override
176
+ log_formatter: CMDx::LogFormatters::Json.new # JSON formatting
158
177
  )
159
178
 
160
179
  def call
161
- # Process payment logic
180
+ # Payment processing logic
181
+ charge_customer(amount, payment_method)
182
+ end
183
+
184
+ private
185
+
186
+ def charge_customer(amount, method)
187
+ # Implementation details
162
188
  end
163
189
  end
164
190
  ```
@@ -174,18 +200,39 @@ end
174
200
  | `log_level` | Symbol | Log level (`:debug`, `:info`, `:warn`, `:error`, `:fatal`) |
175
201
  | `log_formatter` | LogFormatter | Custom log formatter |
176
202
 
203
+ > [!TIP]
204
+ > Use task-level settings for tasks that require special handling, such as payment processing, external API calls, or critical system operations.
205
+
177
206
  ### Workflow Configuration
178
207
 
179
- Configure halt behavior for workflows:
208
+ Configure halt behavior and logging for workflows:
180
209
 
181
210
  ```ruby
182
211
  class OrderProcessingWorkflow < CMDx::Workflow
183
- # Strict workflow - halt on any failure
184
- cmd_settings!(workflow_halt: ["failed", "skipped"])
212
+ # Halt on any non-success status
213
+ cmd_settings!(
214
+ workflow_halt: ["failed", "skipped"],
215
+ tags: ["orders", "e-commerce"],
216
+ log_level: :info
217
+ )
185
218
 
186
219
  process ValidateOrderTask
187
220
  process ChargePaymentTask
188
- process FulfillOrderTask
221
+ process UpdateInventoryTask
222
+ process SendConfirmationTask
223
+ end
224
+
225
+ class DataMigrationWorkflow < CMDx::Workflow
226
+ # Continue on skipped tasks, halt only on failures
227
+ cmd_settings!(
228
+ workflow_halt: "failed",
229
+ tags: ["migration", "maintenance"]
230
+ )
231
+
232
+ process BackupDataTask
233
+ process MigrateUsersTask
234
+ process MigrateOrdersTask
235
+ process ValidateDataTask
189
236
  end
190
237
  ```
191
238
 
@@ -194,34 +241,103 @@ end
194
241
  ### Accessing Configuration
195
242
 
196
243
  ```ruby
197
- # Global configuration
198
- CMDx.configuration.logger #=> <Logger instance>
199
- CMDx.configuration.task_halt #=> "failed"
200
- CMDx.configuration.middlewares #=> <MiddlewareRegistry instance>
201
- CMDx.configuration.callbacks #=> <CallbackRegistry instance>
202
- CMDx.configuration.coercions #=> <CoercionRegistry instance>
203
- CMDx.configuration.validators #=> <ValidatorRegistry instance>
244
+ # Global configuration access
245
+ CMDx.configuration.logger #=> <Logger instance>
246
+ CMDx.configuration.task_halt #=> "failed"
247
+ CMDx.configuration.middlewares.middlewares #=> [<Middleware>, ...]
248
+ CMDx.configuration.callbacks.callbacks #=> {before_execution: [...], ...}
204
249
 
205
250
  # Task-specific settings
206
- class AnalyzeDataTask < CMDx::Task
207
- cmd_settings!(tags: ["analytics"])
251
+ class DataProcessingTask < CMDx::Task
252
+ cmd_settings!(
253
+ tags: ["data", "analytics"],
254
+ task_halt: ["failed", "skipped"]
255
+ )
208
256
 
209
257
  def call
210
- tags = cmd_setting(:tags) # Gets ["analytics"]
211
- halt_statuses = cmd_setting(:task_halt) # Gets global default
258
+ # Access current task settings
259
+ log_tags = cmd_setting(:tags) #=> ["data", "analytics"]
260
+ halt_on = cmd_setting(:task_halt) #=> ["failed", "skipped"]
261
+ logger_instance = cmd_setting(:logger) #=> Inherited from global
212
262
  end
213
263
  end
214
264
  ```
215
265
 
216
266
  ### Resetting Configuration
217
267
 
218
- Reset configuration to defaults (useful for testing):
268
+ > [!WARNING]
269
+ > Resetting configuration affects the entire application. Use primarily in test environments or during application initialization.
219
270
 
220
271
  ```ruby
272
+ # Reset to framework defaults
221
273
  CMDx.reset_configuration!
222
- CMDx.configuration.task_halt #=> "failed" (default)
274
+
275
+ # Verify reset
276
+ CMDx.configuration.task_halt #=> "failed" (default)
277
+ CMDx.configuration.middlewares #=> Empty registry
278
+ CMDx.configuration.callbacks #=> Empty registry
279
+
280
+ # Commonly used in test setup
281
+ RSpec.configure do |config|
282
+ config.before(:each) do
283
+ CMDx.reset_configuration!
284
+ end
285
+ end
286
+ ```
287
+
288
+ ## Error Handling
289
+
290
+ ### Configuration Validation
291
+
292
+ ```ruby
293
+ # Invalid configuration types
294
+ CMDx.configure do |config|
295
+ config.task_halt = :invalid_type # Error: must be String or Array
296
+ config.logger = "not_a_logger" # Error: must respond to logging methods
297
+ end
298
+ ```
299
+
300
+ ### Missing Settings Access
301
+
302
+ ```ruby
303
+ class ExampleTask < CMDx::Task
304
+ def call
305
+ # Accessing non-existent setting
306
+ value = cmd_setting(:non_existent_setting) #=> nil (returns nil for undefined)
307
+
308
+ # Check if setting exists
309
+ if cmd_setting(:custom_timeout)
310
+ timeout = cmd_setting(:custom_timeout)
311
+ else
312
+ timeout = 30 # fallback
313
+ end
314
+ end
315
+ end
316
+ ```
317
+
318
+ ### Configuration Conflicts
319
+
320
+ ```ruby
321
+ # Parent class configuration
322
+ class BaseTask < CMDx::Task
323
+ cmd_settings!(task_halt: "failed", tags: ["base"])
324
+ end
325
+
326
+ # Child class inherits and overrides
327
+ class SpecialTask < BaseTask
328
+ cmd_settings!(task_halt: ["failed", "skipped"]) # Overrides parent
329
+ # tags: ["base"] inherited from parent
330
+
331
+ def call
332
+ halt_statuses = cmd_setting(:task_halt) #=> ["failed", "skipped"]
333
+ inherited_tags = cmd_setting(:tags) #=> ["base"]
334
+ end
335
+ end
223
336
  ```
224
337
 
338
+ > [!IMPORTANT]
339
+ > Settings inheritance follows Ruby's method resolution order. Child class settings always override parent class settings for the same key.
340
+
225
341
  ---
226
342
 
227
343
  - **Prev:** [Getting Started](getting_started.md)
@@ -0,0 +1,245 @@
1
+ # Task Deprecation
2
+
3
+ Task deprecation provides a systematic approach to managing legacy tasks in CMDx applications. The deprecation system enables controlled migration paths by issuing warnings, logging messages, or preventing execution of deprecated tasks entirely, helping teams maintain code quality while providing clear upgrade paths.
4
+
5
+ ## Table of Contents
6
+
7
+ - [TLDR](#tldr)
8
+ - [Deprecation Fundamentals](#deprecation-fundamentals)
9
+ - [Deprecation Modes](#deprecation-modes)
10
+ - [Configuration Examples](#configuration-examples)
11
+ - [Migration Strategies](#migration-strategies)
12
+ - [Error Handling](#error-handling)
13
+ - [Best Practices](#best-practices)
14
+
15
+ ## TLDR
16
+
17
+ ```ruby
18
+ # Prevent task execution completely
19
+ class LegacyTask < CMDx::Task
20
+ cmd_setting!(deprecated: :error)
21
+ end
22
+
23
+ # Log deprecation warnings
24
+ class OldTask < CMDx::Task
25
+ cmd_setting!(deprecated: :log)
26
+ end
27
+
28
+ # Issue Ruby warnings
29
+ class ObsoleteTask < CMDx::Task
30
+ cmd_setting!(deprecated: :warning)
31
+ end
32
+
33
+ # Usage triggers appropriate deprecation handling
34
+ LegacyTask.call # → raises DeprecationError
35
+ OldTask.call # → logs warning via task.logger
36
+ ObsoleteTask.call # → issues Ruby warning
37
+ ```
38
+
39
+ ## Deprecation Fundamentals
40
+
41
+ > [!NOTE]
42
+ > Task deprecation is configured using the `cmd_setting!` declaration and processed automatically by CMDx before task execution. The deprecation system integrates seamlessly with existing logging and error handling infrastructure.
43
+
44
+ ### How It Works
45
+
46
+ 1. **Configuration**: Tasks declare deprecation mode using `cmd_setting!(deprecated: mode)`
47
+ 2. **Processing**: CMDx automatically calls `TaskDeprecator.call(task)` during task lifecycle
48
+ 3. **Action**: Appropriate deprecation handling occurs based on configured mode
49
+ 4. **Execution**: Task proceeds normally (unless `:error` mode prevents it)
50
+
51
+ ### Available Modes
52
+
53
+ | Mode | Behavior | Use Case |
54
+ |------|----------|----------|
55
+ | `:error` | Raises `DeprecationError` | Hard deprecation, prevent execution |
56
+ | `:log` | Logs warning via `task.logger.warn` | Soft deprecation, track usage |
57
+ | `:warning` | Issues Ruby warning | Development alerts |
58
+ | `true` | Same as `:log` | Legacy boolean support |
59
+ | `nil/false` | No deprecation handling | Default behavior |
60
+
61
+ ## Deprecation Modes
62
+
63
+ ### Error Mode (Hard Deprecation)
64
+
65
+ > [!WARNING]
66
+ > Error mode prevents task execution entirely. Use this for tasks that should no longer be used under any circumstances.
67
+
68
+ ```ruby
69
+ class ProcessLegacyPaymentTask < CMDx::Task
70
+ cmd_setting!(deprecated: :error)
71
+
72
+ def call
73
+ # This code will never execute
74
+ charge_customer(amount)
75
+ end
76
+ end
77
+
78
+ # Attempting to use deprecated task
79
+ result = ProcessLegacyPaymentTask.call(amount: 100)
80
+ # → raises CMDx::DeprecationError: "ProcessLegacyPaymentTask usage prohibited"
81
+ ```
82
+
83
+ ### Log Mode (Soft Deprecation)
84
+
85
+ > [!TIP]
86
+ > Log mode allows continued usage while tracking deprecation warnings. Perfect for gradual migration scenarios where immediate replacement isn't feasible.
87
+
88
+ ```ruby
89
+ class ProcessOldPaymentTask < CMDx::Task
90
+ cmd_setting!(deprecated: :log)
91
+
92
+ def call
93
+ # Task executes normally but logs deprecation warning
94
+ charge_customer(amount)
95
+ end
96
+ end
97
+
98
+ # Task executes with logged warning
99
+ result = ProcessOldPaymentTask.call(amount: 100)
100
+ result.successful? # → true
101
+
102
+ # Check logs for deprecation warning:
103
+ # WARN -- : DEPRECATED: migrate to replacement or discontinue use
104
+ ```
105
+
106
+ ### Warning Mode (Development Alerts)
107
+
108
+ > [!NOTE]
109
+ > Warning mode issues Ruby warnings visible in development and testing environments. Useful for alerting developers without affecting production logging.
110
+
111
+ ```ruby
112
+ class ProcessObsoletePaymentTask < CMDx::Task
113
+ cmd_setting!(deprecated: :warning)
114
+
115
+ def call
116
+ # Task executes with Ruby warning
117
+ charge_customer(amount)
118
+ end
119
+ end
120
+
121
+ # Task executes with Ruby warning
122
+ result = ProcessObsoletePaymentTask.call(amount: 100)
123
+ # stderr: [ProcessObsoletePaymentTask] DEPRECATED: migrate to replacement or discontinue use
124
+
125
+ result.successful? # → true
126
+ ```
127
+
128
+ ## Configuration Examples
129
+
130
+ ### Environment-Specific Deprecation
131
+
132
+ ```ruby
133
+ class ExperimentalFeatureTask < CMDx::Task
134
+ # Different deprecation behavior per environment
135
+ cmd_setting!(
136
+ deprecated: Rails.env.production? ? :error : :warning
137
+ )
138
+
139
+ def call
140
+ enable_experimental_feature
141
+ end
142
+ end
143
+ ```
144
+
145
+ ### Conditional Deprecation
146
+
147
+ ```ruby
148
+ class LegacyIntegrationTask < CMDx::Task
149
+ # Deprecate only for specific conditions
150
+ cmd_setting!(
151
+ deprecated: -> { ENV['NEW_API_ENABLED'] == 'true' ? :log : nil }
152
+ )
153
+
154
+ def call
155
+ call_legacy_api
156
+ end
157
+ end
158
+ ```
159
+
160
+ ## Migration Strategies
161
+
162
+ > [!IMPORTANT]
163
+ > When deprecating tasks, always provide clear migration paths and replacement implementations to minimize disruption.
164
+
165
+ ### Graceful Fallback
166
+
167
+ ```ruby
168
+ class NotificationTask < CMDx::Task
169
+ cmd_setting!(deprecated: :log)
170
+
171
+ def call
172
+ # Provide fallback while encouraging migration
173
+ logger.warn "Consider migrating to NotificationServiceV2"
174
+
175
+ # Delegate to new service but maintain compatibility
176
+ NotificationServiceV2.send_notification(
177
+ recipient: recipient,
178
+ message: message,
179
+ delivery_method: :legacy
180
+ )
181
+ end
182
+ end
183
+ ```
184
+
185
+ ## Error Handling
186
+
187
+ ### Catching Deprecation Errors
188
+
189
+ ```ruby
190
+ begin
191
+ result = LegacyTask.call(params)
192
+ rescue CMDx::DeprecationError => e
193
+ # Handle deprecation gracefully
194
+ Rails.logger.error "Attempted to use deprecated task: #{e.message}"
195
+
196
+ # Use replacement task instead
197
+ result = ReplacementTask.call(params)
198
+ end
199
+
200
+ if result.successful?
201
+ # Process successful result
202
+ else
203
+ # Handle task failure
204
+ end
205
+ ```
206
+
207
+ ## Best Practices
208
+
209
+ ### Documentation and Communication
210
+
211
+ > [!TIP]
212
+ > Always document deprecation reasons, timelines, and migration paths. Clear communication prevents confusion and reduces support burden.
213
+
214
+ ```ruby
215
+ class LegacyReportTask < CMDx::Task
216
+ # Document deprecation clearly
217
+ cmd_setting!(deprecated: :log)
218
+
219
+ # Class-level documentation
220
+ # @deprecated Use ReportGeneratorV2Task instead
221
+ # @see ReportGeneratorV2Task
222
+ # @note This task will be removed in v2.0.0
223
+ # @since 1.5.0 marked as deprecated
224
+
225
+ def call
226
+ # Add inline documentation
227
+ logger.warn <<~DEPRECATION
228
+ LegacyReportTask is deprecated and will be removed in v2.0.0.
229
+ Please migrate to ReportGeneratorV2Task which provides:
230
+ - Better performance
231
+ - Enhanced error handling
232
+ - More flexible output formats
233
+
234
+ Migration guide: https://docs.example.com/migration/reports
235
+ DEPRECATION
236
+
237
+ generate_legacy_report
238
+ end
239
+ end
240
+ ```
241
+
242
+ ---
243
+
244
+ - **Prev:** [Testing](testing.md)
245
+ - **Next:** [AI Prompts](ai_prompts.md)