cmdx 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- data/docs/basics/chain.md +190 -160
- data/docs/basics/context.md +242 -154
- data/docs/basics/setup.md +302 -32
- data/docs/callbacks.md +390 -94
- data/docs/configuration.md +181 -65
- data/docs/deprecation.md +245 -0
- data/docs/getting_started.md +161 -39
- data/docs/internationalization.md +590 -70
- data/docs/interruptions/exceptions.md +135 -118
- data/docs/interruptions/faults.md +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- data/docs/outcomes/result.md +140 -112
- data/docs/outcomes/states.md +134 -99
- data/docs/outcomes/statuses.md +204 -146
- data/docs/parameters/coercions.md +232 -281
- data/docs/parameters/defaults.md +224 -169
- data/docs/parameters/definitions.md +289 -141
- data/docs/parameters/namespacing.md +250 -161
- data/docs/parameters/validations.md +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
data/docs/parameters/defaults.md
CHANGED
@@ -1,279 +1,334 @@
|
|
1
1
|
# Parameters - Defaults
|
2
2
|
|
3
|
-
Parameter defaults provide fallback values when arguments are not provided or
|
4
|
-
resolve to `nil`. Defaults ensure tasks have sensible values for optional
|
5
|
-
parameters while maintaining flexibility for callers to override when needed.
|
6
|
-
Defaults work seamlessly with coercion, validation, and nested parameters.
|
3
|
+
Parameter defaults provide fallback values when arguments are not provided or resolve to `nil`. Defaults ensure tasks have sensible values for optional parameters while maintaining flexibility for callers to override when needed.
|
7
4
|
|
8
5
|
## Table of Contents
|
9
6
|
|
10
7
|
- [TLDR](#tldr)
|
11
|
-
- [Default
|
12
|
-
|
13
|
-
|
14
|
-
- [Defaults with Type Coercion](#defaults-with-type-coercion)
|
15
|
-
- [Defaults with Validation](#defaults-with-validation)
|
8
|
+
- [Default Fundamentals](#default-fundamentals)
|
9
|
+
- [Dynamic Defaults](#dynamic-defaults)
|
10
|
+
- [Defaults with Coercion and Validation](#defaults-with-coercion-and-validation)
|
16
11
|
- [Nested Parameter Defaults](#nested-parameter-defaults)
|
12
|
+
- [Error Handling](#error-handling)
|
17
13
|
|
18
14
|
## TLDR
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
```ruby
|
17
|
+
# Fixed defaults
|
18
|
+
optional :priority, default: "normal"
|
19
|
+
optional :retries, type: :integer, default: 3
|
20
|
+
optional :tags, type: :array, default: []
|
25
21
|
|
26
|
-
|
22
|
+
# Dynamic defaults
|
23
|
+
optional :created_at, default: -> { Time.now }
|
24
|
+
optional :template, default: :determine_template
|
27
25
|
|
28
|
-
|
29
|
-
|
26
|
+
# With coercion - defaults are coerced too
|
27
|
+
optional :max_items, type: :integer, default: "50" # → 50
|
30
28
|
|
31
|
-
|
29
|
+
# Nested defaults
|
30
|
+
optional :config, type: :hash, default: {} do
|
31
|
+
optional :timeout, default: 30
|
32
|
+
end
|
33
|
+
```
|
32
34
|
|
33
|
-
|
35
|
+
## Default Fundamentals
|
36
|
+
|
37
|
+
> [!NOTE]
|
38
|
+
> Defaults apply when parameters are not provided or resolve to `nil`. They work seamlessly with coercion, validation, and nested parameters.
|
34
39
|
|
35
40
|
```ruby
|
36
|
-
class
|
41
|
+
class ProcessOrderTask < CMDx::Task
|
42
|
+
required :order_id, type: :integer
|
37
43
|
|
38
|
-
|
39
|
-
optional :priority,
|
40
|
-
optional :
|
44
|
+
# Fixed value defaults
|
45
|
+
optional :priority, default: "standard"
|
46
|
+
optional :send_email, type: :boolean, default: true
|
41
47
|
optional :max_retries, type: :integer, default: 3
|
42
|
-
|
43
|
-
optional :
|
44
|
-
optional :order_metadata, type: :hash, default: {}
|
45
|
-
optional :created_at, type: :datetime, default: -> { Time.now }
|
48
|
+
optional :tags, type: :array, default: []
|
49
|
+
optional :metadata, type: :hash, default: {}
|
46
50
|
|
47
51
|
def call
|
48
|
-
|
49
|
-
priority
|
50
|
-
|
51
|
-
max_retries
|
52
|
-
notification_tags #=> [] if not provided
|
53
|
-
order_metadata #=> {} if not provided
|
54
|
-
created_at #=> current time if not provided
|
52
|
+
# Defaults used when parameters not provided
|
53
|
+
process_order_with_priority(priority) # "standard"
|
54
|
+
send_notification if send_email # true
|
55
|
+
retry_failed_steps(max_retries) # 3
|
55
56
|
end
|
56
|
-
|
57
57
|
end
|
58
58
|
|
59
|
-
#
|
60
|
-
|
61
|
-
# priority: "
|
59
|
+
# Using defaults
|
60
|
+
ProcessOrderTask.call(order_id: 123)
|
61
|
+
# priority: "standard", send_email: true, max_retries: 3
|
62
62
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
63
|
+
# Overriding defaults
|
64
|
+
ProcessOrderTask.call(
|
65
|
+
order_id: 123,
|
66
66
|
priority: "urgent",
|
67
|
-
|
68
|
-
|
67
|
+
send_email: false,
|
68
|
+
tags: ["rush"]
|
69
69
|
)
|
70
70
|
```
|
71
71
|
|
72
|
-
|
72
|
+
## Dynamic Defaults
|
73
73
|
|
74
74
|
> [!TIP]
|
75
|
-
> Use procs, lambdas, or method symbols for dynamic defaults
|
75
|
+
> Use procs, lambdas, or method symbols for dynamic defaults evaluated at runtime. Essential for timestamps, UUIDs, and context-dependent values.
|
76
76
|
|
77
77
|
```ruby
|
78
|
-
class
|
79
|
-
|
80
|
-
required :
|
78
|
+
class SendNotificationTask < CMDx::Task
|
79
|
+
required :user_id, type: :integer
|
80
|
+
required :message, type: :string
|
81
81
|
|
82
|
-
#
|
82
|
+
# Proc defaults - evaluated when accessed
|
83
83
|
optional :sent_at, type: :datetime, default: -> { Time.now }
|
84
|
-
optional :tracking_id,
|
84
|
+
optional :tracking_id, default: -> { SecureRandom.uuid }
|
85
85
|
|
86
86
|
# Environment-aware defaults
|
87
|
-
optional :
|
88
|
-
optional :sender_email, type: :string, default: -> { Rails.application.credentials.sender_email }
|
87
|
+
optional :service, default: -> { Rails.env.production? ? "sendgrid" : "test" }
|
89
88
|
|
90
89
|
# Method symbol defaults
|
91
|
-
optional :
|
92
|
-
optional :
|
90
|
+
optional :template, default: :default_template
|
91
|
+
optional :priority, default: :calculate_priority
|
93
92
|
|
94
93
|
def call
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
94
|
+
notification = {
|
95
|
+
message: message,
|
96
|
+
sent_at: sent_at, # Current time when accessed
|
97
|
+
tracking_id: tracking_id, # Unique UUID when accessed
|
98
|
+
template: template, # Result of default_template method
|
99
|
+
priority: priority # Result of calculate_priority method
|
100
|
+
}
|
101
|
+
|
102
|
+
NotificationService.send(notification, service: service)
|
101
103
|
end
|
102
104
|
|
103
105
|
private
|
104
106
|
|
105
|
-
def
|
106
|
-
|
107
|
+
def default_template
|
108
|
+
user.premium? ? "premium_notification" : "standard_notification"
|
107
109
|
end
|
108
110
|
|
109
|
-
def
|
110
|
-
|
111
|
+
def calculate_priority
|
112
|
+
user.vip? ? "high" : "normal"
|
111
113
|
end
|
112
114
|
|
113
|
-
def
|
114
|
-
@
|
115
|
+
def user
|
116
|
+
@user ||= User.find(user_id)
|
115
117
|
end
|
116
|
-
|
117
118
|
end
|
118
119
|
```
|
119
120
|
|
120
|
-
## Defaults with
|
121
|
+
## Defaults with Coercion and Validation
|
121
122
|
|
122
123
|
> [!IMPORTANT]
|
123
|
-
> Defaults
|
124
|
+
> Defaults are subject to the same coercion and validation rules as provided values, ensuring consistency and catching configuration errors early.
|
125
|
+
|
126
|
+
### Coercion with Defaults
|
124
127
|
|
125
128
|
```ruby
|
126
|
-
class
|
129
|
+
class ConfigureServiceTask < CMDx::Task
|
130
|
+
# String defaults coerced to target types
|
131
|
+
optional :max_connections, type: :integer, default: "100"
|
132
|
+
optional :config, type: :hash, default: '{"timeout": 30}'
|
133
|
+
optional :allowed_hosts, type: :array, default: '["localhost"]'
|
134
|
+
optional :debug_mode, type: :boolean, default: "false"
|
135
|
+
|
136
|
+
# Dynamic defaults with coercion
|
137
|
+
optional :session_id, type: :string, default: -> { Time.now.to_i }
|
127
138
|
|
128
|
-
|
129
|
-
|
139
|
+
def call
|
140
|
+
max_connections # → 100 (Integer from "100")
|
141
|
+
config # → {"timeout" => 30} (Hash from JSON)
|
142
|
+
allowed_hosts # → ["localhost"] (Array from JSON)
|
143
|
+
debug_mode # → false (Boolean from "false")
|
144
|
+
session_id # → "1640995200" (String from Integer)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
130
148
|
|
131
|
-
|
132
|
-
optional :shipping_config, type: :hash, default: '{"carrier": "ups", "speed": "standard"}'
|
149
|
+
### Validation with Defaults
|
133
150
|
|
134
|
-
|
135
|
-
|
151
|
+
```ruby
|
152
|
+
class ScheduleTaskTask < CMDx::Task
|
153
|
+
required :task_name, type: :string
|
136
154
|
|
137
|
-
#
|
138
|
-
optional :
|
155
|
+
# Default must pass validation rules
|
156
|
+
optional :priority, default: "medium",
|
157
|
+
inclusion: { in: %w[low medium high urgent] }
|
139
158
|
|
140
|
-
|
141
|
-
|
159
|
+
optional :timeout, type: :integer, default: 300,
|
160
|
+
numeric: { min: 60, max: 3600 }
|
142
161
|
|
143
|
-
|
144
|
-
|
162
|
+
optional :retry_count, type: :integer, default: 3,
|
163
|
+
numeric: { min: 0, max: 10 }
|
145
164
|
|
146
165
|
def call
|
147
|
-
|
148
|
-
|
149
|
-
allowed_countries #=> ["US", "CA", "UK"] (array)
|
150
|
-
require_signature #=> true (boolean)
|
151
|
-
embargo_date #=> Date object
|
152
|
-
order_number #=> "1640995200" (string from integer)
|
166
|
+
# All defaults validated against their rules
|
167
|
+
schedule_task(task_name, priority: priority, timeout: timeout)
|
153
168
|
end
|
154
|
-
|
155
169
|
end
|
156
|
-
```
|
157
170
|
|
158
|
-
|
171
|
+
# Invalid default would cause validation error
|
172
|
+
# optional :priority, default: "invalid", inclusion: { in: %w[low medium high] }
|
173
|
+
# → CMDx::ValidationError: priority invalid is not included in the list
|
174
|
+
```
|
159
175
|
|
160
|
-
|
161
|
-
> Default values are subject to the same validation rules as provided values, ensuring consistency and catching configuration errors early.
|
176
|
+
## Nested Parameter Defaults
|
162
177
|
|
163
178
|
```ruby
|
164
|
-
class
|
165
|
-
|
166
|
-
required :
|
167
|
-
|
168
|
-
# Default must pass inclusion validation
|
169
|
-
optional :priority, type: :string, default: "standard",
|
170
|
-
inclusion: { in: %w[low standard high urgent] }
|
179
|
+
class ProcessPaymentTask < CMDx::Task
|
180
|
+
required :amount, type: :float
|
181
|
+
required :user_id, type: :integer
|
171
182
|
|
172
|
-
#
|
173
|
-
optional :
|
174
|
-
|
183
|
+
# Nested structure with defaults at multiple levels
|
184
|
+
optional :payment_config, type: :hash, default: {} do
|
185
|
+
optional :method, default: "credit_card"
|
186
|
+
optional :currency, default: "USD"
|
187
|
+
optional :require_cvv, type: :boolean, default: true
|
175
188
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
189
|
+
optional :billing_address, type: :hash, default: -> { user_default_address } do
|
190
|
+
optional :country, default: "US"
|
191
|
+
optional :state, default: -> { user_default_state }
|
192
|
+
end
|
180
193
|
|
181
|
-
|
182
|
-
|
183
|
-
|
194
|
+
optional :notification_settings, type: :hash, default: {} do
|
195
|
+
optional :send_receipt, type: :boolean, default: true
|
196
|
+
optional :send_sms, type: :boolean, default: false
|
197
|
+
end
|
198
|
+
end
|
184
199
|
|
185
200
|
def call
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
201
|
+
# Process payment with defaults applied at each level
|
202
|
+
PaymentProcessor.charge(
|
203
|
+
amount: amount,
|
204
|
+
method: payment_config[:method], # "credit_card"
|
205
|
+
currency: payment_config[:currency], # "USD"
|
206
|
+
billing_address: payment_config[:billing_address],
|
207
|
+
notifications: payment_config[:notification_settings]
|
208
|
+
)
|
190
209
|
end
|
191
210
|
|
192
211
|
private
|
193
212
|
|
194
|
-
def
|
195
|
-
|
213
|
+
def user
|
214
|
+
@user ||= User.find(user_id)
|
215
|
+
end
|
216
|
+
|
217
|
+
def user_default_address
|
218
|
+
user.billing_address&.to_hash || {}
|
196
219
|
end
|
197
220
|
|
221
|
+
def user_default_state
|
222
|
+
user.billing_address&.state || "CA"
|
223
|
+
end
|
198
224
|
end
|
225
|
+
|
226
|
+
# Usage with nested defaults
|
227
|
+
ProcessPaymentTask.call(amount: 99.99, user_id: 123)
|
228
|
+
# payment_config automatically gets:
|
229
|
+
# {
|
230
|
+
# method: "credit_card",
|
231
|
+
# currency: "USD",
|
232
|
+
# require_cvv: true,
|
233
|
+
# billing_address: { country: "US", state: "CA" },
|
234
|
+
# notification_settings: { send_receipt: true, send_sms: false }
|
235
|
+
# }
|
199
236
|
```
|
200
237
|
|
201
|
-
##
|
238
|
+
## Error Handling
|
202
239
|
|
203
|
-
|
204
|
-
|
240
|
+
> [!WARNING]
|
241
|
+
> Default values that fail coercion or validation will cause task execution to fail with detailed error information.
|
205
242
|
|
206
|
-
|
243
|
+
### Validation Errors with Defaults
|
207
244
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
245
|
+
```ruby
|
246
|
+
class BadDefaultsTask < CMDx::Task
|
247
|
+
# This default will fail validation
|
248
|
+
optional :priority, default: "invalid",
|
249
|
+
inclusion: { in: %w[low medium high] }
|
213
250
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
251
|
+
# This default will fail coercion
|
252
|
+
optional :count, type: :integer, default: "not-a-number"
|
253
|
+
|
254
|
+
def call
|
255
|
+
# Won't reach here due to validation/coercion failures
|
219
256
|
end
|
257
|
+
end
|
220
258
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
259
|
+
result = BadDefaultsTask.call
|
260
|
+
result.failed? # → true
|
261
|
+
result.metadata
|
262
|
+
# {
|
263
|
+
# reason: "priority invalid is not included in the list. count could not coerce into an integer.",
|
264
|
+
# messages: {
|
265
|
+
# priority: ["invalid is not included in the list"],
|
266
|
+
# count: ["could not coerce into an integer"]
|
267
|
+
# }
|
268
|
+
# }
|
269
|
+
```
|
225
270
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
271
|
+
### Dynamic Default Errors
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
class ProblematicDefaultsTask < CMDx::Task
|
275
|
+
# Method that might raise an error
|
276
|
+
optional :config, default: :load_external_config
|
277
|
+
|
278
|
+
# Proc that might fail
|
279
|
+
optional :api_key, default: -> { fetch_api_key_from_vault }
|
231
280
|
|
232
281
|
def call
|
233
|
-
#
|
234
|
-
shipping_details #=> {} if not provided
|
235
|
-
notification_preferences #=> customer defaults if not provided
|
236
|
-
|
237
|
-
# Child defaults (when parent exists)
|
238
|
-
carrier #=> "fedex"
|
239
|
-
expedited #=> false
|
240
|
-
insurance_required #=> true if order > $500
|
241
|
-
country #=> "US"
|
242
|
-
state #=> determined by logic
|
243
|
-
email_updates #=> true
|
244
|
-
preferred_time #=> "anytime"
|
245
|
-
weekend_delivery #=> false
|
282
|
+
# Task logic
|
246
283
|
end
|
247
284
|
|
248
285
|
private
|
249
286
|
|
250
|
-
def
|
251
|
-
|
287
|
+
def load_external_config
|
288
|
+
# This might raise if external service is down
|
289
|
+
ExternalConfigService.fetch_config
|
290
|
+
rescue => e
|
291
|
+
raise CMDx::Error, "Failed to load default config: #{e.message}"
|
252
292
|
end
|
253
293
|
|
254
|
-
def
|
255
|
-
|
294
|
+
def fetch_api_key_from_vault
|
295
|
+
# This might raise if vault is unavailable
|
296
|
+
VaultService.get_secret("api_key")
|
297
|
+
rescue => e
|
298
|
+
raise CMDx::Error, "Failed to fetch default API key: #{e.message}"
|
256
299
|
end
|
300
|
+
end
|
301
|
+
```
|
257
302
|
|
258
|
-
|
259
|
-
order.customer.default_shipping_address&.to_hash || {}
|
260
|
-
end
|
303
|
+
### Nil vs Missing Parameters
|
261
304
|
|
262
|
-
|
263
|
-
|
264
|
-
|
305
|
+
```ruby
|
306
|
+
class NilHandlingTask < CMDx::Task
|
307
|
+
optional :status, default: "active"
|
308
|
+
optional :tags, type: :array, default: []
|
265
309
|
|
266
|
-
def
|
267
|
-
|
268
|
-
|
269
|
-
email_updates: prefs.email_enabled?,
|
270
|
-
sms_updates: prefs.sms_enabled?
|
271
|
-
}
|
310
|
+
def call
|
311
|
+
status # Default applied based on input
|
312
|
+
tags # Default applied based on input
|
272
313
|
end
|
273
|
-
|
274
314
|
end
|
315
|
+
|
316
|
+
# Missing parameters use defaults
|
317
|
+
NilHandlingTask.call
|
318
|
+
# status: "active", tags: []
|
319
|
+
|
320
|
+
# Explicitly nil parameters also use defaults
|
321
|
+
NilHandlingTask.call(status: nil, tags: nil)
|
322
|
+
# status: "active", tags: []
|
323
|
+
|
324
|
+
# Empty string is NOT nil - no default applied
|
325
|
+
NilHandlingTask.call(status: "", tags: "")
|
326
|
+
# status: "", tags: "" (string, not array - may cause coercion error)
|
275
327
|
```
|
276
328
|
|
329
|
+
> [!TIP]
|
330
|
+
> Defaults only apply to `nil` values. Empty strings, empty arrays, or false values are considered valid inputs and won't trigger defaults.
|
331
|
+
|
277
332
|
---
|
278
333
|
|
279
334
|
- **Prev:** [Parameters - Validations](validations.md)
|