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.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- 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 +390 -94
- data/docs/configuration.md +181 -65
- 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 +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- 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 +232 -281
- 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 +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
data/lib/cmdx/task.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Core task
|
4
|
+
# Core task implementation providing executable units of work with parameter management.
|
5
5
|
#
|
6
|
-
# Task
|
7
|
-
# with parameter validation, middleware
|
8
|
-
# result tracking. Tasks encapsulate
|
9
|
-
#
|
6
|
+
# Task is the fundamental building block of the CMDx framework, providing a structured
|
7
|
+
# approach to implementing business logic with built-in parameter validation, middleware
|
8
|
+
# support, callback handling, and comprehensive result tracking. Tasks encapsulate
|
9
|
+
# discrete units of work that can be chained together into workflows or executed
|
10
|
+
# independently with rich execution context and error handling.
|
10
11
|
class Task
|
11
12
|
|
12
13
|
cmdx_attr_setting :cmd_settings,
|
@@ -45,20 +46,28 @@ module CMDx
|
|
45
46
|
# @return [Result] alias for result
|
46
47
|
alias res result
|
47
48
|
|
48
|
-
# Creates a new task instance with the
|
49
|
+
# Creates a new task instance with the given execution context.
|
49
50
|
#
|
50
|
-
#
|
51
|
+
# Initializes all internal state including context, errors, unique identifier,
|
52
|
+
# result tracking, and execution chain. The context parameter supports various
|
53
|
+
# input formats and will be normalized into a Context instance.
|
51
54
|
#
|
52
|
-
# @
|
55
|
+
# @param context [Hash, Context, Object] initial execution context and parameters
|
53
56
|
#
|
54
|
-
# @
|
57
|
+
# @return [Task] the newly created task instance
|
58
|
+
#
|
59
|
+
# @example Create task with hash context
|
55
60
|
# task = MyTask.new(user_id: 123, action: "process")
|
56
61
|
# task.context.user_id #=> 123
|
57
62
|
#
|
58
|
-
# @example Create
|
59
|
-
# existing_context =
|
63
|
+
# @example Create task with existing context
|
64
|
+
# existing_context = OtherTask.call(status: "active")
|
60
65
|
# task = MyTask.new(existing_context)
|
61
|
-
# task.context.
|
66
|
+
# task.context.status #=> "active"
|
67
|
+
#
|
68
|
+
# @example Create task with empty context
|
69
|
+
# task = MyTask.new
|
70
|
+
# task.context #=> empty Context instance
|
62
71
|
def initialize(context = {})
|
63
72
|
context = context.context if context.respond_to?(:context)
|
64
73
|
|
@@ -73,95 +82,138 @@ module CMDx
|
|
73
82
|
|
74
83
|
class << self
|
75
84
|
|
76
|
-
# Registers callbacks for task execution lifecycle events.
|
77
|
-
#
|
78
|
-
# These methods are dynamically defined for each callback type and provide
|
79
|
-
# a clean DSL for registering callbacks that will be executed at specific
|
80
|
-
# points during task execution.
|
81
|
-
#
|
82
|
-
# @param callables [Array<Object>] callback objects to register (symbols, procs, classes)
|
83
|
-
# @param options [Hash] conditional execution options
|
84
|
-
# @param block [Proc] optional block to register as a callback
|
85
|
-
#
|
86
|
-
# @return [void]
|
87
|
-
#
|
88
|
-
# @example Register before_execution callback with symbol
|
89
|
-
# MyTask.before_execution :setup_database
|
90
|
-
#
|
91
|
-
# @example Register before_execution callback with proc
|
92
|
-
# MyTask.before_execution -> { puts "Starting task execution" }
|
93
|
-
#
|
94
|
-
# @example Register before_execution callback with class
|
95
|
-
# MyTask.before_execution SetupCallback
|
96
|
-
#
|
97
|
-
# @example Register before_execution callback with block
|
98
|
-
# MyTask.before_execution { |task| task.context.started_at = Time.now }
|
99
|
-
#
|
100
|
-
# @example Register on_success callback with conditional options
|
101
|
-
# MyTask.on_success :send_notification, if: -> { Rails.env.production? }
|
102
|
-
#
|
103
|
-
# @example Register on_success callback with multiple callables
|
104
|
-
# MyTask.on_success :log_success, :send_email, :update_metrics
|
105
85
|
CallbackRegistry::TYPES.each do |callback|
|
86
|
+
# Registers a callback for the specified lifecycle event.
|
87
|
+
#
|
88
|
+
# This method is dynamically defined for each callback type supported by
|
89
|
+
# CallbackRegistry, allowing tasks to register callbacks for various
|
90
|
+
# execution lifecycle events.
|
91
|
+
#
|
92
|
+
# @param callables [Array<Object>] callback objects or procs to register
|
93
|
+
# @param options [Hash] options for callback registration
|
94
|
+
# @param block [Proc] optional block to use as callback
|
95
|
+
#
|
96
|
+
# @return [void]
|
97
|
+
#
|
98
|
+
# @example Register before_execution callback with symbol
|
99
|
+
# class MyTask < CMDx::Task
|
100
|
+
# before_execution :setup_database
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# @example Register before_execution callback with proc
|
104
|
+
# class MyTask < CMDx::Task
|
105
|
+
# before_execution -> { puts "Starting task execution" }
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# @example Register before_execution callback with class
|
109
|
+
# class MyTask < CMDx::Task
|
110
|
+
# before_execution SetupCallback
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# @example Register before_execution callback with block
|
114
|
+
# class MyTask < CMDx::Task
|
115
|
+
# before_execution { |task| task.context.started_at = Time.now }
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# @example Register on_success callback with conditional options
|
119
|
+
# class MyTask < CMDx::Task
|
120
|
+
# on_success :send_notification, if: -> { Rails.env.production? }
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# @example Register on_success callback with multiple callables
|
124
|
+
# class MyTask < CMDx::Task
|
125
|
+
# on_success :log_success, :send_email, :update_metrics
|
126
|
+
# end
|
106
127
|
define_method(callback) do |*callables, **options, &block|
|
107
128
|
cmd_callbacks.register(callback, *callables, **options, &block)
|
108
129
|
end
|
109
130
|
end
|
110
131
|
|
111
|
-
# Retrieves
|
132
|
+
# Retrieves a configuration setting value by key.
|
133
|
+
#
|
134
|
+
# Provides access to task-specific configuration settings that control
|
135
|
+
# various aspects of task execution including logging, halt conditions,
|
136
|
+
# and custom settings.
|
112
137
|
#
|
113
|
-
# @param key [Symbol] the setting key to retrieve
|
138
|
+
# @param key [Symbol, String] the configuration setting key to retrieve
|
114
139
|
#
|
115
|
-
# @return [Object] the
|
140
|
+
# @return [Object] the configuration value, or nil if key doesn't exist
|
116
141
|
#
|
117
142
|
# @example Get logger setting
|
118
|
-
# MyTask.cmd_setting(:logger) #=>
|
143
|
+
# MyTask.cmd_setting(:logger) #=> Logger instance
|
119
144
|
#
|
120
|
-
# @example Get
|
121
|
-
# MyTask.
|
145
|
+
# @example Get custom setting
|
146
|
+
# MyTask.cmd_settings!(timeout: 30)
|
147
|
+
# MyTask.cmd_setting(:timeout) #=> 30
|
122
148
|
def cmd_setting(key)
|
123
149
|
cmdx_yield(cmd_settings[key])
|
124
150
|
end
|
125
151
|
|
126
|
-
# Checks if a
|
152
|
+
# Checks if a configuration setting exists.
|
127
153
|
#
|
128
|
-
# @param key [Symbol] the setting key to check
|
154
|
+
# @param key [Symbol, String] the configuration setting key to check
|
129
155
|
#
|
130
|
-
# @return [Boolean] true if the setting exists, false otherwise
|
156
|
+
# @return [Boolean] true if the setting key exists, false otherwise
|
131
157
|
#
|
132
|
-
# @example Check
|
158
|
+
# @example Check for existing setting
|
133
159
|
# MyTask.cmd_setting?(:logger) #=> true
|
134
|
-
#
|
160
|
+
#
|
161
|
+
# @example Check for non-existing setting
|
162
|
+
# MyTask.cmd_setting?(:nonexistent) #=> false
|
135
163
|
def cmd_setting?(key)
|
136
164
|
cmd_settings.key?(key)
|
137
165
|
end
|
138
166
|
|
139
|
-
# Updates task settings with
|
167
|
+
# Updates task configuration settings with the provided options.
|
140
168
|
#
|
141
|
-
#
|
169
|
+
# Merges the given options into the existing configuration settings,
|
170
|
+
# allowing tasks to customize their execution behavior.
|
142
171
|
#
|
143
|
-
# @
|
172
|
+
# @param options [Hash] configuration options to merge
|
144
173
|
#
|
145
|
-
# @
|
174
|
+
# @return [Hash] the updated settings hash
|
175
|
+
#
|
176
|
+
# @example Set custom timeout
|
177
|
+
# MyTask.cmd_settings!(timeout: 60, retries: 3)
|
178
|
+
#
|
179
|
+
# @example Override halt condition
|
146
180
|
# MyTask.cmd_settings!(task_halt: ["failed", "error"])
|
147
|
-
# MyTask.cmd_setting(:task_halt) #=> ["failed", "error"]
|
148
181
|
def cmd_settings!(**options)
|
149
182
|
cmd_settings.merge!(options)
|
150
183
|
end
|
151
184
|
|
152
185
|
# Registers middleware, callbacks, validators, or coercions with the task.
|
153
186
|
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
187
|
+
# Provides a unified interface for registering various types of task
|
188
|
+
# extensions that modify or enhance task execution behavior.
|
189
|
+
#
|
190
|
+
# @param type [Symbol] the type of extension to register (:middleware, :callback, :validator, :coercion)
|
191
|
+
# @param object [Object] the extension object to register
|
192
|
+
# @param args [Array] additional arguments for registration
|
157
193
|
#
|
158
194
|
# @return [void]
|
159
195
|
#
|
196
|
+
# @raise [ArgumentError] if an unsupported type is provided
|
197
|
+
#
|
198
|
+
# @example Register coercion
|
199
|
+
# class MyTask < CMDx::Task
|
200
|
+
# use :coercion, TemperatureCoercion
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# @example Register validator
|
204
|
+
# class MyTask < CMDx::Task
|
205
|
+
# use :validator, ZipcodeValidator, country: "US"
|
206
|
+
# end
|
207
|
+
#
|
160
208
|
# @example Register middleware
|
161
|
-
# MyTask
|
209
|
+
# class MyTask < CMDx::Task
|
210
|
+
# use :middleware, CMDx::Middlewares::Timeout.new(seconds: 30)
|
211
|
+
# end
|
162
212
|
#
|
163
213
|
# @example Register callback
|
164
|
-
# MyTask
|
214
|
+
# class MyTask < CMDx::Task
|
215
|
+
# use :callback, :before, LogCallback.new
|
216
|
+
# end
|
165
217
|
def use(type, object, ...)
|
166
218
|
case type
|
167
219
|
when :middleware
|
@@ -175,77 +227,120 @@ module CMDx
|
|
175
227
|
end
|
176
228
|
end
|
177
229
|
|
178
|
-
# Defines optional parameters for the task.
|
230
|
+
# Defines optional parameters for the task with validation and coercion.
|
231
|
+
#
|
232
|
+
# Creates parameter definitions that are not required for task execution
|
233
|
+
# but will be validated and coerced if provided. Supports nested parameter
|
234
|
+
# structures through block syntax.
|
179
235
|
#
|
180
236
|
# @param attributes [Array<Symbol>] parameter names to define as optional
|
181
237
|
# @param options [Hash] parameter configuration options
|
238
|
+
# @option options [Symbol, Array<Symbol>] :type parameter type(s) for coercion
|
239
|
+
# @option options [Object] :default default value if parameter not provided
|
240
|
+
# @option options [Hash] :validates validation rules to apply
|
182
241
|
# @param block [Proc] optional block for defining nested parameters
|
183
242
|
#
|
184
|
-
# @return [
|
243
|
+
# @return [Array<Parameter>] the created parameter definitions
|
185
244
|
#
|
186
|
-
# @example Define optional parameters
|
187
|
-
# MyTask
|
245
|
+
# @example Define simple optional parameters
|
246
|
+
# class MyTask < CMDx::Task
|
247
|
+
# optional :name, :email, type: :string
|
248
|
+
# optional :age, type: :integer, default: 0
|
249
|
+
# end
|
188
250
|
#
|
189
251
|
# @example Define optional parameter with validation
|
190
|
-
# MyTask
|
252
|
+
# class MyTask < CMDx::Task
|
253
|
+
# optional :score, type: :integer, validates: { numeric: { greater_than: 0 } }
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
# @example Define nested optional parameters
|
257
|
+
# class MyTask < CMDx::Task
|
258
|
+
# optional :user, type: :hash do
|
259
|
+
# required :name, type: :string
|
260
|
+
# optional :age, type: :integer
|
261
|
+
# end
|
262
|
+
# end
|
191
263
|
def optional(*attributes, **options, &)
|
192
264
|
parameters = Parameter.optional(*attributes, **options.merge(klass: self), &)
|
193
265
|
cmd_parameters.registry.concat(parameters)
|
194
266
|
end
|
195
267
|
|
196
|
-
# Defines required parameters for the task.
|
268
|
+
# Defines required parameters for the task with validation and coercion.
|
269
|
+
#
|
270
|
+
# Creates parameter definitions that must be provided for successful task
|
271
|
+
# execution. Missing required parameters will cause task validation to fail.
|
272
|
+
# Supports nested parameter structures through block syntax.
|
197
273
|
#
|
198
274
|
# @param attributes [Array<Symbol>] parameter names to define as required
|
199
275
|
# @param options [Hash] parameter configuration options
|
276
|
+
# @option options [Symbol, Array<Symbol>] :type parameter type(s) for coercion
|
277
|
+
# @option options [Object] :default default value if parameter not provided
|
278
|
+
# @option options [Hash] :validates validation rules to apply
|
200
279
|
# @param block [Proc] optional block for defining nested parameters
|
201
280
|
#
|
202
|
-
# @return [
|
281
|
+
# @return [Array<Parameter>] the created parameter definitions
|
282
|
+
#
|
283
|
+
# @example Define simple required parameters
|
284
|
+
# class MyTask < CMDx::Task
|
285
|
+
# required :user_id, type: :integer
|
286
|
+
# required :action, type: :string
|
287
|
+
# end
|
203
288
|
#
|
204
|
-
# @example Define required
|
205
|
-
# MyTask
|
289
|
+
# @example Define required parameter with validation
|
290
|
+
# class MyTask < CMDx::Task
|
291
|
+
# required :email, type: :string, validates: { format: /@/ }
|
292
|
+
# end
|
206
293
|
#
|
207
|
-
# @example Define required
|
208
|
-
# MyTask
|
209
|
-
# required :
|
210
|
-
#
|
294
|
+
# @example Define nested required parameters
|
295
|
+
# class MyTask < CMDx::Task
|
296
|
+
# required :payment, type: :hash do
|
297
|
+
# required :amount, type: :big_decimal
|
298
|
+
# required :currency, type: :string
|
299
|
+
# optional :description, type: :string
|
300
|
+
# end
|
211
301
|
# end
|
212
302
|
def required(*attributes, **options, &)
|
213
303
|
parameters = Parameter.required(*attributes, **options.merge(klass: self), &)
|
214
304
|
cmd_parameters.registry.concat(parameters)
|
215
305
|
end
|
216
306
|
|
217
|
-
# Executes
|
307
|
+
# Executes a task instance and returns the result without raising exceptions.
|
308
|
+
#
|
309
|
+
# Creates a new task instance with the provided context, processes it through
|
310
|
+
# the complete execution pipeline, and returns the result. This method will
|
311
|
+
# not raise exceptions for task failures but will capture them in the result.
|
218
312
|
#
|
219
|
-
# @param args [Array] arguments passed to
|
313
|
+
# @param args [Array] arguments passed to task constructor
|
220
314
|
#
|
221
|
-
# @return [Result] the
|
315
|
+
# @return [Result] the execution result containing state, status, and metadata
|
222
316
|
#
|
223
|
-
# @example Execute task
|
224
|
-
# result = MyTask.call(user_id: 123)
|
225
|
-
# result.
|
226
|
-
# result.context.user_id #=> 123
|
317
|
+
# @example Execute task
|
318
|
+
# result = MyTask.call(user_id: 123, action: "process")
|
319
|
+
# puts result.status #=> "success" or "failed" or "skipped"
|
227
320
|
def call(...)
|
228
321
|
instance = new(...)
|
229
322
|
instance.process
|
230
323
|
instance.result
|
231
324
|
end
|
232
325
|
|
233
|
-
# Executes
|
326
|
+
# Executes a task instance and returns the result, raising exceptions on failure.
|
234
327
|
#
|
235
|
-
#
|
328
|
+
# Creates a new task instance with the provided context, processes it through
|
329
|
+
# the complete execution pipeline, and returns the result. This method will
|
330
|
+
# raise appropriate fault exceptions if the task fails or is skipped.
|
236
331
|
#
|
237
|
-
# @
|
332
|
+
# @param args [Array] arguments passed to task constructor
|
238
333
|
#
|
239
|
-
# @
|
334
|
+
# @return [Result] the execution result containing state, status, and metadata
|
240
335
|
#
|
241
|
-
# @
|
242
|
-
#
|
243
|
-
# result.success? #=> true
|
336
|
+
# @raise [Failed] when task execution fails
|
337
|
+
# @raise [Skipped] when task execution is skipped
|
244
338
|
#
|
245
|
-
# @example
|
339
|
+
# @example Execute task
|
246
340
|
# begin
|
247
|
-
# MyTask.call!(
|
248
|
-
#
|
341
|
+
# result = MyTask.call!(user_id: 123)
|
342
|
+
# puts "Success: #{result.status}"
|
343
|
+
# rescue CMDx::Failed => e
|
249
344
|
# puts "Task failed: #{e.message}"
|
250
345
|
# end
|
251
346
|
def call!(...)
|
@@ -258,58 +353,84 @@ module CMDx
|
|
258
353
|
|
259
354
|
# Abstract method that must be implemented by task subclasses.
|
260
355
|
#
|
261
|
-
# This method contains the
|
262
|
-
#
|
356
|
+
# This method contains the actual business logic for the task. Subclasses
|
357
|
+
# must override this method to provide their specific implementation.
|
358
|
+
# The method has access to the task's context, can modify it, and can
|
359
|
+
# use skip!, fail!, or throw! to control execution flow.
|
263
360
|
#
|
264
361
|
# @return [void]
|
265
362
|
#
|
266
|
-
# @raise [UndefinedCallError]
|
363
|
+
# @raise [UndefinedCallError] always raised in the base Task class
|
267
364
|
#
|
268
365
|
# @example Implement in a subclass
|
269
366
|
# class ProcessUserTask < CMDx::Task
|
367
|
+
# required :user_id, type: :integer
|
368
|
+
#
|
270
369
|
# def call
|
271
|
-
#
|
272
|
-
#
|
370
|
+
# user = User.find(context.user_id)
|
371
|
+
# skip!(reason: "User already processed") if user.processed?
|
372
|
+
#
|
373
|
+
# user.process!
|
374
|
+
# context.processed_at = Time.now
|
273
375
|
# end
|
274
376
|
# end
|
275
377
|
def call
|
276
378
|
raise UndefinedCallError, "call method not defined in #{self.class.name}"
|
277
379
|
end
|
278
380
|
|
279
|
-
#
|
381
|
+
# Executes the task through the middleware pipeline without raising exceptions.
|
382
|
+
#
|
383
|
+
# Processes the task by running it through all registered middleware and
|
384
|
+
# the TaskProcessor. This method captures exceptions and converts them
|
385
|
+
# into result states rather than propagating them.
|
280
386
|
#
|
281
387
|
# @return [void]
|
282
388
|
#
|
283
|
-
# @example
|
284
|
-
# task = MyTask.new(
|
389
|
+
# @example Process a task instance
|
390
|
+
# task = MyTask.new(data: "input")
|
285
391
|
# task.process
|
286
|
-
# task.result.
|
392
|
+
# puts task.result.status #=> "success", "failed", or "skipped"
|
287
393
|
def process
|
288
394
|
cmd_middlewares.call(self) { |task| TaskProcessor.call(task) }
|
289
395
|
end
|
290
396
|
|
291
|
-
#
|
397
|
+
# Executes the task through the middleware pipeline, raising exceptions on failure.
|
398
|
+
#
|
399
|
+
# Processes the task by running it through all registered middleware and
|
400
|
+
# the TaskProcessor. This method will raise appropriate fault exceptions
|
401
|
+
# if the task fails or is skipped.
|
292
402
|
#
|
293
403
|
# @return [void]
|
294
404
|
#
|
295
|
-
# @raise [
|
405
|
+
# @raise [Failed] when task execution fails
|
406
|
+
# @raise [Skipped] when task execution is skipped
|
296
407
|
#
|
297
|
-
# @example
|
298
|
-
# task =
|
299
|
-
#
|
300
|
-
#
|
408
|
+
# @example Process a task instance with exception handling
|
409
|
+
# task = RiskyTask.new(data: "input")
|
410
|
+
# begin
|
411
|
+
# task.process!
|
412
|
+
# puts "Task completed successfully"
|
413
|
+
# rescue CMDx::Failed => e
|
414
|
+
# puts "Task failed: #{e.message}"
|
415
|
+
# end
|
301
416
|
def process!
|
302
417
|
cmd_middlewares.call(self) { |task| TaskProcessor.call!(task) }
|
303
418
|
end
|
304
419
|
|
305
|
-
# Creates a logger instance for this task.
|
420
|
+
# Creates a logger instance configured for this task.
|
306
421
|
#
|
307
|
-
#
|
422
|
+
# Returns a logger instance that is pre-configured with the task's
|
423
|
+
# settings and context information for consistent logging throughout
|
424
|
+
# task execution.
|
308
425
|
#
|
309
|
-
# @
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
426
|
+
# @return [Logger] configured logger instance for this task
|
427
|
+
#
|
428
|
+
# @example Log task execution
|
429
|
+
# def call
|
430
|
+
# logger.info "Starting user processing"
|
431
|
+
# # ... task logic ...
|
432
|
+
# logger.info "User processing completed"
|
433
|
+
# end
|
313
434
|
def logger
|
314
435
|
Logger.call(self)
|
315
436
|
end
|
data/lib/cmdx/task_deprecator.rb
CHANGED
@@ -1,52 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
#
|
4
|
+
# Task deprecation system for CMDx tasks.
|
5
5
|
#
|
6
|
-
# This module provides
|
7
|
-
# and
|
8
|
-
#
|
6
|
+
# This module provides a centralized system for handling task deprecation
|
7
|
+
# warnings and errors. It supports multiple deprecation modes including
|
8
|
+
# raising exceptions, logging warnings, or issuing Ruby warnings based
|
9
|
+
# on task configuration settings.
|
9
10
|
module TaskDeprecator
|
10
11
|
|
11
12
|
module_function
|
12
13
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# This method examines the task's deprecation setting and takes appropriate action:
|
16
|
-
# - :raise - raises DeprecationError to prevent task execution
|
17
|
-
# - :warn - issues Ruby deprecation warning
|
18
|
-
# - :log or true - logs deprecation warning
|
19
|
-
# - nil or false - allows task execution without warnings
|
20
|
-
#
|
21
|
-
# @param task [Task] the task instance to check for deprecation
|
14
|
+
# Processes task deprecation based on the task's deprecated setting.
|
22
15
|
#
|
16
|
+
# @param task [CMDx::Task] the task instance to check for deprecation
|
23
17
|
# @return [void]
|
18
|
+
# @raise [DeprecationError] when task's deprecated setting is :error
|
24
19
|
#
|
25
|
-
# @
|
26
|
-
#
|
27
|
-
# @example Task with raise deprecation setting
|
20
|
+
# @example Handle task with raise deprecation
|
28
21
|
# class MyTask < CMDx::Task
|
29
|
-
#
|
22
|
+
# cmd_setting!(deprecated: :error)
|
30
23
|
# end
|
31
|
-
#
|
24
|
+
# task = MyTask.new
|
25
|
+
# TaskDeprecator.call(task) # raises DeprecationError
|
32
26
|
#
|
33
|
-
# @example
|
27
|
+
# @example Handle task with log deprecation
|
34
28
|
# class MyTask < CMDx::Task
|
35
|
-
#
|
29
|
+
# cmd_setting!(deprecated: :log)
|
36
30
|
# end
|
37
|
-
#
|
31
|
+
# task = MyTask.new
|
32
|
+
# TaskDeprecator.call(task) # logs warning via task.logger
|
38
33
|
#
|
39
|
-
# @example
|
34
|
+
# @example Handle task with warn deprecation
|
40
35
|
# class MyTask < CMDx::Task
|
36
|
+
# cmd_setting!(deprecated: :warning)
|
41
37
|
# end
|
42
|
-
#
|
38
|
+
# task = MyTask.new
|
39
|
+
# TaskDeprecator.call(task) # issues Ruby warning
|
43
40
|
def call(task)
|
44
41
|
case task.cmd_setting(:deprecated)
|
45
|
-
when :
|
42
|
+
when :error
|
46
43
|
raise(DeprecationError, "#{task.class.name} usage prohibited")
|
47
44
|
when :log, true
|
48
45
|
task.logger.warn { "DEPRECATED: migrate to replacement or discontinue use" }
|
49
|
-
when :
|
46
|
+
when :warning
|
50
47
|
warn("[#{task.class.name}] DEPRECATED: migrate to replacement or discontinue use", category: :deprecated)
|
51
48
|
end
|
52
49
|
end
|