cmdx 0.5.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/rules/cursor-instructions.mdc +6 -0
- data/.rubocop.yml +19 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +95 -28
- data/README.md +73 -25
- data/docs/ai_prompts.md +319 -0
- data/docs/basics/call.md +234 -14
- data/docs/basics/chain.md +280 -0
- data/docs/basics/context.md +241 -33
- data/docs/basics/setup.md +85 -12
- data/docs/callbacks.md +283 -0
- data/docs/configuration.md +155 -30
- data/docs/getting_started.md +145 -22
- data/docs/internationalization.md +148 -0
- data/docs/interruptions/exceptions.md +198 -11
- data/docs/interruptions/faults.md +196 -44
- data/docs/interruptions/halt.md +188 -35
- data/docs/logging.md +204 -53
- data/docs/middlewares.md +745 -0
- data/docs/outcomes/result.md +305 -10
- data/docs/outcomes/states.md +212 -31
- data/docs/outcomes/statuses.md +284 -30
- data/docs/parameters/coercions.md +411 -29
- data/docs/parameters/defaults.md +258 -25
- data/docs/parameters/definitions.md +247 -72
- data/docs/parameters/namespacing.md +259 -27
- data/docs/parameters/validations.md +173 -168
- data/docs/testing.md +560 -0
- data/docs/tips_and_tricks.md +103 -42
- data/docs/workflows.md +329 -0
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +69 -0
- data/lib/cmdx/callback_registry.rb +106 -0
- data/lib/cmdx/chain.rb +190 -0
- data/lib/cmdx/chain_inspector.rb +149 -0
- data/lib/cmdx/chain_serializer.rb +175 -0
- data/lib/cmdx/coercions/array.rb +37 -0
- data/lib/cmdx/coercions/big_decimal.rb +33 -0
- data/lib/cmdx/coercions/boolean.rb +41 -1
- data/lib/cmdx/coercions/complex.rb +31 -0
- data/lib/cmdx/coercions/date.rb +39 -0
- data/lib/cmdx/coercions/date_time.rb +39 -0
- data/lib/cmdx/coercions/float.rb +31 -0
- data/lib/cmdx/coercions/hash.rb +42 -0
- data/lib/cmdx/coercions/integer.rb +32 -0
- data/lib/cmdx/coercions/rational.rb +31 -0
- data/lib/cmdx/coercions/string.rb +31 -0
- data/lib/cmdx/coercions/time.rb +39 -0
- data/lib/cmdx/coercions/virtual.rb +31 -0
- data/lib/cmdx/configuration.rb +217 -9
- data/lib/cmdx/context.rb +173 -2
- data/lib/cmdx/core_ext/hash.rb +72 -0
- data/lib/cmdx/core_ext/module.rb +94 -0
- data/lib/cmdx/core_ext/object.rb +105 -0
- data/lib/cmdx/correlator.rb +217 -0
- data/lib/cmdx/error.rb +210 -8
- data/lib/cmdx/errors.rb +256 -1
- data/lib/cmdx/fault.rb +177 -2
- data/lib/cmdx/faults.rb +158 -2
- data/lib/cmdx/immutator.rb +121 -2
- data/lib/cmdx/lazy_struct.rb +261 -18
- data/lib/cmdx/log_formatters/json.rb +46 -0
- data/lib/cmdx/log_formatters/key_value.rb +46 -0
- data/lib/cmdx/log_formatters/line.rb +54 -0
- data/lib/cmdx/log_formatters/logstash.rb +64 -0
- data/lib/cmdx/log_formatters/pretty_json.rb +57 -0
- data/lib/cmdx/log_formatters/pretty_key_value.rb +51 -0
- data/lib/cmdx/log_formatters/pretty_line.rb +60 -0
- data/lib/cmdx/log_formatters/raw.rb +54 -0
- data/lib/cmdx/logger.rb +85 -0
- data/lib/cmdx/logger_ansi.rb +93 -7
- data/lib/cmdx/logger_serializer.rb +116 -0
- data/lib/cmdx/middleware.rb +74 -0
- data/lib/cmdx/middleware_registry.rb +106 -0
- data/lib/cmdx/middlewares/correlate.rb +266 -0
- data/lib/cmdx/middlewares/timeout.rb +232 -0
- data/lib/cmdx/parameter.rb +228 -1
- data/lib/cmdx/parameter_inspector.rb +61 -0
- data/lib/cmdx/parameter_registry.rb +125 -0
- data/lib/cmdx/parameter_serializer.rb +83 -0
- data/lib/cmdx/parameter_validator.rb +62 -0
- data/lib/cmdx/parameter_value.rb +109 -1
- data/lib/cmdx/parameters_inspector.rb +59 -0
- data/lib/cmdx/parameters_serializer.rb +102 -0
- data/lib/cmdx/railtie.rb +123 -3
- data/lib/cmdx/result.rb +367 -25
- data/lib/cmdx/result_ansi.rb +105 -9
- data/lib/cmdx/result_inspector.rb +76 -0
- data/lib/cmdx/result_logger.rb +90 -3
- data/lib/cmdx/result_serializer.rb +137 -0
- data/lib/cmdx/rspec/result_matchers.rb +917 -0
- data/lib/cmdx/rspec/task_matchers.rb +570 -0
- data/lib/cmdx/task.rb +405 -37
- data/lib/cmdx/task_serializer.rb +74 -2
- data/lib/cmdx/utils/ansi_color.rb +95 -0
- data/lib/cmdx/utils/log_timestamp.rb +48 -0
- data/lib/cmdx/utils/monotonic_runtime.rb +71 -4
- data/lib/cmdx/utils/name_affix.rb +78 -0
- data/lib/cmdx/validators/custom.rb +82 -0
- data/lib/cmdx/validators/exclusion.rb +94 -0
- data/lib/cmdx/validators/format.rb +102 -8
- data/lib/cmdx/validators/inclusion.rb +104 -0
- data/lib/cmdx/validators/length.rb +128 -0
- data/lib/cmdx/validators/numeric.rb +128 -0
- data/lib/cmdx/validators/presence.rb +93 -7
- data/lib/cmdx/version.rb +7 -1
- data/lib/cmdx/workflow.rb +394 -0
- data/lib/cmdx.rb +25 -64
- data/lib/generators/cmdx/install_generator.rb +37 -1
- data/lib/generators/cmdx/task_generator.rb +69 -1
- data/lib/generators/cmdx/templates/install.rb +43 -15
- data/lib/generators/cmdx/workflow_generator.rb +109 -0
- data/lib/locales/ar.yml +36 -0
- data/lib/locales/cs.yml +36 -0
- data/lib/locales/da.yml +36 -0
- data/lib/locales/de.yml +36 -0
- data/lib/locales/el.yml +36 -0
- data/lib/locales/en.yml +20 -20
- data/lib/locales/es.yml +20 -20
- data/lib/locales/fi.yml +36 -0
- data/lib/locales/fr.yml +36 -0
- data/lib/locales/he.yml +36 -0
- data/lib/locales/hi.yml +36 -0
- data/lib/locales/it.yml +36 -0
- data/lib/locales/ja.yml +36 -0
- data/lib/locales/ko.yml +36 -0
- data/lib/locales/nl.yml +36 -0
- data/lib/locales/no.yml +36 -0
- data/lib/locales/pl.yml +36 -0
- data/lib/locales/pt.yml +36 -0
- data/lib/locales/ru.yml +36 -0
- data/lib/locales/sv.yml +36 -0
- data/lib/locales/th.yml +36 -0
- data/lib/locales/tr.yml +36 -0
- data/lib/locales/vi.yml +36 -0
- data/lib/locales/zh.yml +36 -0
- metadata +77 -15
- data/docs/basics/run.md +0 -34
- data/docs/batch.md +0 -53
- data/docs/example.md +0 -82
- data/docs/hooks.md +0 -62
- data/lib/cmdx/batch.rb +0 -43
- data/lib/cmdx/parameters.rb +0 -35
- data/lib/cmdx/run.rb +0 -39
- data/lib/cmdx/run_inspector.rb +0 -26
- data/lib/cmdx/run_serializer.rb +0 -20
- data/lib/cmdx/task_hook.rb +0 -18
- data/lib/generators/cmdx/batch_generator.rb +0 -30
- /data/lib/generators/cmdx/templates/{batch.rb.tt → workflow.rb.tt} +0 -0
@@ -1,57 +1,289 @@
|
|
1
1
|
# Parameters - Namespacing
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
Parameter namespacing provides method name customization to prevent conflicts
|
4
|
+
and enable flexible parameter access patterns. When parameters share names with
|
5
|
+
existing methods or when multiple parameters from different sources have the
|
6
|
+
same name, namespacing ensures clean method resolution within tasks.
|
5
7
|
|
6
|
-
|
8
|
+
## Table of Contents
|
7
9
|
|
8
|
-
|
10
|
+
- [TLDR](#tldr)
|
11
|
+
- [Namespacing Fundamentals](#namespacing-fundamentals)
|
12
|
+
- [Fixed Value Namespacing](#fixed-value-namespacing)
|
13
|
+
- [Dynamic Source-Based Namespacing](#dynamic-source-based-namespacing)
|
14
|
+
- [Conflict Resolution](#conflict-resolution)
|
15
|
+
- [Advanced Namespacing Patterns](#advanced-namespacing-patterns)
|
16
|
+
- [Error Handling with Namespacing](#error-handling-with-namespacing)
|
17
|
+
|
18
|
+
## TLDR
|
19
|
+
|
20
|
+
- **Method naming** - Use `prefix:` and `suffix:` to customize parameter method names
|
21
|
+
- **Fixed prefixes** - `prefix: "user_"` creates `user_name` method for `name` parameter
|
22
|
+
- **Dynamic prefixes** - `prefix: true` uses source name (e.g., `context_name`)
|
23
|
+
- **Conflict resolution** - Avoid conflicts with Ruby methods or multiple same-named parameters
|
24
|
+
- **Call arguments** - Always use original parameter names, namespacing only affects method names
|
25
|
+
|
26
|
+
## Namespacing Fundamentals
|
27
|
+
|
28
|
+
> [!IMPORTANT]
|
29
|
+
> The `:prefix` and `:suffix` options modify only the generated accessor method names while preserving the original parameter names for call arguments.
|
30
|
+
|
31
|
+
This separation allows for flexible method naming without affecting the task interface.
|
32
|
+
|
33
|
+
### Fixed Value Namespacing
|
34
|
+
|
35
|
+
Use string or symbol values to add consistent prefixes or suffixes to parameter
|
36
|
+
method names:
|
9
37
|
|
10
38
|
```ruby
|
11
|
-
class
|
39
|
+
class CreateOrderTask < CMDx::Task
|
40
|
+
|
41
|
+
# Fixed prefix for shipping dimensions
|
42
|
+
required :width, prefix: "shipping_"
|
43
|
+
required :height, prefix: "shipping_"
|
44
|
+
|
45
|
+
# Fixed suffix for user contact info
|
46
|
+
required :email, suffix: "_contact"
|
47
|
+
required :phone, suffix: "_contact"
|
12
48
|
|
13
|
-
|
14
|
-
required :
|
49
|
+
# Combined prefix and suffix
|
50
|
+
required :weight, prefix: "item_", suffix: "_kg"
|
15
51
|
|
16
52
|
def call
|
17
|
-
|
18
|
-
|
53
|
+
# Generated method names with namespacing
|
54
|
+
shipping_width #=> accesses width parameter
|
55
|
+
shipping_height #=> accesses height parameter
|
56
|
+
email_contact #=> accesses email parameter
|
57
|
+
phone_contact #=> accesses phone parameter
|
58
|
+
item_weight_kg #=> accesses weight parameter
|
19
59
|
end
|
20
60
|
|
21
61
|
end
|
22
62
|
|
23
|
-
# Call arguments
|
24
|
-
|
63
|
+
# Call arguments use original parameter names
|
64
|
+
CreateOrderTask.call(
|
65
|
+
width: 10,
|
66
|
+
height: 20,
|
67
|
+
email: "customer@example.com",
|
68
|
+
phone: "555-1234",
|
69
|
+
weight: 2.5
|
70
|
+
)
|
25
71
|
```
|
26
72
|
|
27
|
-
|
73
|
+
### Dynamic Source-Based Namespacing
|
74
|
+
|
75
|
+
Use `true` value to automatically generate prefixes or suffixes based on the
|
76
|
+
parameter source name:
|
28
77
|
|
29
78
|
```ruby
|
30
|
-
class
|
79
|
+
class ProcessUserRegistrationTask < CMDx::Task
|
80
|
+
|
81
|
+
# Automatic prefix from default source (:context)
|
82
|
+
required :user_id, prefix: true # Generates: context_user_id
|
31
83
|
|
32
|
-
#
|
33
|
-
|
84
|
+
# Automatic suffix from custom source
|
85
|
+
required :name, source: :profile, suffix: true # Generates: name_profile
|
34
86
|
|
35
|
-
#
|
36
|
-
|
87
|
+
# Combined automatic namespacing
|
88
|
+
required :email, source: :account, prefix: true, suffix: true # Generates: account_email_account
|
37
89
|
|
38
90
|
def call
|
39
|
-
|
40
|
-
|
91
|
+
context_user_id #=> accesses context.user_id
|
92
|
+
name_profile #=> accesses profile.name
|
93
|
+
account_email_account #=> accesses account.email
|
41
94
|
end
|
42
95
|
|
43
|
-
|
96
|
+
private
|
44
97
|
|
45
|
-
|
46
|
-
|
47
|
-
|
98
|
+
def profile
|
99
|
+
@profile ||= User.find(context.user_id).profile
|
100
|
+
end
|
101
|
+
|
102
|
+
def account
|
103
|
+
@account ||= User.find(context.user_id).account
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
48
107
|
```
|
49
108
|
|
50
109
|
> [!NOTE]
|
51
|
-
>
|
52
|
-
|
110
|
+
> Call arguments always use original parameter names regardless of namespacing configuration.
|
111
|
+
|
112
|
+
## Conflict Resolution
|
113
|
+
|
114
|
+
Namespacing is essential when dealing with method name conflicts or when
|
115
|
+
accessing multiple objects with similar attribute names:
|
116
|
+
|
117
|
+
### Method Name Conflicts
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
class UpdateUserProfileTask < CMDx::Task
|
121
|
+
|
122
|
+
# Avoid conflict with Ruby's built-in 'name' method
|
123
|
+
required :name, prefix: "user_"
|
124
|
+
|
125
|
+
# Avoid conflict with custom private methods
|
126
|
+
required :status, suffix: "_param"
|
127
|
+
|
128
|
+
def call
|
129
|
+
user_name #=> parameter value, not Ruby's Object#name
|
130
|
+
status_param #=> parameter value, not custom status method
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def status
|
136
|
+
"processing" # Custom method that would conflict without suffix
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
### Multiple Source Disambiguation
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class GenerateInvoiceTask < CMDx::Task
|
146
|
+
|
147
|
+
# Customer information
|
148
|
+
required :name, source: :customer, prefix: "customer_"
|
149
|
+
required :email, source: :customer, prefix: "customer_"
|
150
|
+
|
151
|
+
# Company information
|
152
|
+
required :name, source: :company, prefix: "company_"
|
153
|
+
required :email, source: :company, prefix: "company_"
|
154
|
+
|
155
|
+
# Order information
|
156
|
+
required :total, source: :order, suffix: "_amount"
|
157
|
+
required :status, source: :order, suffix: "_state"
|
158
|
+
|
159
|
+
def call
|
160
|
+
# Clear disambiguation of same-named attributes
|
161
|
+
customer_name #=> customer.name
|
162
|
+
company_name #=> company.name
|
163
|
+
customer_email #=> customer.email
|
164
|
+
company_email #=> company.email
|
165
|
+
total_amount #=> order.total
|
166
|
+
status_state #=> order.status
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def customer
|
172
|
+
@customer ||= Customer.find(context.customer_id)
|
173
|
+
end
|
174
|
+
|
175
|
+
def company
|
176
|
+
@company ||= Company.find(context.company_id)
|
177
|
+
end
|
178
|
+
|
179
|
+
def order
|
180
|
+
@order ||= Order.find(context.order_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
## Advanced Namespacing Patterns
|
187
|
+
|
188
|
+
### Hierarchical Namespacing
|
189
|
+
|
190
|
+
Combine namespacing with nested parameters for complex data structures:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class CreateShipmentTask < CMDx::Task
|
194
|
+
|
195
|
+
# Origin address with prefix
|
196
|
+
required :origin_address, source: :shipment, prefix: "from_" do
|
197
|
+
required :street, :city, :state, :zip
|
198
|
+
end
|
199
|
+
|
200
|
+
# Destination address with suffix
|
201
|
+
required :destination_address, source: :shipment, suffix: "_to" do
|
202
|
+
required :street, :city, :state, :zip
|
203
|
+
end
|
204
|
+
|
205
|
+
def call
|
206
|
+
from_origin_address #=> shipment.origin_address
|
207
|
+
destination_address_to #=> shipment.destination_address
|
208
|
+
|
209
|
+
# Nested parameters access depends on current context
|
210
|
+
street #=> current address context street
|
211
|
+
city #=> current address context city
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def shipment
|
217
|
+
@shipment ||= Shipment.find(context.shipment_id)
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
```
|
222
|
+
|
223
|
+
### Conditional Namespacing
|
224
|
+
|
225
|
+
Apply namespacing based on runtime conditions:
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
class ProcessPaymentTask < CMDx::Task
|
229
|
+
|
230
|
+
# Different namespacing based on payment type
|
231
|
+
required :reference_id,
|
232
|
+
prefix: -> { context.payment_type == "credit_card" ? "card_" : "bank_" }
|
233
|
+
|
234
|
+
def call
|
235
|
+
# Method names determined at runtime
|
236
|
+
if context.payment_type == "credit_card"
|
237
|
+
card_reference_id #=> accesses reference_id parameter
|
238
|
+
else
|
239
|
+
bank_reference_id #=> accesses reference_id parameter
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
```
|
245
|
+
|
246
|
+
## Error Handling with Namespacing
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
class ValidateUserDataTask < CMDx::Task
|
250
|
+
|
251
|
+
required :email,
|
252
|
+
prefix: "user_",
|
253
|
+
type: :string,
|
254
|
+
format: { with: /@/ }
|
255
|
+
|
256
|
+
required :age,
|
257
|
+
suffix: "_years",
|
258
|
+
type: :integer,
|
259
|
+
numeric: { min: 18 }
|
260
|
+
|
261
|
+
def call
|
262
|
+
# Access via namespaced methods
|
263
|
+
user_email #=> validated email
|
264
|
+
age_years #=> validated age
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
# Invalid parameters
|
270
|
+
result = ValidateUserDataTask.call(
|
271
|
+
email: "invalid-email",
|
272
|
+
age: "not-a-number"
|
273
|
+
)
|
274
|
+
|
275
|
+
result.failed? #=> true
|
276
|
+
result.metadata
|
277
|
+
#=> {
|
278
|
+
# reason: "email format is not valid. age could not coerce into an integer.",
|
279
|
+
# messages: {
|
280
|
+
# user_email: ["format is not valid"],
|
281
|
+
# age_years: ["could not coerce into an integer"]
|
282
|
+
# }
|
283
|
+
# }
|
284
|
+
```
|
53
285
|
|
54
286
|
---
|
55
287
|
|
56
|
-
- **Prev:** [Definitions](
|
57
|
-
- **Next:** [Coercions](
|
288
|
+
- **Prev:** [Parameters - Definitions](definitions.md)
|
289
|
+
- **Next:** [Parameters - Coercions](coercions.md)
|