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.
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 +56 -1
  8. data/.irbrc +6 -0
  9. data/.rubocop.yml +29 -18
  10. data/CHANGELOG.md +5 -133
  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 +91 -154
  85. data/lib/cmdx/validators/numeric.rb +87 -162
  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
data/docs/workflows.md CHANGED
@@ -1,374 +1,190 @@
1
- # Workflow
1
+ # Workflows
2
2
 
3
- CMDx::Workflow orchestrates sequential execution of multiple tasks in a linear pipeline. Workflows provide a declarative DSL for composing complex business workflows from individual task components, with support for conditional execution, context propagation, and configurable halt behavior.
4
-
5
- Workflows inherit from Task, gaining all task capabilities including callbacks, parameter validation, result tracking, and configuration. The key difference is that workflows coordinate other tasks rather than implementing business logic directly.
3
+ Workflow orchestrates sequential execution of multiple tasks in a linear pipeline. Workflows provide a declarative DSL for composing complex business logic from individual task components, with support for conditional execution, context propagation, and configurable halt behavior.
6
4
 
7
5
  ## Table of Contents
8
6
 
9
- - [TLDR](#tldr)
10
- - [Basic Usage](#basic-usage)
11
- - [Task Declaration](#task-declaration)
12
- - [Context Propagation](#context-propagation)
13
- - [Conditional Execution](#conditional-execution)
7
+ - [Declarations](#declarations)
8
+ - [Task](#task)
9
+ - [Group](#group)
10
+ - [Conditionals](#conditionals)
14
11
  - [Halt Behavior](#halt-behavior)
15
- - [Default Behavior](#default-behavior)
16
- - [Class-Level Configuration](#class-level-configuration)
17
- - [Group-Level Configuration](#group-level-configuration)
18
- - [Available Result Statuses](#available-result-statuses)
19
- - [Process Method Options](#process-method-options)
20
- - [Error Handling](#error-handling)
12
+ - [Task Configuration](#task-configuration)
13
+ - [Group Configuration](#group-configuration)
21
14
  - [Nested Workflows](#nested-workflows)
22
- - [Task Settings Integration](#task-settings-integration)
23
- - [Generator](#generator)
24
-
25
- ## TLDR
26
-
27
- ```ruby
28
- # Basic workflow - sequential task execution
29
- class OrderWorkflow < CMDx::Workflow
30
- process ValidateOrderTask # Step 1
31
- process CalculateTaxTask # Step 2
32
- process ChargePaymentTask # Step 3
33
- end
34
15
 
35
- # Conditional execution
36
- process SendEmailTask, if: proc { context.notify_user? }
37
- process SkipableTask, unless: :should_skip?
16
+ ## Declarations
38
17
 
39
- # Halt behavior control
40
- process CriticalTask, workflow_halt: [CMDx::Result::FAILED, CMDx::Result::SKIPPED]
41
- process OptionalTask, workflow_halt: [] # Never halt
18
+ Tasks execute in declaration order (FIFO). The workflow context propagates to each task, allowing access to data from previous executions.
42
19
 
43
- # Context flows through all tasks automatically
44
- result = OrderWorkflow.call(order: order)
45
- result.context.tax_amount # Set by CalculateTaxTask
46
- result.context.payment_id # Set by ChargePaymentTask
47
- ```
48
-
49
- ## Basic Usage
20
+ > [!IMPORTANT]
21
+ > Do **NOT** define a `work` method in workflow tasks. The included module automatically provides the execution logic.
50
22
 
51
- > [!WARNING]
52
- > Do **NOT** define a `call` method in workflow classes. The workflow automatically provides execution logic.
23
+ ### Task
53
24
 
54
25
  ```ruby
55
- class OrderProcessingWorkflow < CMDx::Workflow
56
- process ValidateOrderTask
57
- process CalculateTaxTask
58
- process ChargePaymentTask
59
- process FulfillOrderTask
60
- end
26
+ class OnboardingWorkflow < CMDx::Task
27
+ include CMDx::Workflow
61
28
 
62
- # Execute workflow
63
- result = OrderProcessingWorkflow.call(order: order, user: current_user)
29
+ task CreateUserProfile
30
+ task SetupAccountPreferences
64
31
 
65
- if result.success?
66
- redirect_to order_path(result.context.order)
67
- elsif result.failed?
68
- handle_error(result.metadata[:reason])
32
+ tasks SendWelcomeEmail, SendWelcomeSms, CreateDashboard
69
33
  end
70
34
  ```
71
35
 
72
- ## Task Declaration
36
+ ### Group
73
37
 
74
- Tasks are declared using the `process` method in execution order:
38
+ Group related tasks for better organization and shared configuration:
39
+
40
+ > [!IMPORTANT]
41
+ > Settings and conditionals for a group apply to all tasks within that group.
75
42
 
76
43
  ```ruby
77
- class NotificationWorkflow < CMDx::Workflow
78
- # Single task
79
- process PrepareNotificationTask
44
+ class ContentModerationWorkflow < CMDx::Task
45
+ include CMDx::Workflow
80
46
 
81
- # Multiple tasks (grouped with same options)
82
- process SendEmailTask, SendSmsTask, SendPushTask
47
+ # Screening phase
48
+ tasks ScanForProfanity, CheckForSpam, ValidateImages, breakpoints: ["skipped"]
83
49
 
84
- # Tasks with conditions
85
- process SendWebhookTask, if: proc { context.webhook_enabled? }
86
- process SendSlackTask, unless: :slack_disabled?
50
+ # Review phase
51
+ tasks ApplyFilters, ScoreContent, FlagSuspicious
87
52
 
88
- private
89
-
90
- def slack_disabled?
91
- !context.user.slack_enabled?
92
- end
53
+ # Decision phase
54
+ tasks PublishContent, QueueForReview, NotifyModerators
93
55
  end
94
56
  ```
95
57
 
96
- > [!IMPORTANT]
97
- > Tasks execute in declaration order (FIFO). Use grouping to apply the same options to multiple tasks.
98
-
99
- ## Context Propagation
58
+ ### Conditionals
100
59
 
101
- The context object flows through all tasks, creating a data pipeline:
60
+ Conditionals support multiple syntaxes for flexible execution control:
102
61
 
103
62
  ```ruby
104
- class PaymentWorkflow < CMDx::Workflow
105
- process ValidateOrderTask # Sets context.validation_errors
106
- process CalculateTaxTask # Uses context.order, sets context.tax_amount
107
- process ChargePaymentTask # Uses context.tax_amount, sets context.payment_id
63
+ class ContentAccessCheck
64
+ def call(task)
65
+ task.context.user.can?(:publish_content)
66
+ end
108
67
  end
109
68
 
110
- result = PaymentWorkflow.call(order: order)
111
- # Context contains cumulative data from all executed tasks
112
- result.context.validation_errors # From ValidateOrderTask
113
- result.context.tax_amount # From CalculateTaxTask
114
- result.context.payment_id # From ChargePaymentTask
115
- ```
116
-
117
- ## Conditional Execution
69
+ class OnboardingWorkflow < CMDx::Task
70
+ include CMDx::Workflow
118
71
 
119
- Tasks can execute conditionally using `:if` and `:unless` options:
72
+ # If and/or Unless
73
+ task SendWelcomeEmail, if: :email_configured?, unless: :email_disabled?
120
74
 
121
- ```ruby
122
- class UserWorkflow < CMDx::Workflow
123
- process ValidateUserTask
75
+ # Proc
76
+ task SendWelcomeEmail, if: ->(workflow) { Rails.env.production? && workflow.class.name.include?("Premium") }
124
77
 
125
- # Proc condition
126
- process UpgradeToPremiumTask, if: proc { context.user.premium? }
78
+ # Lambda
79
+ task SendWelcomeEmail, if: proc { |workflow| workflow.context.features_enabled? }
127
80
 
128
- # Lambda condition
129
- process ProcessInternationalTask, unless: -> { context.user.domestic? }
81
+ # Class or Module
82
+ task SendWelcomeEmail, unless: ContentAccessCheck
130
83
 
131
- # Method condition
132
- process LogDebugInfoTask, if: :debug_enabled?
84
+ # Instance
85
+ task SendWelcomeEmail, if: ContentAccessCheck.new
133
86
 
134
- # Complex condition
135
- process SendSpecialOfferTask, if: proc {
136
- context.user.active? &&
137
- context.feature_enabled?(:offers) &&
138
- business_hours?
139
- }
87
+ # Conditional applies to all tasks of this declaration group
88
+ tasks SendWelcomeEmail, CreateDashboard, SetupTutorial, if: :email_configured?
140
89
 
141
90
  private
142
91
 
143
- def debug_enabled?
144
- Rails.env.development?
92
+ def email_configured?
93
+ context.user.email_address.present?
145
94
  end
146
95
 
147
- def business_hours?
148
- Time.now.hour.between?(9, 17)
96
+ def email_disabled?
97
+ context.user.communication_preference == :disabled
149
98
  end
150
99
  end
151
100
  ```
152
101
 
153
- > [!NOTE]
154
- > Conditions are evaluated in the workflow instance context. Skipped tasks return `SKIPPED` status but don't halt execution by default.
155
-
156
102
  ## Halt Behavior
157
103
 
158
- Workflows control execution flow by halting on specific result statuses.
159
-
160
- ### Default Behavior
161
-
162
- By default, workflows halt on `FAILED` status but continue on `SKIPPED`:
104
+ By default skipped tasks are considered no-op executions and does not stop workflow execution.
105
+ This is configurable via global and task level breakpoint settings. Task and group configurations
106
+ can be used together within a workflow.
163
107
 
164
108
  ```ruby
165
- class DataWorkflow < CMDx::Workflow
166
- process LoadDataTask # If fails → workflow stops
167
- process ValidateDataTask # If skipped → workflow continues
168
- process SaveDataTask # Only runs if no failures occurred
109
+ class AnalyticsWorkflow < CMDx::Task
110
+ include CMDx::Workflow
111
+
112
+ task CollectMetrics # If fails workflow stops
113
+ task FilterOutliers # If skipped → workflow continues
114
+ task GenerateDashboard # Only runs if no failures occurred
169
115
  end
170
116
  ```
171
117
 
172
- ### Class-Level Configuration
118
+ ### Task Configuration
173
119
 
174
120
  Configure halt behavior for the entire workflow:
175
121
 
176
122
  ```ruby
177
- class CriticalWorkflow < CMDx::Workflow
123
+ class SecurityWorkflow < CMDx::Task
124
+ include CMDx::Workflow
125
+
178
126
  # Halt on both failed and skipped results
179
- cmd_settings!(workflow_halt: [CMDx::Result::FAILED, CMDx::Result::SKIPPED])
127
+ settings(workflow_breakpoints: ["skipped", "failed"])
180
128
 
181
- process LoadCriticalDataTask
182
- process ValidateCriticalDataTask
129
+ task PerformSecurityScan
130
+ task ValidateSecurityRules
183
131
  end
184
132
 
185
- class OptionalWorkflow < CMDx::Workflow
133
+ class OptionalTasksWorkflow < CMDx::Task
134
+ include CMDx::Workflow
135
+
186
136
  # Never halt, always continue
187
- cmd_settings!(workflow_halt: [])
137
+ settings(breakpoints: [])
188
138
 
189
- process TryLoadDataTask
190
- process TryValidateDataTask
191
- process TrySaveDataTask
139
+ task TryBackupData
140
+ task TryCleanupLogs
141
+ task TryOptimizeCache
192
142
  end
193
143
  ```
194
144
 
195
- ### Group-Level Configuration
145
+ ### Group Configuration
196
146
 
197
147
  Different task groups can have different halt behavior:
198
148
 
199
149
  ```ruby
200
- class AccountWorkflow < CMDx::Workflow
201
- # Critical tasks - halt on any failure or skip
202
- process CreateUserTask, ValidateUserTask,
203
- workflow_halt: [CMDx::Result::FAILED, CMDx::Result::SKIPPED]
204
-
205
- # Optional tasks - never halt
206
- process SendWelcomeEmailTask, CreateProfileTask,
207
- workflow_halt: []
208
-
209
- # Default behavior for remaining tasks
210
- process NotifyAdminTask, LogUserCreationTask
211
- end
212
- ```
213
-
214
- ### Available Result Statuses
215
-
216
- Use these statuses in `workflow_halt` arrays:
217
-
218
- | Status | Description |
219
- |--------|-------------|
220
- | `CMDx::Result::SUCCESS` | Task completed successfully |
221
- | `CMDx::Result::SKIPPED` | Task was skipped intentionally |
222
- | `CMDx::Result::FAILED` | Task failed due to error or validation |
223
-
224
- ## Process Method Options
225
-
226
- The `process` method supports these options:
227
-
228
- | Option | Description | Example |
229
- |--------|-------------|---------|
230
- | `:if` | Execute task if condition is true | `if: proc { context.enabled? }` |
231
- | `:unless` | Execute task if condition is false | `unless: :should_skip?` |
232
- | `:workflow_halt` | Which statuses should halt execution | `workflow_halt: [CMDx::Result::FAILED]` |
233
-
234
- Conditions can be procs, lambdas, symbols, or strings referencing instance methods.
235
-
236
- ## Error Handling
237
-
238
- > [!WARNING]
239
- > Workflow failures provide detailed information about which task failed and why, enabling precise error handling and debugging.
240
-
241
- ```ruby
242
- class OrderWorkflow < CMDx::Workflow
243
- process ValidateOrderTask
244
- process CalculateTaxTask
245
- process ChargePaymentTask
246
- end
247
-
248
- result = OrderWorkflow.call(order: invalid_order)
249
-
250
- if result.failed?
251
- result.metadata
252
- # {
253
- # reason: "ValidateOrderTask failed: Order ID is required",
254
- # failed_task: "ValidateOrderTask",
255
- # task_index: 0,
256
- # executed_tasks: ["ValidateOrderTask"],
257
- # skipped_tasks: [],
258
- # context_at_failure: { order: {...} }
259
- # }
260
- end
261
- ```
262
-
263
- ### Common Error Scenarios
264
-
265
- ```ruby
266
- # Task raises exception
267
- class ProcessDataWorkflow < CMDx::Workflow
268
- process ValidateDataTask # Raises validation error
269
- process TransformDataTask # Never executes
270
- end
150
+ class SubscriptionWorkflow < CMDx::Task
151
+ include CMDx::Workflow
271
152
 
272
- result = ProcessDataWorkflow.call(data: nil)
273
- result.failed? # → true
274
- result.metadata[:reason] # → "ValidateDataTask failed: Data cannot be nil"
153
+ task CreateSubscription, ValidatePayment, workflow_breakpoints: ["skipped", "failed"]
275
154
 
276
- # Halt on skipped task
277
- class StrictWorkflow < CMDx::Workflow
278
- process RequiredTask, workflow_halt: [CMDx::Result::SKIPPED]
279
- process OptionalTask, if: proc { false } # Always skipped
280
- process FinalTask # Never executes
155
+ # Never halt, always continue
156
+ task SendConfirmationEmail, UpdateBilling, breakpoints: []
281
157
  end
282
-
283
- result = StrictWorkflow.call
284
- result.failed? # → true (halted on skipped task)
285
158
  ```
286
159
 
287
- > [!TIP]
288
- > Use specific halt configurations to implement different failure strategies: strict validation, best-effort processing, or fault-tolerant pipelines.
289
-
290
160
  ## Nested Workflows
291
161
 
292
- Workflows can process other workflows for hierarchical composition:
162
+ Workflows can task other workflows for hierarchical composition:
293
163
 
294
164
  ```ruby
295
- class DataPreProcessingWorkflow < CMDx::Workflow
296
- process ValidateInputTask
297
- process SanitizeDataTask
298
- end
299
-
300
- class DataProcessingWorkflow < CMDx::Workflow
301
- process TransformDataTask
302
- process ApplyBusinessLogicTask
303
- end
165
+ class EmailPreparationWorkflow < CMDx::Task
166
+ include CMDx::Workflow
304
167
 
305
- class CompleteDataWorkflow < CMDx::Workflow
306
- process DataPreProcessingWorkflow
307
- process DataProcessingWorkflow, if: proc { context.pre_processing_successful? }
308
- process GenerateReportTask
168
+ task ValidateRecipients
169
+ task CompileTemplate
309
170
  end
310
- ```
311
-
312
- > [!NOTE]
313
- > Nested workflows share the same context object, enabling seamless data flow across workflow boundaries.
314
-
315
- ## Task Settings Integration
316
-
317
- Workflows support all task capabilities including parameters, callbacks, and configuration:
318
-
319
- ```ruby
320
- class PaymentWorkflow < CMDx::Workflow
321
- # Parameter validation
322
- required :order_id, type: :integer
323
- optional :notify_user, type: :boolean, default: true
324
-
325
- # Workflow settings
326
- cmd_settings!(
327
- workflow_halt: [CMDx::Result::FAILED],
328
- log_level: :debug,
329
- tags: [:critical, :payment]
330
- )
331
-
332
- # Callbacks
333
- before_execution :setup_context
334
- after_execution :cleanup_resources
335
-
336
- process ValidateOrderTask
337
- process ProcessPaymentTask
338
- process NotifyUserTask, if: proc { context.notify_user }
339
-
340
- private
341
171
 
342
- def setup_context
343
- context.start_time = Time.now
344
- end
172
+ class EmailDeliveryWorkflow < CMDx::Task
173
+ include CMDx::Workflow
345
174
 
346
- def cleanup_resources
347
- context.temp_files&.each(&:delete)
348
- end
175
+ tasks SendEmails, TrackDeliveries
349
176
  end
350
- ```
351
177
 
352
- ## Generator
178
+ class CompleteEmailWorkflow < CMDx::Task
179
+ include CMDx::Workflow
353
180
 
354
- Generate workflow scaffolding using the Rails generator:
355
-
356
- ```bash
357
- rails g cmdx:workflow ProcessOrder
358
- ```
359
-
360
- Creates `app/commands/process_order_workflow.rb`:
361
-
362
- ```ruby
363
- class ProcessOrderWorkflow < ApplicationWorkflow
364
- process # TODO: Add your tasks here
181
+ task EmailPreparationWorkflow
182
+ task EmailDeliveryWorkflow, if: proc { context.preparation_successful? }
183
+ task GenerateDeliveryReport
365
184
  end
366
185
  ```
367
186
 
368
- > [!NOTE]
369
- > The generator creates workflow files in `app/commands/`, inherits from `ApplicationWorkflow` if available (otherwise `CMDx::Workflow`), and handles proper naming conventions.
370
-
371
187
  ---
372
188
 
373
- - **Prev:** [Middlewares](middlewares.md)
374
- - **Next:** [Logging](logging.md)
189
+ - **Prev:** [Deprecation](deprecation.md)
190
+ - **Next:** [Tips and Tricks](tips_and_tricks.md)
data/lib/cmdx/.DS_Store CHANGED
Binary file