cmdx 1.1.2 → 1.5.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 (192) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +4 -1
  4. data/.cursor/prompts/llms.md +20 -0
  5. data/.cursor/prompts/rspec.md +4 -1
  6. data/.cursor/prompts/yardoc.md +3 -2
  7. data/.cursor/rules/cursor-instructions.mdc +55 -1
  8. data/.irbrc +6 -0
  9. data/.rubocop.yml +29 -18
  10. data/CHANGELOG.md +11 -132
  11. data/LLM.md +3317 -0
  12. data/README.md +68 -44
  13. data/docs/attributes/coercions.md +162 -0
  14. data/docs/attributes/defaults.md +90 -0
  15. data/docs/attributes/definitions.md +281 -0
  16. data/docs/attributes/naming.md +78 -0
  17. data/docs/attributes/validations.md +309 -0
  18. data/docs/basics/chain.md +56 -249
  19. data/docs/basics/context.md +56 -289
  20. data/docs/basics/execution.md +114 -0
  21. data/docs/basics/setup.md +37 -334
  22. data/docs/callbacks.md +89 -467
  23. data/docs/deprecation.md +91 -174
  24. data/docs/getting_started.md +212 -202
  25. data/docs/internationalization.md +11 -647
  26. data/docs/interruptions/exceptions.md +23 -198
  27. data/docs/interruptions/faults.md +71 -151
  28. data/docs/interruptions/halt.md +109 -186
  29. data/docs/logging.md +44 -256
  30. data/docs/middlewares.md +113 -426
  31. data/docs/outcomes/result.md +81 -228
  32. data/docs/outcomes/states.md +33 -221
  33. data/docs/outcomes/statuses.md +21 -311
  34. data/docs/tips_and_tricks.md +120 -70
  35. data/docs/workflows.md +99 -283
  36. data/lib/cmdx/.DS_Store +0 -0
  37. data/lib/cmdx/attribute.rb +229 -0
  38. data/lib/cmdx/attribute_registry.rb +94 -0
  39. data/lib/cmdx/attribute_value.rb +193 -0
  40. data/lib/cmdx/callback_registry.rb +69 -77
  41. data/lib/cmdx/chain.rb +56 -73
  42. data/lib/cmdx/coercion_registry.rb +52 -68
  43. data/lib/cmdx/coercions/array.rb +19 -18
  44. data/lib/cmdx/coercions/big_decimal.rb +20 -24
  45. data/lib/cmdx/coercions/boolean.rb +26 -25
  46. data/lib/cmdx/coercions/complex.rb +21 -22
  47. data/lib/cmdx/coercions/date.rb +25 -23
  48. data/lib/cmdx/coercions/date_time.rb +24 -25
  49. data/lib/cmdx/coercions/float.rb +25 -22
  50. data/lib/cmdx/coercions/hash.rb +31 -32
  51. data/lib/cmdx/coercions/integer.rb +30 -24
  52. data/lib/cmdx/coercions/rational.rb +29 -24
  53. data/lib/cmdx/coercions/string.rb +19 -22
  54. data/lib/cmdx/coercions/symbol.rb +37 -0
  55. data/lib/cmdx/coercions/time.rb +26 -25
  56. data/lib/cmdx/configuration.rb +49 -108
  57. data/lib/cmdx/context.rb +222 -44
  58. data/lib/cmdx/deprecator.rb +61 -0
  59. data/lib/cmdx/errors.rb +42 -252
  60. data/lib/cmdx/exceptions.rb +39 -0
  61. data/lib/cmdx/faults.rb +78 -39
  62. data/lib/cmdx/freezer.rb +51 -0
  63. data/lib/cmdx/identifier.rb +30 -0
  64. data/lib/cmdx/locale.rb +52 -0
  65. data/lib/cmdx/log_formatters/json.rb +21 -22
  66. data/lib/cmdx/log_formatters/key_value.rb +20 -22
  67. data/lib/cmdx/log_formatters/line.rb +15 -22
  68. data/lib/cmdx/log_formatters/logstash.rb +22 -23
  69. data/lib/cmdx/log_formatters/raw.rb +16 -22
  70. data/lib/cmdx/middleware_registry.rb +70 -74
  71. data/lib/cmdx/middlewares/correlate.rb +90 -54
  72. data/lib/cmdx/middlewares/runtime.rb +58 -0
  73. data/lib/cmdx/middlewares/timeout.rb +48 -68
  74. data/lib/cmdx/railtie.rb +12 -45
  75. data/lib/cmdx/result.rb +229 -314
  76. data/lib/cmdx/task.rb +194 -366
  77. data/lib/cmdx/utils/call.rb +49 -0
  78. data/lib/cmdx/utils/condition.rb +71 -0
  79. data/lib/cmdx/utils/format.rb +61 -0
  80. data/lib/cmdx/validator_registry.rb +63 -72
  81. data/lib/cmdx/validators/exclusion.rb +38 -67
  82. data/lib/cmdx/validators/format.rb +48 -49
  83. data/lib/cmdx/validators/inclusion.rb +43 -74
  84. data/lib/cmdx/validators/length.rb +101 -162
  85. data/lib/cmdx/validators/numeric.rb +95 -170
  86. data/lib/cmdx/validators/presence.rb +37 -50
  87. data/lib/cmdx/version.rb +1 -1
  88. data/lib/cmdx/worker.rb +178 -0
  89. data/lib/cmdx/workflow.rb +85 -81
  90. data/lib/cmdx.rb +19 -13
  91. data/lib/generators/cmdx/install_generator.rb +14 -13
  92. data/lib/generators/cmdx/task_generator.rb +25 -50
  93. data/lib/generators/cmdx/templates/install.rb +11 -46
  94. data/lib/generators/cmdx/templates/task.rb.tt +3 -2
  95. data/lib/locales/en.yml +18 -4
  96. data/src/cmdx-logo.png +0 -0
  97. metadata +32 -116
  98. data/docs/ai_prompts.md +0 -393
  99. data/docs/basics/call.md +0 -317
  100. data/docs/configuration.md +0 -344
  101. data/docs/parameters/coercions.md +0 -396
  102. data/docs/parameters/defaults.md +0 -335
  103. data/docs/parameters/definitions.md +0 -446
  104. data/docs/parameters/namespacing.md +0 -378
  105. data/docs/parameters/validations.md +0 -405
  106. data/docs/testing.md +0 -553
  107. data/lib/cmdx/callback.rb +0 -53
  108. data/lib/cmdx/chain_inspector.rb +0 -56
  109. data/lib/cmdx/chain_serializer.rb +0 -63
  110. data/lib/cmdx/coercion.rb +0 -57
  111. data/lib/cmdx/coercions/virtual.rb +0 -29
  112. data/lib/cmdx/core_ext/hash.rb +0 -83
  113. data/lib/cmdx/core_ext/module.rb +0 -98
  114. data/lib/cmdx/core_ext/object.rb +0 -125
  115. data/lib/cmdx/correlator.rb +0 -122
  116. data/lib/cmdx/error.rb +0 -67
  117. data/lib/cmdx/fault.rb +0 -140
  118. data/lib/cmdx/immutator.rb +0 -52
  119. data/lib/cmdx/lazy_struct.rb +0 -246
  120. data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
  121. data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
  122. data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
  123. data/lib/cmdx/logger.rb +0 -49
  124. data/lib/cmdx/logger_ansi.rb +0 -68
  125. data/lib/cmdx/logger_serializer.rb +0 -116
  126. data/lib/cmdx/middleware.rb +0 -70
  127. data/lib/cmdx/parameter.rb +0 -312
  128. data/lib/cmdx/parameter_evaluator.rb +0 -231
  129. data/lib/cmdx/parameter_inspector.rb +0 -66
  130. data/lib/cmdx/parameter_registry.rb +0 -106
  131. data/lib/cmdx/parameter_serializer.rb +0 -59
  132. data/lib/cmdx/result_ansi.rb +0 -71
  133. data/lib/cmdx/result_inspector.rb +0 -71
  134. data/lib/cmdx/result_logger.rb +0 -59
  135. data/lib/cmdx/result_serializer.rb +0 -104
  136. data/lib/cmdx/rspec/matchers.rb +0 -28
  137. data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
  138. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
  139. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
  140. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
  141. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
  142. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
  143. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
  144. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
  145. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
  146. data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
  147. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
  148. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
  149. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
  150. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
  151. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
  152. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
  153. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
  154. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
  155. data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
  156. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
  157. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
  158. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
  159. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
  160. data/lib/cmdx/task_deprecator.rb +0 -58
  161. data/lib/cmdx/task_processor.rb +0 -246
  162. data/lib/cmdx/task_serializer.rb +0 -57
  163. data/lib/cmdx/utils/ansi_color.rb +0 -73
  164. data/lib/cmdx/utils/log_timestamp.rb +0 -36
  165. data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
  166. data/lib/cmdx/utils/name_affix.rb +0 -52
  167. data/lib/cmdx/validator.rb +0 -57
  168. data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
  169. data/lib/generators/cmdx/workflow_generator.rb +0 -84
  170. data/lib/locales/ar.yml +0 -35
  171. data/lib/locales/cs.yml +0 -35
  172. data/lib/locales/da.yml +0 -35
  173. data/lib/locales/de.yml +0 -35
  174. data/lib/locales/el.yml +0 -35
  175. data/lib/locales/es.yml +0 -35
  176. data/lib/locales/fi.yml +0 -35
  177. data/lib/locales/fr.yml +0 -35
  178. data/lib/locales/he.yml +0 -35
  179. data/lib/locales/hi.yml +0 -35
  180. data/lib/locales/it.yml +0 -35
  181. data/lib/locales/ja.yml +0 -35
  182. data/lib/locales/ko.yml +0 -35
  183. data/lib/locales/nl.yml +0 -35
  184. data/lib/locales/no.yml +0 -35
  185. data/lib/locales/pl.yml +0 -35
  186. data/lib/locales/pt.yml +0 -35
  187. data/lib/locales/ru.yml +0 -35
  188. data/lib/locales/sv.yml +0 -35
  189. data/lib/locales/th.yml +0 -35
  190. data/lib/locales/tr.yml +0 -35
  191. data/lib/locales/vi.yml +0 -35
  192. data/lib/locales/zh.yml +0 -35
@@ -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
@@ -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
@@ -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,7 +0,0 @@
1
- <% module_namespacing do -%>
2
- class <%= class_name %> < <%= parent_class_name %>
3
-
4
- process # TODO
5
-
6
- end
7
- <% 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: "لا يمكن أن يكون فارغاً"