cmdx 1.1.2 → 1.5.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.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +4 -1
- data/.cursor/prompts/llms.md +20 -0
- data/.cursor/prompts/rspec.md +4 -1
- data/.cursor/prompts/yardoc.md +3 -2
- data/.cursor/rules/cursor-instructions.mdc +56 -1
- data/.irbrc +6 -0
- data/.rubocop.yml +29 -18
- data/CHANGELOG.md +5 -133
- data/LLM.md +3317 -0
- data/README.md +68 -44
- data/docs/attributes/coercions.md +162 -0
- data/docs/attributes/defaults.md +90 -0
- data/docs/attributes/definitions.md +281 -0
- data/docs/attributes/naming.md +78 -0
- data/docs/attributes/validations.md +309 -0
- data/docs/basics/chain.md +56 -249
- data/docs/basics/context.md +56 -289
- data/docs/basics/execution.md +114 -0
- data/docs/basics/setup.md +37 -334
- data/docs/callbacks.md +89 -467
- data/docs/deprecation.md +91 -174
- data/docs/getting_started.md +212 -202
- data/docs/internationalization.md +11 -647
- data/docs/interruptions/exceptions.md +23 -198
- data/docs/interruptions/faults.md +71 -151
- data/docs/interruptions/halt.md +109 -186
- data/docs/logging.md +44 -256
- data/docs/middlewares.md +113 -426
- data/docs/outcomes/result.md +81 -228
- data/docs/outcomes/states.md +33 -221
- data/docs/outcomes/statuses.md +21 -311
- data/docs/tips_and_tricks.md +120 -70
- data/docs/workflows.md +99 -283
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/attribute.rb +229 -0
- data/lib/cmdx/attribute_registry.rb +94 -0
- data/lib/cmdx/attribute_value.rb +193 -0
- data/lib/cmdx/callback_registry.rb +69 -77
- data/lib/cmdx/chain.rb +56 -73
- data/lib/cmdx/coercion_registry.rb +52 -68
- data/lib/cmdx/coercions/array.rb +19 -18
- data/lib/cmdx/coercions/big_decimal.rb +20 -24
- data/lib/cmdx/coercions/boolean.rb +26 -25
- data/lib/cmdx/coercions/complex.rb +21 -22
- data/lib/cmdx/coercions/date.rb +25 -23
- data/lib/cmdx/coercions/date_time.rb +24 -25
- data/lib/cmdx/coercions/float.rb +25 -22
- data/lib/cmdx/coercions/hash.rb +31 -32
- data/lib/cmdx/coercions/integer.rb +30 -24
- data/lib/cmdx/coercions/rational.rb +29 -24
- data/lib/cmdx/coercions/string.rb +19 -22
- data/lib/cmdx/coercions/symbol.rb +37 -0
- data/lib/cmdx/coercions/time.rb +26 -25
- data/lib/cmdx/configuration.rb +49 -108
- data/lib/cmdx/context.rb +222 -44
- data/lib/cmdx/deprecator.rb +61 -0
- data/lib/cmdx/errors.rb +42 -252
- data/lib/cmdx/exceptions.rb +39 -0
- data/lib/cmdx/faults.rb +78 -39
- data/lib/cmdx/freezer.rb +51 -0
- data/lib/cmdx/identifier.rb +30 -0
- data/lib/cmdx/locale.rb +52 -0
- data/lib/cmdx/log_formatters/json.rb +21 -22
- data/lib/cmdx/log_formatters/key_value.rb +20 -22
- data/lib/cmdx/log_formatters/line.rb +15 -22
- data/lib/cmdx/log_formatters/logstash.rb +22 -23
- data/lib/cmdx/log_formatters/raw.rb +16 -22
- data/lib/cmdx/middleware_registry.rb +70 -74
- data/lib/cmdx/middlewares/correlate.rb +90 -54
- data/lib/cmdx/middlewares/runtime.rb +58 -0
- data/lib/cmdx/middlewares/timeout.rb +48 -68
- data/lib/cmdx/railtie.rb +12 -45
- data/lib/cmdx/result.rb +229 -314
- data/lib/cmdx/task.rb +194 -366
- data/lib/cmdx/utils/call.rb +49 -0
- data/lib/cmdx/utils/condition.rb +71 -0
- data/lib/cmdx/utils/format.rb +61 -0
- data/lib/cmdx/validator_registry.rb +63 -72
- data/lib/cmdx/validators/exclusion.rb +38 -67
- data/lib/cmdx/validators/format.rb +48 -49
- data/lib/cmdx/validators/inclusion.rb +43 -74
- data/lib/cmdx/validators/length.rb +91 -154
- data/lib/cmdx/validators/numeric.rb +87 -162
- data/lib/cmdx/validators/presence.rb +37 -50
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/worker.rb +178 -0
- data/lib/cmdx/workflow.rb +85 -81
- data/lib/cmdx.rb +19 -13
- data/lib/generators/cmdx/install_generator.rb +14 -13
- data/lib/generators/cmdx/task_generator.rb +25 -50
- data/lib/generators/cmdx/templates/install.rb +11 -46
- data/lib/generators/cmdx/templates/task.rb.tt +3 -2
- data/lib/locales/en.yml +18 -4
- data/src/cmdx-logo.png +0 -0
- metadata +32 -116
- data/docs/ai_prompts.md +0 -393
- data/docs/basics/call.md +0 -317
- data/docs/configuration.md +0 -344
- data/docs/parameters/coercions.md +0 -396
- data/docs/parameters/defaults.md +0 -335
- data/docs/parameters/definitions.md +0 -446
- data/docs/parameters/namespacing.md +0 -378
- data/docs/parameters/validations.md +0 -405
- data/docs/testing.md +0 -553
- data/lib/cmdx/callback.rb +0 -53
- data/lib/cmdx/chain_inspector.rb +0 -56
- data/lib/cmdx/chain_serializer.rb +0 -63
- data/lib/cmdx/coercion.rb +0 -57
- data/lib/cmdx/coercions/virtual.rb +0 -29
- data/lib/cmdx/core_ext/hash.rb +0 -83
- data/lib/cmdx/core_ext/module.rb +0 -98
- data/lib/cmdx/core_ext/object.rb +0 -125
- data/lib/cmdx/correlator.rb +0 -122
- data/lib/cmdx/error.rb +0 -67
- data/lib/cmdx/fault.rb +0 -140
- data/lib/cmdx/immutator.rb +0 -52
- data/lib/cmdx/lazy_struct.rb +0 -246
- data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
- data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
- data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
- data/lib/cmdx/logger.rb +0 -49
- data/lib/cmdx/logger_ansi.rb +0 -68
- data/lib/cmdx/logger_serializer.rb +0 -116
- data/lib/cmdx/middleware.rb +0 -70
- data/lib/cmdx/parameter.rb +0 -312
- data/lib/cmdx/parameter_evaluator.rb +0 -231
- data/lib/cmdx/parameter_inspector.rb +0 -66
- data/lib/cmdx/parameter_registry.rb +0 -106
- data/lib/cmdx/parameter_serializer.rb +0 -59
- data/lib/cmdx/result_ansi.rb +0 -71
- data/lib/cmdx/result_inspector.rb +0 -71
- data/lib/cmdx/result_logger.rb +0 -59
- data/lib/cmdx/result_serializer.rb +0 -104
- data/lib/cmdx/rspec/matchers.rb +0 -28
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
- data/lib/cmdx/task_deprecator.rb +0 -58
- data/lib/cmdx/task_processor.rb +0 -246
- data/lib/cmdx/task_serializer.rb +0 -57
- data/lib/cmdx/utils/ansi_color.rb +0 -73
- data/lib/cmdx/utils/log_timestamp.rb +0 -36
- data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
- data/lib/cmdx/utils/name_affix.rb +0 -52
- data/lib/cmdx/validator.rb +0 -57
- data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
- data/lib/generators/cmdx/workflow_generator.rb +0 -84
- data/lib/locales/ar.yml +0 -35
- data/lib/locales/cs.yml +0 -35
- data/lib/locales/da.yml +0 -35
- data/lib/locales/de.yml +0 -35
- data/lib/locales/el.yml +0 -35
- data/lib/locales/es.yml +0 -35
- data/lib/locales/fi.yml +0 -35
- data/lib/locales/fr.yml +0 -35
- data/lib/locales/he.yml +0 -35
- data/lib/locales/hi.yml +0 -35
- data/lib/locales/it.yml +0 -35
- data/lib/locales/ja.yml +0 -35
- data/lib/locales/ko.yml +0 -35
- data/lib/locales/nl.yml +0 -35
- data/lib/locales/no.yml +0 -35
- data/lib/locales/pl.yml +0 -35
- data/lib/locales/pt.yml +0 -35
- data/lib/locales/ru.yml +0 -35
- data/lib/locales/sv.yml +0 -35
- data/lib/locales/th.yml +0 -35
- data/lib/locales/tr.yml +0 -35
- data/lib/locales/vi.yml +0 -35
- data/lib/locales/zh.yml +0 -35
data/lib/cmdx/task_processor.rb
DELETED
@@ -1,246 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Core task execution processor handling the complete task lifecycle.
|
5
|
-
#
|
6
|
-
# TaskProcessor manages the execution pipeline for individual tasks, coordinating
|
7
|
-
# parameter validation, callback invocation, error handling, and result state
|
8
|
-
# management. It provides both safe execution (capturing exceptions) and unsafe
|
9
|
-
# execution (re-raising exceptions) modes through call and call! methods respectively.
|
10
|
-
# The processor ensures proper state transitions, handles fault propagation, and
|
11
|
-
# maintains execution context throughout the task lifecycle.
|
12
|
-
class TaskProcessor
|
13
|
-
|
14
|
-
# @return [CMDx::Task] The task instance being executed
|
15
|
-
attr_reader :task
|
16
|
-
|
17
|
-
# Creates a new task processor for the specified task instance.
|
18
|
-
#
|
19
|
-
# @param task [CMDx::Task] the task instance to process
|
20
|
-
#
|
21
|
-
# @return [TaskProcessor] a new processor instance for the task
|
22
|
-
#
|
23
|
-
# @example Create a processor for a task
|
24
|
-
# task = MyTask.new(user_id: 123)
|
25
|
-
# processor = TaskProcessor.new(task)
|
26
|
-
def initialize(task)
|
27
|
-
@task = task
|
28
|
-
end
|
29
|
-
|
30
|
-
class << self
|
31
|
-
|
32
|
-
# Executes the specified task and returns the result without raising exceptions.
|
33
|
-
#
|
34
|
-
# Creates a new processor instance and executes the task through the complete
|
35
|
-
# lifecycle including validation, callbacks, and error handling. Exceptions
|
36
|
-
# are captured in the result rather than being raised to the caller.
|
37
|
-
#
|
38
|
-
# @param task [CMDx::Task] the task instance to execute
|
39
|
-
#
|
40
|
-
# @return [CMDx::Result] the execution result containing state and status information
|
41
|
-
#
|
42
|
-
# @example Execute a task safely
|
43
|
-
# task = ProcessDataTask.new(data: raw_data)
|
44
|
-
# result = TaskProcessor.call(task)
|
45
|
-
# puts result.status #=> "success", "failed", or "skipped"
|
46
|
-
def call(task)
|
47
|
-
new(task).call
|
48
|
-
end
|
49
|
-
|
50
|
-
# Executes the specified task and raises exceptions on failure.
|
51
|
-
#
|
52
|
-
# Creates a new processor instance and executes the task through the complete
|
53
|
-
# lifecycle. Unlike call, this method will re-raise exceptions including
|
54
|
-
# Fault exceptions when their status matches the task's halt configuration.
|
55
|
-
#
|
56
|
-
# @param task [CMDx::Task] the task instance to execute
|
57
|
-
#
|
58
|
-
# @return [CMDx::Result] the execution result on success
|
59
|
-
#
|
60
|
-
# @raise [CMDx::Fault] when a fault occurs with status matching task halt configuration
|
61
|
-
# @raise [StandardError] when unexpected errors occur during execution
|
62
|
-
#
|
63
|
-
# @example Execute a task with exception raising
|
64
|
-
# task = CriticalTask.new(operation: "delete")
|
65
|
-
# begin
|
66
|
-
# result = TaskProcessor.call!(task)
|
67
|
-
# puts "Success: #{result.status}"
|
68
|
-
# rescue CMDx::Fault => e
|
69
|
-
# puts "Task failed: #{e.message}"
|
70
|
-
# end
|
71
|
-
def call!(task)
|
72
|
-
new(task).call!
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
# Executes the task with safe error handling and returns the result.
|
78
|
-
#
|
79
|
-
# Runs the complete task execution pipeline including parameter validation,
|
80
|
-
# callback invocation, and the task's call method. Captures all exceptions
|
81
|
-
# as result status rather than raising them, ensuring the chain continues
|
82
|
-
# execution. Handles both standard errors and Fault exceptions according
|
83
|
-
# to the task's halt configuration.
|
84
|
-
#
|
85
|
-
# @return [CMDx::Result] the execution result with captured state and status
|
86
|
-
#
|
87
|
-
# @example Safe task execution
|
88
|
-
# processor = TaskProcessor.new(task)
|
89
|
-
# result = processor.call
|
90
|
-
# if result.success?
|
91
|
-
# puts "Task completed successfully"
|
92
|
-
# else
|
93
|
-
# puts "Task failed: #{result.metadata[:reason]}"
|
94
|
-
# end
|
95
|
-
def call
|
96
|
-
task.result.runtime do
|
97
|
-
before_call
|
98
|
-
validate_parameters
|
99
|
-
task.call
|
100
|
-
rescue UndefinedCallError => e
|
101
|
-
raise(e)
|
102
|
-
rescue Fault => e
|
103
|
-
if Array(task.cmd_setting(:task_halt)).include?(e.result.status)
|
104
|
-
# No need to clear the Chain since exception is not being re-raised
|
105
|
-
task.result.throw!(e.result, original_exception: e)
|
106
|
-
end
|
107
|
-
rescue StandardError => e
|
108
|
-
task.result.fail!(reason: "[#{e.class}] #{e.message}", original_exception: e)
|
109
|
-
ensure
|
110
|
-
task.result.executed!
|
111
|
-
after_call
|
112
|
-
end
|
113
|
-
|
114
|
-
terminate_call
|
115
|
-
end
|
116
|
-
|
117
|
-
# Executes the task with exception raising on halt conditions.
|
118
|
-
#
|
119
|
-
# Runs the complete task execution pipeline including parameter validation,
|
120
|
-
# callback invocation, and the task's call method. Unlike call, this method
|
121
|
-
# will re-raise Fault exceptions when their status matches the task's halt
|
122
|
-
# configuration, and clears the execution chain before raising.
|
123
|
-
#
|
124
|
-
# @return [CMDx::Result] the execution result on successful completion
|
125
|
-
#
|
126
|
-
# @raise [CMDx::Fault] when a fault occurs with status matching task halt configuration
|
127
|
-
# @raise [CMDx::UndefinedCallError] when the task's call method is not implemented
|
128
|
-
# @raise [StandardError] when unexpected errors occur during execution
|
129
|
-
#
|
130
|
-
# @example Task execution with exception raising
|
131
|
-
# processor = TaskProcessor.new(critical_task)
|
132
|
-
# begin
|
133
|
-
# result = processor.call!
|
134
|
-
# puts "Task succeeded"
|
135
|
-
# rescue CMDx::Fault => e
|
136
|
-
# puts "Critical failure: #{e.message}"
|
137
|
-
# # Chain is cleared, execution stops
|
138
|
-
# end
|
139
|
-
def call!
|
140
|
-
task.result.runtime do
|
141
|
-
before_call
|
142
|
-
validate_parameters
|
143
|
-
task.call
|
144
|
-
rescue UndefinedCallError => e
|
145
|
-
raise!(e)
|
146
|
-
rescue Fault => e
|
147
|
-
task.result.executed!
|
148
|
-
|
149
|
-
raise!(e) if Array(task.cmd_setting(:task_halt)).include?(e.result.status)
|
150
|
-
|
151
|
-
after_call # HACK: treat as NO-OP
|
152
|
-
else
|
153
|
-
task.result.executed!
|
154
|
-
after_call # ELSE: treat as success
|
155
|
-
end
|
156
|
-
|
157
|
-
terminate_call
|
158
|
-
end
|
159
|
-
|
160
|
-
private
|
161
|
-
|
162
|
-
# Executes pre-execution callbacks and sets the task to executing state.
|
163
|
-
#
|
164
|
-
# Invokes before_execution callbacks, transitions the result to executing
|
165
|
-
# state, and triggers on_executing callbacks. This method prepares the
|
166
|
-
# task for execution and notifies registered callbacks about the state change.
|
167
|
-
#
|
168
|
-
# @return [void]
|
169
|
-
def before_call
|
170
|
-
task.cmd_callbacks.call(task, :before_execution)
|
171
|
-
|
172
|
-
task.result.executing!
|
173
|
-
task.cmd_callbacks.call(task, :on_executing)
|
174
|
-
end
|
175
|
-
|
176
|
-
# Validates task parameters and handles validation failures.
|
177
|
-
#
|
178
|
-
# Executes parameter validation callbacks, validates all task parameters
|
179
|
-
# against their defined rules, and sets the task result to failed if
|
180
|
-
# validation errors are found. Collects all validation messages into
|
181
|
-
# the result metadata.
|
182
|
-
#
|
183
|
-
# @return [void]
|
184
|
-
def validate_parameters
|
185
|
-
task.cmd_callbacks.call(task, :before_validation)
|
186
|
-
|
187
|
-
task.cmd_parameters.validate!(task)
|
188
|
-
unless task.errors.empty?
|
189
|
-
task.result.fail!(
|
190
|
-
reason: task.errors.full_messages.join(". "),
|
191
|
-
messages: task.errors.messages
|
192
|
-
)
|
193
|
-
end
|
194
|
-
|
195
|
-
task.cmd_callbacks.call(task, :after_validation)
|
196
|
-
end
|
197
|
-
|
198
|
-
# Clears the execution chain and raises the specified exception.
|
199
|
-
#
|
200
|
-
# This method is used to clean up the execution context before
|
201
|
-
# re-raising exceptions, ensuring that the chain state is properly
|
202
|
-
# reset when execution cannot continue.
|
203
|
-
#
|
204
|
-
# @param exception [Exception] the exception to raise after clearing the chain
|
205
|
-
#
|
206
|
-
# @return [void]
|
207
|
-
#
|
208
|
-
# @raise [Exception] the provided exception after chain cleanup
|
209
|
-
def raise!(exception)
|
210
|
-
Chain.clear
|
211
|
-
raise(exception)
|
212
|
-
end
|
213
|
-
|
214
|
-
# Executes post-execution callbacks based on task result state and status.
|
215
|
-
#
|
216
|
-
# Invokes appropriate callbacks based on the task's final execution state
|
217
|
-
# (success, failure, etc.) and status. Handles both state-specific and
|
218
|
-
# status-specific callback invocation, as well as general execution
|
219
|
-
# completion callbacks.
|
220
|
-
#
|
221
|
-
# @return [void]
|
222
|
-
def after_call
|
223
|
-
task.cmd_callbacks.call(task, :"on_#{task.result.state}")
|
224
|
-
task.cmd_callbacks.call(task, :on_executed) if task.result.executed?
|
225
|
-
|
226
|
-
task.cmd_callbacks.call(task, :"on_#{task.result.status}")
|
227
|
-
task.cmd_callbacks.call(task, :on_good) if task.result.good?
|
228
|
-
task.cmd_callbacks.call(task, :on_bad) if task.result.bad?
|
229
|
-
|
230
|
-
task.cmd_callbacks.call(task, :after_execution)
|
231
|
-
end
|
232
|
-
|
233
|
-
# Finalizes task execution by freezing state and logging results.
|
234
|
-
#
|
235
|
-
# Applies immutability to the task instance and logs the execution
|
236
|
-
# result. This method ensures that the task state cannot be modified
|
237
|
-
# after execution and provides visibility into the execution outcome.
|
238
|
-
#
|
239
|
-
# @return [void]
|
240
|
-
def terminate_call
|
241
|
-
Immutator.call(task)
|
242
|
-
ResultLogger.call(task.result)
|
243
|
-
end
|
244
|
-
|
245
|
-
end
|
246
|
-
end
|
data/lib/cmdx/task_serializer.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Task serialization module for converting task objects to hash format.
|
5
|
-
#
|
6
|
-
# TaskSerializer provides functionality to serialize task objects into a
|
7
|
-
# standardized hash representation that includes essential metadata about
|
8
|
-
# the task such as its index, chain ID, type, class, ID, and tags. The
|
9
|
-
# serialized format is commonly used for debugging, logging, and introspection
|
10
|
-
# purposes throughout the task execution pipeline.
|
11
|
-
module TaskSerializer
|
12
|
-
|
13
|
-
module_function
|
14
|
-
|
15
|
-
# Serializes a task object into a hash representation.
|
16
|
-
#
|
17
|
-
# Converts a task instance into a standardized hash format containing
|
18
|
-
# key metadata about the task's execution context and classification.
|
19
|
-
# The serialization includes information from the task's result, chain,
|
20
|
-
# and command settings to provide comprehensive task identification.
|
21
|
-
#
|
22
|
-
# @param task [CMDx::Task, CMDx::Workflow] the task or workflow object to serialize
|
23
|
-
#
|
24
|
-
# @return [Hash] a hash containing the task's metadata
|
25
|
-
# @option return [Integer] :index the task's position index in the execution chain
|
26
|
-
# @option return [String] :chain_id the unique identifier of the task's execution chain
|
27
|
-
# @option return [String] :type the task type, either "Task" or "Workflow"
|
28
|
-
# @option return [String] :class the full class name of the task
|
29
|
-
# @option return [String] :id the unique identifier of the task instance
|
30
|
-
# @option return [Array] :tags the tags associated with the task from cmd settings
|
31
|
-
#
|
32
|
-
# @raise [NoMethodError] if the task doesn't respond to required methods
|
33
|
-
#
|
34
|
-
# @example Serialize a basic task
|
35
|
-
# task = ProcessDataTask.new
|
36
|
-
# TaskSerializer.call(task)
|
37
|
-
# #=> {
|
38
|
-
# # index: 0,
|
39
|
-
# # chain_id: "abc123",
|
40
|
-
# # type: "Task",
|
41
|
-
# # class: "ProcessDataTask",
|
42
|
-
# # id: "def456",
|
43
|
-
# # tags: []
|
44
|
-
# # }
|
45
|
-
def call(task)
|
46
|
-
{
|
47
|
-
index: task.result.index,
|
48
|
-
chain_id: task.chain.id,
|
49
|
-
type: task.is_a?(Workflow) ? "Workflow" : "Task",
|
50
|
-
class: task.class.name,
|
51
|
-
id: task.id,
|
52
|
-
tags: task.cmd_setting(:tags)
|
53
|
-
}
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module Utils
|
5
|
-
# Utility module for applying ANSI color and formatting codes to text.
|
6
|
-
#
|
7
|
-
# This module provides functionality to colorize and format text output
|
8
|
-
# using ANSI escape sequences, supporting various colors and text modes.
|
9
|
-
module AnsiColor
|
10
|
-
|
11
|
-
COLOR_CODES = {
|
12
|
-
black: 30,
|
13
|
-
red: 31,
|
14
|
-
green: 32,
|
15
|
-
yellow: 33,
|
16
|
-
blue: 34,
|
17
|
-
magenta: 35,
|
18
|
-
cyan: 36,
|
19
|
-
white: 37,
|
20
|
-
default: 39,
|
21
|
-
light_black: 90,
|
22
|
-
light_red: 91,
|
23
|
-
light_green: 92,
|
24
|
-
light_yellow: 93,
|
25
|
-
light_blue: 94,
|
26
|
-
light_magenta: 95,
|
27
|
-
light_cyan: 96,
|
28
|
-
light_white: 97
|
29
|
-
}.freeze
|
30
|
-
MODE_CODES = {
|
31
|
-
default: 0,
|
32
|
-
bold: 1,
|
33
|
-
dim: 2,
|
34
|
-
italic: 3,
|
35
|
-
underline: 4,
|
36
|
-
blink: 5,
|
37
|
-
blink_slow: 5,
|
38
|
-
blink_fast: 6,
|
39
|
-
invert: 7,
|
40
|
-
hide: 8,
|
41
|
-
strike: 9,
|
42
|
-
double_underline: 20,
|
43
|
-
reveal: 28,
|
44
|
-
overlined: 53
|
45
|
-
}.freeze
|
46
|
-
|
47
|
-
module_function
|
48
|
-
|
49
|
-
# Applies ANSI color and formatting to the given text value.
|
50
|
-
#
|
51
|
-
# @param value [String] the text to format with ANSI codes
|
52
|
-
# @param color [Symbol] the color to apply (must be a key in COLOR_CODES)
|
53
|
-
# @param mode [Symbol] the formatting mode to apply (must be a key in MODE_CODES)
|
54
|
-
#
|
55
|
-
# @return [String] the formatted text with ANSI escape sequences
|
56
|
-
#
|
57
|
-
# @raise [KeyError] if the specified color or mode is not found in the respective code maps
|
58
|
-
#
|
59
|
-
# @example Basic color application
|
60
|
-
# AnsiColor.call("Hello", color: :red) #=> "\e[0;31;49mHello\e[0m"
|
61
|
-
#
|
62
|
-
# @example Color with formatting mode
|
63
|
-
# AnsiColor.call("Warning", color: :yellow, mode: :bold) #=> "\e[1;33;49mWarning\e[0m"
|
64
|
-
def call(value, color:, mode: :default)
|
65
|
-
color_code = COLOR_CODES.fetch(color)
|
66
|
-
mode_code = MODE_CODES.fetch(mode)
|
67
|
-
|
68
|
-
"\e[#{mode_code};#{color_code};49m#{value}\e[0m"
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module Utils
|
5
|
-
# Utility module for formatting timestamps into standardized string representations.
|
6
|
-
#
|
7
|
-
# This module provides functionality to convert Time objects into consistent
|
8
|
-
# ISO 8601-like formatted strings with microsecond precision, suitable for
|
9
|
-
# logging and timestamp display purposes.
|
10
|
-
module LogTimestamp
|
11
|
-
|
12
|
-
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%6N"
|
13
|
-
|
14
|
-
module_function
|
15
|
-
|
16
|
-
# Formats a Time object into a standardized timestamp string.
|
17
|
-
#
|
18
|
-
# @param time [Time] the time object to format
|
19
|
-
#
|
20
|
-
# @return [String] the formatted timestamp string in ISO 8601-like format
|
21
|
-
#
|
22
|
-
# @raise [NoMethodError] if the time object doesn't respond to strftime
|
23
|
-
#
|
24
|
-
# @example Basic timestamp formatting
|
25
|
-
# LogTimestamp.call(Time.now) #=> "2023-12-25T10:30:45.123456"
|
26
|
-
#
|
27
|
-
# @example With specific time
|
28
|
-
# time = Time.new(2023, 12, 25, 10, 30, 45, 123456)
|
29
|
-
# LogTimestamp.call(time) #=> "2023-12-25T10:30:45.123456"
|
30
|
-
def call(time)
|
31
|
-
time.strftime(DATETIME_FORMAT)
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module Utils
|
5
|
-
# Utility module for measuring execution time using monotonic clock.
|
6
|
-
#
|
7
|
-
# This module provides functionality to measure the time taken to execute
|
8
|
-
# a block of code using the monotonic clock, which is not affected by
|
9
|
-
# system clock adjustments and provides more accurate timing measurements.
|
10
|
-
module MonotonicRuntime
|
11
|
-
|
12
|
-
module_function
|
13
|
-
|
14
|
-
# Measures the execution time of a given block using monotonic clock.
|
15
|
-
#
|
16
|
-
# @param block [Proc] the block of code to measure execution time for
|
17
|
-
# @yield executes the provided block while measuring its runtime
|
18
|
-
#
|
19
|
-
# @return [Integer] the execution time in milliseconds
|
20
|
-
#
|
21
|
-
# @example Basic usage
|
22
|
-
# MonotonicRuntime.call { sleep(0.1) } #=> 100 (approximately)
|
23
|
-
#
|
24
|
-
# @example Measuring database query time
|
25
|
-
# MonotonicRuntime.call { User.find(1) } #=> 15 (milliseconds)
|
26
|
-
def call(&)
|
27
|
-
now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
28
|
-
yield
|
29
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - now
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module Utils
|
5
|
-
# Utility module for generating method names with configurable prefixes and suffixes.
|
6
|
-
#
|
7
|
-
# This module provides functionality to dynamically construct method names
|
8
|
-
# by applying prefixes and suffixes to a base method name, with support
|
9
|
-
# for custom naming through options.
|
10
|
-
module NameAffix
|
11
|
-
|
12
|
-
# Proc that handles affix logic - returns block result if value is true, otherwise returns value as-is.
|
13
|
-
AFFIX = proc do |o, &block|
|
14
|
-
o == true ? block.call : o
|
15
|
-
end.freeze
|
16
|
-
|
17
|
-
module_function
|
18
|
-
|
19
|
-
# Generates a method name with optional prefix and suffix based on source and options.
|
20
|
-
#
|
21
|
-
# @param method_name [String, Symbol] the base method name to be affixed
|
22
|
-
# @param source [String, Symbol] the source identifier used for generating default prefixes/suffixes
|
23
|
-
# @param options [Hash] configuration options for name generation
|
24
|
-
# @option options [String, Symbol, true] :prefix custom prefix or true for default "#{source}_"
|
25
|
-
# @option options [String, Symbol, true] :suffix custom suffix or true for default "_#{source}"
|
26
|
-
# @option options [String, Symbol] :as override the entire generated name
|
27
|
-
#
|
28
|
-
# @return [Symbol] the generated method name as a symbol
|
29
|
-
#
|
30
|
-
# @example Using default prefix and suffix
|
31
|
-
# NameAffix.call("process", "user", prefix: true, suffix: true) #=> :user_process_user
|
32
|
-
#
|
33
|
-
# @example Using custom prefix
|
34
|
-
# NameAffix.call("process", "user", prefix: "handle_") #=> :handle_process
|
35
|
-
#
|
36
|
-
# @example Using custom suffix
|
37
|
-
# NameAffix.call("process", "user", suffix: "_data") #=> :process_data
|
38
|
-
#
|
39
|
-
# @example Overriding with custom name
|
40
|
-
# NameAffix.call("process", "user", as: "custom_method") #=> :custom_method
|
41
|
-
def call(method_name, source, options = {})
|
42
|
-
options[:as] || begin
|
43
|
-
prefix = AFFIX.call(options[:prefix]) { "#{source}_" }
|
44
|
-
suffix = AFFIX.call(options[:suffix]) { "_#{source}" }
|
45
|
-
|
46
|
-
"#{prefix}#{method_name}#{suffix}".strip.to_sym
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/cmdx/validator.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Base class for implementing parameter validation functionality in task processing.
|
5
|
-
#
|
6
|
-
# Validators are used to validate parameter values against specific rules and constraints,
|
7
|
-
# supporting both built-in validation types and custom validation logic. All validator
|
8
|
-
# implementations must inherit from this class and implement the abstract call method.
|
9
|
-
class Validator
|
10
|
-
|
11
|
-
# Executes a validator by creating a new instance and calling it.
|
12
|
-
#
|
13
|
-
# @param value [Object] the value to be validated
|
14
|
-
# @param options [Hash] additional options for the validation
|
15
|
-
#
|
16
|
-
# @return [Object] the validated value if validation passes
|
17
|
-
#
|
18
|
-
# @raise [UndefinedCallError] when the validator subclass doesn't implement call
|
19
|
-
# @raise [ValidationError] when validation fails
|
20
|
-
#
|
21
|
-
# @example Execute a validator on a value
|
22
|
-
# PresenceValidator.call("some_value") #=> "some_value"
|
23
|
-
#
|
24
|
-
# @example Execute with options
|
25
|
-
# NumericValidator.call(42, greater_than: 10) #=> 42
|
26
|
-
def self.call(value, options = {})
|
27
|
-
new.call(value, options)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Abstract method that must be implemented by validator subclasses.
|
31
|
-
#
|
32
|
-
# This method contains the actual validation logic to verify the input
|
33
|
-
# value meets the specified criteria. Subclasses must override this method
|
34
|
-
# to provide their specific validation implementation.
|
35
|
-
#
|
36
|
-
# @param value [Object] the value to be validated
|
37
|
-
# @param options [Hash] additional options for the validation
|
38
|
-
#
|
39
|
-
# @return [Object] the validated value if validation passes
|
40
|
-
#
|
41
|
-
# @raise [UndefinedCallError] always raised in the base class
|
42
|
-
# @raise [ValidationError] when validation fails in subclass implementations
|
43
|
-
#
|
44
|
-
# @example Implement in a subclass
|
45
|
-
# class BlankValidator < CMDx::Validator
|
46
|
-
# def call(value, options = {})
|
47
|
-
# if value.nil? || value.empty?
|
48
|
-
# raise ValidationError, options[:message] || "Value cannot be blank"
|
49
|
-
# end
|
50
|
-
# end
|
51
|
-
# end
|
52
|
-
def call(value, options = {}) # rubocop:disable Lint/UnusedMethodArgument
|
53
|
-
raise UndefinedCallError, "call method not defined in #{self.class.name}"
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Cmdx
|
4
|
-
# Rails generator for creating CMDx workflow files.
|
5
|
-
#
|
6
|
-
# This generator creates workflow files in the app/cmds directory with proper
|
7
|
-
# class naming conventions and inheritance. It ensures workflow names end with
|
8
|
-
# "Workflow" suffix and creates files in the correct location within the Rails
|
9
|
-
# application structure.
|
10
|
-
class WorkflowGenerator < Rails::Generators::NamedBase
|
11
|
-
|
12
|
-
source_root File.expand_path("templates", __dir__)
|
13
|
-
check_class_collision suffix: "Workflow"
|
14
|
-
|
15
|
-
desc "Creates a workflow with the given NAME"
|
16
|
-
|
17
|
-
# Creates the workflow file from the template.
|
18
|
-
#
|
19
|
-
# Generates a new workflow file in the app/cmds directory based on the provided
|
20
|
-
# name. The file name is normalized to ensure it ends with "_workflow.rb" and
|
21
|
-
# is placed in the appropriate subdirectory structure.
|
22
|
-
#
|
23
|
-
# @return [void]
|
24
|
-
#
|
25
|
-
# @raise [Thor::Error] if the destination file cannot be created or already exists without force
|
26
|
-
#
|
27
|
-
# @example Generate a user workflow
|
28
|
-
# rails generate cmdx:workflow user
|
29
|
-
# #=> Creates app/cmds/user_workflow.rb
|
30
|
-
#
|
31
|
-
# @example Generate a nested workflow
|
32
|
-
# rails generate cmdx:workflow admin/users
|
33
|
-
# #=> Creates app/cmds/admin/users_workflow.rb
|
34
|
-
def copy_files
|
35
|
-
name = file_name.sub(/_?workflow$/i, "")
|
36
|
-
path = File.join("app/cmds", class_path, "#{name}_workflow.rb")
|
37
|
-
template("workflow.rb.tt", path)
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
# Ensures the class name ends with "Workflow" suffix.
|
43
|
-
#
|
44
|
-
# Takes the provided class name and appends "Workflow" if it doesn't already
|
45
|
-
# end with that suffix, ensuring consistent naming conventions across
|
46
|
-
# all generated workflow classes.
|
47
|
-
#
|
48
|
-
# @return [String] the class name with "Workflow" suffix
|
49
|
-
#
|
50
|
-
# @example Class name without suffix
|
51
|
-
# # Given name: "User"
|
52
|
-
# class_name #=> "UserWorkflow"
|
53
|
-
#
|
54
|
-
# @example Class name with suffix
|
55
|
-
# # Given name: "UserWorkflow"
|
56
|
-
# class_name #=> "UserWorkflow"
|
57
|
-
def class_name
|
58
|
-
@class_name ||= super.end_with?("Workflow") ? super : "#{super}Workflow"
|
59
|
-
end
|
60
|
-
|
61
|
-
# Determines the parent class for the generated workflow.
|
62
|
-
#
|
63
|
-
# Attempts to use ApplicationWorkflow as the parent class if it exists in the
|
64
|
-
# application, otherwise falls back to CMDx::Workflow as the base class.
|
65
|
-
# This allows applications to define their own base workflow class with
|
66
|
-
# common functionality.
|
67
|
-
#
|
68
|
-
# @return [Class] the parent class for the generated workflow
|
69
|
-
#
|
70
|
-
# @raise [StandardError] if neither ApplicationWorkflow nor CMDx::Workflow are available
|
71
|
-
#
|
72
|
-
# @example With ApplicationWorkflow defined
|
73
|
-
# parent_class_name #=> ApplicationWorkflow
|
74
|
-
#
|
75
|
-
# @example Without ApplicationWorkflow
|
76
|
-
# parent_class_name #=> CMDx::Workflow
|
77
|
-
def parent_class_name
|
78
|
-
ApplicationWorkflow
|
79
|
-
rescue StandardError
|
80
|
-
CMDx::Workflow
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
end
|
data/lib/locales/ar.yml
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
ar:
|
2
|
-
cmdx:
|
3
|
-
coercions:
|
4
|
-
into_a: "لا يمكن تحويل إلى %{type}"
|
5
|
-
into_an: "لا يمكن تحويل إلى %{type}"
|
6
|
-
into_any: "لا يمكن تحويل إلى أي من: %{values}"
|
7
|
-
unknown: "نوع التحويل %{type} غير معروف"
|
8
|
-
faults:
|
9
|
-
unspecified: "لم يتم تحديد سبب"
|
10
|
-
parameters:
|
11
|
-
required: "معامل مطلوب"
|
12
|
-
undefined: "يفوض لطريقة غير معرفة %{source}"
|
13
|
-
validators:
|
14
|
-
exclusion:
|
15
|
-
of: "يجب ألا يكون أحد: %{values}"
|
16
|
-
within: "يجب ألا يكون بين %{min} و %{max}"
|
17
|
-
format: "له تنسيق غير صالح"
|
18
|
-
inclusion:
|
19
|
-
of: "يجب أن يكون أحد: %{values}"
|
20
|
-
within: "يجب أن يكون بين %{min} و %{max}"
|
21
|
-
length:
|
22
|
-
is: "يجب أن يكون الطول %{is}"
|
23
|
-
is_not: "يجب ألا يكون الطول %{is_not}"
|
24
|
-
min: "يجب أن يكون الطول على الأقل %{min}"
|
25
|
-
max: "يجب أن يكون الطول على الأكثر %{max}"
|
26
|
-
not_within: "يجب ألا يكون الطول بين %{min} و %{max}"
|
27
|
-
within: "يجب أن يكون الطول بين %{min} و %{max}"
|
28
|
-
numeric:
|
29
|
-
is: "يجب أن يكون %{is}"
|
30
|
-
is_not: "يجب ألا يكون %{is_not}"
|
31
|
-
min: "يجب أن يكون على الأقل %{min}"
|
32
|
-
max: "يجب أن يكون على الأكثر %{max}"
|
33
|
-
not_within: "يجب ألا يكون بين %{min} و %{max}"
|
34
|
-
within: "يجب أن يكون بين %{min} و %{max}"
|
35
|
-
presence: "لا يمكن أن يكون فارغاً"
|