cmdx 1.0.1 → 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 +21 -0
- data/.cursor/prompts/yardoc.md +13 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +29 -3
- data/README.md +2 -1
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +126 -60
- 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 +382 -119
- data/docs/configuration.md +211 -49
- 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 +152 -127
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +183 -120
- data/docs/middlewares.md +165 -392
- 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 +251 -289
- 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 +247 -159
- data/docs/testing.md +196 -203
- data/docs/workflows.md +146 -101
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +39 -55
- data/lib/cmdx/callback_registry.rb +80 -73
- data/lib/cmdx/chain.rb +65 -122
- data/lib/cmdx/chain_inspector.rb +23 -116
- data/lib/cmdx/chain_serializer.rb +34 -146
- data/lib/cmdx/coercion.rb +57 -0
- data/lib/cmdx/coercion_registry.rb +113 -0
- data/lib/cmdx/coercions/array.rb +18 -36
- data/lib/cmdx/coercions/big_decimal.rb +21 -33
- data/lib/cmdx/coercions/boolean.rb +21 -40
- data/lib/cmdx/coercions/complex.rb +18 -31
- data/lib/cmdx/coercions/date.rb +20 -39
- data/lib/cmdx/coercions/date_time.rb +22 -39
- data/lib/cmdx/coercions/float.rb +19 -32
- data/lib/cmdx/coercions/hash.rb +22 -41
- data/lib/cmdx/coercions/integer.rb +20 -33
- data/lib/cmdx/coercions/rational.rb +20 -32
- data/lib/cmdx/coercions/string.rb +23 -31
- data/lib/cmdx/coercions/time.rb +24 -40
- data/lib/cmdx/coercions/virtual.rb +14 -31
- data/lib/cmdx/configuration.rb +101 -162
- data/lib/cmdx/context.rb +34 -166
- data/lib/cmdx/core_ext/hash.rb +42 -67
- data/lib/cmdx/core_ext/module.rb +35 -79
- data/lib/cmdx/core_ext/object.rb +63 -98
- data/lib/cmdx/correlator.rb +59 -154
- data/lib/cmdx/error.rb +37 -202
- data/lib/cmdx/errors.rb +153 -216
- data/lib/cmdx/fault.rb +68 -150
- data/lib/cmdx/faults.rb +26 -137
- data/lib/cmdx/immutator.rb +22 -110
- data/lib/cmdx/lazy_struct.rb +110 -186
- data/lib/cmdx/log_formatters/json.rb +14 -40
- data/lib/cmdx/log_formatters/key_value.rb +14 -40
- data/lib/cmdx/log_formatters/line.rb +14 -48
- data/lib/cmdx/log_formatters/logstash.rb +14 -57
- data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
- data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
- data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
- data/lib/cmdx/log_formatters/raw.rb +19 -49
- data/lib/cmdx/logger.rb +22 -79
- data/lib/cmdx/logger_ansi.rb +31 -72
- data/lib/cmdx/logger_serializer.rb +74 -103
- data/lib/cmdx/middleware.rb +56 -60
- data/lib/cmdx/middleware_registry.rb +82 -77
- data/lib/cmdx/middlewares/correlate.rb +41 -226
- data/lib/cmdx/middlewares/timeout.rb +46 -185
- data/lib/cmdx/parameter.rb +167 -183
- data/lib/cmdx/parameter_evaluator.rb +231 -0
- data/lib/cmdx/parameter_inspector.rb +37 -55
- data/lib/cmdx/parameter_registry.rb +65 -84
- data/lib/cmdx/parameter_serializer.rb +32 -76
- data/lib/cmdx/railtie.rb +24 -107
- data/lib/cmdx/result.rb +254 -259
- data/lib/cmdx/result_ansi.rb +28 -80
- data/lib/cmdx/result_inspector.rb +34 -70
- data/lib/cmdx/result_logger.rb +23 -77
- data/lib/cmdx/result_serializer.rb +59 -125
- data/lib/cmdx/rspec/matchers.rb +28 -0
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
- data/lib/cmdx/task.rb +336 -427
- data/lib/cmdx/task_deprecator.rb +52 -0
- data/lib/cmdx/task_processor.rb +246 -0
- data/lib/cmdx/task_serializer.rb +34 -69
- data/lib/cmdx/utils/ansi_color.rb +13 -89
- data/lib/cmdx/utils/log_timestamp.rb +13 -42
- data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
- data/lib/cmdx/utils/name_affix.rb +21 -71
- data/lib/cmdx/validator.rb +57 -0
- data/lib/cmdx/validator_registry.rb +108 -0
- data/lib/cmdx/validators/exclusion.rb +55 -94
- data/lib/cmdx/validators/format.rb +31 -85
- data/lib/cmdx/validators/inclusion.rb +65 -110
- data/lib/cmdx/validators/length.rb +117 -133
- data/lib/cmdx/validators/numeric.rb +123 -130
- data/lib/cmdx/validators/presence.rb +38 -79
- data/lib/cmdx/version.rb +1 -7
- data/lib/cmdx/workflow.rb +58 -330
- data/lib/cmdx.rb +1 -1
- data/lib/generators/cmdx/install_generator.rb +14 -31
- data/lib/generators/cmdx/task_generator.rb +39 -55
- data/lib/generators/cmdx/templates/install.rb +24 -6
- data/lib/generators/cmdx/workflow_generator.rb +41 -66
- data/lib/locales/ar.yml +0 -1
- data/lib/locales/cs.yml +0 -1
- data/lib/locales/da.yml +0 -1
- data/lib/locales/de.yml +0 -1
- data/lib/locales/el.yml +0 -1
- data/lib/locales/en.yml +0 -1
- data/lib/locales/es.yml +0 -1
- data/lib/locales/fi.yml +0 -1
- data/lib/locales/fr.yml +0 -1
- data/lib/locales/he.yml +0 -1
- data/lib/locales/hi.yml +0 -1
- data/lib/locales/it.yml +0 -1
- data/lib/locales/ja.yml +0 -1
- data/lib/locales/ko.yml +0 -1
- data/lib/locales/nl.yml +0 -1
- data/lib/locales/no.yml +0 -1
- data/lib/locales/pl.yml +0 -1
- data/lib/locales/pt.yml +0 -1
- data/lib/locales/ru.yml +0 -1
- data/lib/locales/sv.yml +0 -1
- data/lib/locales/th.yml +0 -1
- data/lib/locales/tr.yml +0 -1
- data/lib/locales/vi.yml +0 -1
- data/lib/locales/zh.yml +0 -1
- metadata +36 -8
- data/lib/cmdx/parameter_validator.rb +0 -81
- data/lib/cmdx/parameter_value.rb +0 -244
- data/lib/cmdx/parameters_inspector.rb +0 -72
- data/lib/cmdx/parameters_serializer.rb +0 -115
- data/lib/cmdx/rspec/result_matchers.rb +0 -917
- data/lib/cmdx/rspec/task_matchers.rb +0 -570
- data/lib/cmdx/validators/custom.rb +0 -102
data/lib/cmdx/correlator.rb
CHANGED
@@ -1,205 +1,110 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
|
5
|
-
# Thread-safe correlation ID management for tracking related operations across request boundaries.
|
4
|
+
# Thread-safe correlation ID management for distributed tracing and request tracking.
|
6
5
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# Correlation IDs are automatically used by CMDx runs when available, providing seamless
|
12
|
-
# request tracking without requiring explicit parameter passing between tasks.
|
13
|
-
#
|
14
|
-
# ## Thread Safety
|
15
|
-
#
|
16
|
-
# All correlation operations are thread-local, ensuring that different threads maintain
|
17
|
-
# separate correlation contexts without interference. This is essential for concurrent
|
18
|
-
# request processing in multi-threaded applications.
|
19
|
-
#
|
20
|
-
# ## Integration with CMDx Runs
|
21
|
-
#
|
22
|
-
# When a new CMDx::Chain is created, it automatically uses the current thread's correlation
|
23
|
-
# ID as its chain identifier if available, falling back to UUID generation if none exists.
|
24
|
-
#
|
25
|
-
# @example Basic correlation usage
|
26
|
-
# CMDx::Correlator.id = "req-12345"
|
27
|
-
# CMDx::Correlator.id # => "req-12345"
|
28
|
-
#
|
29
|
-
# # Chain automatically inherits correlation ID
|
30
|
-
# result = ProcessOrderTask.call(order_id: 123)
|
31
|
-
# result.chain.id # => "req-12345"
|
32
|
-
#
|
33
|
-
# @example Block-based correlation context
|
34
|
-
# CMDx::Correlator.use("workflow-operation-456") do
|
35
|
-
# # All tasks within this block share the same correlation
|
36
|
-
# ProcessOrderTask.call(order_id: 123)
|
37
|
-
# SendEmailTask.call(user_id: 456)
|
38
|
-
# end
|
39
|
-
# # Correlation context is automatically restored
|
40
|
-
#
|
41
|
-
# @example Nested correlation contexts
|
42
|
-
# CMDx::Correlator.use("parent-operation") do
|
43
|
-
# CMDx::Correlator.use("child-operation") do
|
44
|
-
# ProcessOrderTask.call(order_id: 123)
|
45
|
-
# # Uses "child-operation" as correlation ID
|
46
|
-
# end
|
47
|
-
# # Restored to "parent-operation"
|
48
|
-
# SendEmailTask.call(user_id: 456)
|
49
|
-
# end
|
50
|
-
#
|
51
|
-
# @example Manual correlation management
|
52
|
-
# # Set correlation ID for current thread
|
53
|
-
# CMDx::Correlator.id = "manual-correlation"
|
54
|
-
#
|
55
|
-
# # Check current correlation
|
56
|
-
# current_id = CMDx::Correlator.id
|
57
|
-
#
|
58
|
-
# # Clear correlation when done
|
59
|
-
# CMDx::Correlator.clear
|
60
|
-
#
|
61
|
-
# @example Middleware integration pattern
|
62
|
-
# class CorrelationMiddleware
|
63
|
-
# def call(env)
|
64
|
-
# correlation_id = env['HTTP_X_CORRELATION_ID'] || CMDx::Correlator.generate
|
65
|
-
#
|
66
|
-
# CMDx::Correlator.use(correlation_id) do
|
67
|
-
# @app.call(env)
|
68
|
-
# end
|
69
|
-
# end
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# @see CMDx::Chain Chain execution context that inherits correlation IDs
|
73
|
-
# @since 1.0.0
|
6
|
+
# Correlator provides functionality to generate, store, and manage correlation IDs
|
7
|
+
# across thread boundaries for request tracing, logging correlation, and distributed
|
8
|
+
# system monitoring. Correlation IDs are stored in thread-local storage to ensure
|
9
|
+
# thread safety and isolation between concurrent operations.
|
74
10
|
module Correlator
|
75
11
|
|
76
|
-
##
|
77
|
-
# Thread-local storage key for correlation identifiers.
|
78
|
-
#
|
79
|
-
# Uses a Symbol key to avoid potential conflicts with other thread-local
|
80
|
-
# variables and to ensure consistent access across the correlator methods.
|
81
|
-
#
|
82
|
-
# @return [Symbol] the thread-local storage key
|
83
12
|
THREAD_KEY = :cmdx_correlation_id
|
84
13
|
|
85
14
|
module_function
|
86
15
|
|
87
|
-
|
88
|
-
# Generates a new UUID suitable for use as a correlation identifier.
|
16
|
+
# Generates a new correlation ID using the best available UUID algorithm.
|
89
17
|
#
|
90
|
-
#
|
91
|
-
#
|
18
|
+
# Attempts to use UUID v7 (time-ordered) if available in Ruby 3.3+, otherwise
|
19
|
+
# falls back to standard UUID v4. UUID v7 provides better database indexing
|
20
|
+
# performance and natural time-based ordering for correlation tracking.
|
92
21
|
#
|
93
|
-
# @return [String] a new UUID
|
22
|
+
# @return [String] a new UUID correlation ID
|
94
23
|
#
|
95
|
-
# @example
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
24
|
+
# @example Generate a correlation ID
|
25
|
+
# Correlator.generate #=> "01234567-89ab-7def-0123-456789abcdef"
|
26
|
+
#
|
27
|
+
# @example Using the generated ID for logging
|
28
|
+
# correlation_id = Correlator.generate
|
29
|
+
# logger.info "Request started", correlation_id: correlation_id
|
99
30
|
def generate
|
31
|
+
return SecureRandom.uuid_v7 if SecureRandom.respond_to?(:uuid_v7)
|
32
|
+
|
100
33
|
SecureRandom.uuid
|
101
34
|
end
|
102
35
|
|
103
|
-
|
104
|
-
# Retrieves the current thread's correlation identifier.
|
105
|
-
#
|
106
|
-
# Returns the correlation ID that was previously set for the current thread,
|
107
|
-
# or nil if no correlation ID has been established. This method is thread-safe
|
108
|
-
# and will not interfere with correlation IDs set in other threads.
|
36
|
+
# Retrieves the current correlation ID for the active thread.
|
109
37
|
#
|
110
|
-
#
|
38
|
+
# Returns the correlation ID that has been set for the current thread's
|
39
|
+
# execution context. Returns nil if no correlation ID has been established
|
40
|
+
# for the current thread.
|
111
41
|
#
|
112
|
-
# @
|
113
|
-
# CMDx::Correlator.id # => nil (when none is set)
|
42
|
+
# @return [String, nil] the current thread's correlation ID, or nil if not set
|
114
43
|
#
|
115
|
-
#
|
116
|
-
#
|
44
|
+
# @example Get current correlation ID
|
45
|
+
# Correlator.id #=> "01234567-89ab-7def-0123-456789abcdef"
|
117
46
|
def id
|
118
47
|
Thread.current[THREAD_KEY]
|
119
48
|
end
|
120
49
|
|
121
|
-
|
122
|
-
# Sets the correlation identifier for the current thread.
|
50
|
+
# Sets the correlation ID for the current thread.
|
123
51
|
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
52
|
+
# Establishes a correlation ID in thread-local storage that will be
|
53
|
+
# accessible to all operations within the current thread's execution
|
54
|
+
# context. This ID will persist until explicitly changed or cleared.
|
127
55
|
#
|
128
|
-
# @param value [String,
|
129
|
-
# @return [String] the assigned correlation identifier
|
56
|
+
# @param value [String, Symbol] the correlation ID to set for this thread
|
130
57
|
#
|
131
|
-
# @
|
132
|
-
# CMDx::Correlator.id = "user-request-123"
|
133
|
-
# CMDx::Correlator.id # => "user-request-123"
|
58
|
+
# @return [String, Symbol] the assigned correlation ID value
|
134
59
|
#
|
135
|
-
# @example
|
136
|
-
#
|
137
|
-
#
|
60
|
+
# @example Set a custom correlation ID
|
61
|
+
# Correlator.id = "custom-trace-123"
|
62
|
+
#
|
63
|
+
# @example Set a generated correlation ID
|
64
|
+
# Correlator.id = Correlator.generate
|
138
65
|
def id=(value)
|
139
66
|
Thread.current[THREAD_KEY] = value
|
140
67
|
end
|
141
68
|
|
142
|
-
|
143
|
-
# Clears the correlation identifier for the current thread.
|
144
|
-
#
|
145
|
-
# Removes the correlation ID from the current thread's local storage,
|
146
|
-
# effectively resetting the correlation context. Subsequent calls to
|
147
|
-
# {#id} will return nil until a new correlation ID is set.
|
69
|
+
# Clears the correlation ID for the current thread.
|
148
70
|
#
|
149
|
-
#
|
71
|
+
# Removes the correlation ID from thread-local storage, effectively
|
72
|
+
# resetting the correlation context for the current thread. Useful
|
73
|
+
# for cleanup between request processing or test scenarios.
|
150
74
|
#
|
151
|
-
# @
|
152
|
-
# CMDx::Correlator.id = "temporary-correlation"
|
153
|
-
# CMDx::Correlator.id # => "temporary-correlation"
|
75
|
+
# @return [nil] always returns nil after clearing
|
154
76
|
#
|
155
|
-
#
|
156
|
-
#
|
77
|
+
# @example Clear correlation ID
|
78
|
+
# Correlator.clear
|
79
|
+
# Correlator.id #=> nil
|
157
80
|
def clear
|
158
81
|
Thread.current[THREAD_KEY] = nil
|
159
82
|
end
|
160
83
|
|
161
|
-
|
162
|
-
# Temporarily sets a correlation identifier for the duration of a block.
|
84
|
+
# Temporarily sets a correlation ID for the duration of a block execution.
|
163
85
|
#
|
164
|
-
# Establishes a correlation context for the
|
165
|
-
# restoring the previous correlation ID when the block completes. This
|
166
|
-
#
|
167
|
-
# if the block raises an error.
|
86
|
+
# Establishes a correlation ID context for the provided block, automatically
|
87
|
+
# restoring the previous correlation ID when the block completes. This ensures
|
88
|
+
# proper correlation ID isolation for nested operations or temporary contexts.
|
168
89
|
#
|
169
|
-
#
|
170
|
-
# ensures proper cleanup and supports nested correlation scopes.
|
90
|
+
# @param value [String, Symbol] the temporary correlation ID to use during block execution
|
171
91
|
#
|
172
|
-
# @param value [String, #to_s] the correlation identifier to use during block execution
|
173
|
-
# @yieldreturn [Object] the return value of the block
|
174
92
|
# @return [Object] the return value of the executed block
|
175
93
|
#
|
176
|
-
# @
|
177
|
-
# result = CMDx::Correlator.use("operation-123") do
|
178
|
-
# ProcessOrderTask.call(order_id: 456)
|
179
|
-
# end
|
180
|
-
# # Correlation context is automatically restored
|
181
|
-
#
|
182
|
-
# @example Nested contexts
|
183
|
-
# CMDx::Correlator.use("parent") do
|
184
|
-
# CMDx::Correlator.id # => "parent"
|
185
|
-
#
|
186
|
-
# CMDx::Correlator.use("child") do
|
187
|
-
# CMDx::Correlator.id # => "child"
|
188
|
-
# end
|
94
|
+
# @raise [TypeError] if the provided value is not a String or Symbol
|
189
95
|
#
|
190
|
-
#
|
96
|
+
# @example Use temporary correlation ID
|
97
|
+
# Correlator.use("temp-id-123") do
|
98
|
+
# logger.info "Processing with temporary ID"
|
99
|
+
# perform_operation
|
191
100
|
# end
|
192
101
|
#
|
193
|
-
# @example
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
# CMDx::Correlator.use("temporary") do
|
198
|
-
# raise StandardError, "something went wrong"
|
199
|
-
# end
|
200
|
-
# rescue StandardError
|
201
|
-
# CMDx::Correlator.id # => "original" (still restored)
|
102
|
+
# @example Nested correlation contexts
|
103
|
+
# Correlator.id = "parent-id"
|
104
|
+
# Correlator.use("child-id") do
|
105
|
+
# puts Correlator.id #=> "child-id"
|
202
106
|
# end
|
107
|
+
# puts Correlator.id #=> "parent-id"
|
203
108
|
def use(value)
|
204
109
|
unless value.is_a?(String) || value.is_a?(Symbol)
|
205
110
|
raise TypeError,
|
data/lib/cmdx/error.rb
CHANGED
@@ -2,224 +2,59 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
|
5
|
-
|
6
|
-
# Base exception class for all CMDx-specific errors.
|
7
|
-
# All other CMDx exceptions inherit from this class, providing a common
|
8
|
-
# hierarchy for error handling and rescue operations.
|
5
|
+
# Base exception class for all CMDx-related errors.
|
9
6
|
#
|
10
|
-
# This
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# @example Catching all CMDx errors
|
14
|
-
# begin
|
15
|
-
# ProcessOrderTask.call(invalid_params)
|
16
|
-
# rescue CMDx::Error => e
|
17
|
-
# logger.error "CMDx error occurred: #{e.message}"
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# @example Specific error handling
|
21
|
-
# begin
|
22
|
-
# ProcessOrderTask.call(order_id: "invalid")
|
23
|
-
# rescue CMDx::CoercionError => e
|
24
|
-
# # Handle type coercion failures
|
25
|
-
# rescue CMDx::ValidationError => e
|
26
|
-
# # Handle validation failures
|
27
|
-
# rescue CMDx::Error => e
|
28
|
-
# # Handle any other CMDx errors
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# @see StandardError Ruby's standard error base class
|
32
|
-
# @since 1.0.0
|
7
|
+
# This serves as the root exception class for all errors raised by the CMDx
|
8
|
+
# framework. It inherits from StandardError and provides a common base for
|
9
|
+
# handling CMDx-specific exceptions.
|
33
10
|
Error = Class.new(StandardError)
|
34
11
|
|
35
|
-
|
36
|
-
# Raised when a value cannot be coerced to the specified type.
|
37
|
-
# This exception occurs during parameter processing when type coercion fails,
|
38
|
-
# typically due to incompatible data formats or invalid input values.
|
39
|
-
#
|
40
|
-
# CoercionError is raised by the various coercion modules when they encounter
|
41
|
-
# values that cannot be converted to the target type. Each coercion module
|
42
|
-
# provides specific error messages indicating the expected type and the
|
43
|
-
# problematic value.
|
44
|
-
#
|
45
|
-
# @example Integer coercion failure
|
46
|
-
# class MyTask < CMDx::Task
|
47
|
-
# required :count, type: :integer
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# # This will raise CoercionError during parameter processing
|
51
|
-
# MyTask.call(count: "not_a_number")
|
52
|
-
# # => CMDx::CoercionError: could not coerce into an integer
|
53
|
-
#
|
54
|
-
# @example Date coercion failure
|
55
|
-
# class ScheduleTask < CMDx::Task
|
56
|
-
# required :due_date, type: :date
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# ScheduleTask.call(due_date: "invalid_date")
|
60
|
-
# # => CMDx::CoercionError: could not coerce into a date
|
12
|
+
# Raised when parameter coercion fails during task execution.
|
61
13
|
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# rescue CMDx::CoercionError => e
|
66
|
-
# # Log the coercion failure and provide user-friendly message
|
67
|
-
# logger.warn "Invalid input format: #{e.message}"
|
68
|
-
# render json: { error: "Please provide a valid number" }
|
69
|
-
# end
|
70
|
-
#
|
71
|
-
# @see Parameter Parameter type definitions and coercion
|
72
|
-
# @see ParameterValue Parameter value processing and coercion
|
73
|
-
# @since 1.0.0
|
14
|
+
# This error occurs when a parameter value cannot be converted to the expected
|
15
|
+
# type using the registered coercion handlers. It indicates that the provided
|
16
|
+
# value is incompatible with the parameter's defined type.
|
74
17
|
CoercionError = Class.new(Error)
|
75
18
|
|
76
|
-
|
77
|
-
# Raised when a task class doesn't implement the required `call` method.
|
78
|
-
# This exception enforces the CMDx contract that all task classes must
|
79
|
-
# provide a `call` method containing their business logic.
|
80
|
-
#
|
81
|
-
# This error typically occurs during development when creating new task
|
82
|
-
# classes that inherit from CMDx::Task but forget to implement the
|
83
|
-
# abstract `call` method.
|
84
|
-
#
|
85
|
-
# @example Missing call method
|
86
|
-
# class IncompleteTask < CMDx::Task
|
87
|
-
# required :data, type: :string
|
88
|
-
# # Missing call method implementation
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# IncompleteTask.call(data: "test")
|
92
|
-
# # => CMDx::UndefinedCallError: call method not defined in IncompleteTask
|
19
|
+
# Raised when a deprecated task is used.
|
93
20
|
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
#
|
99
|
-
# # Business logic implementation
|
100
|
-
# context.result = process(data)
|
101
|
-
# end
|
102
|
-
# end
|
103
|
-
#
|
104
|
-
# @example Handling undefined call errors
|
105
|
-
# begin
|
106
|
-
# SomeTask.call(params)
|
107
|
-
# rescue CMDx::UndefinedCallError => e
|
108
|
-
# # This should typically only happen during development
|
109
|
-
# logger.error "Task implementation incomplete: #{e.message}"
|
110
|
-
# raise # Re-raise as this is a programming error
|
111
|
-
# end
|
21
|
+
# This error occurs when a deprecated task is called. It indicates that the
|
22
|
+
# task is no longer supported and should be replaced with a newer alternative.
|
23
|
+
DeprecationError = Class.new(Error)
|
24
|
+
|
25
|
+
# Raised when an abstract method is called without being implemented.
|
112
26
|
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
27
|
+
# This error occurs when a subclass fails to implement required abstract methods
|
28
|
+
# such as call methods in validators, callbacks, or middleware. It indicates
|
29
|
+
# incomplete implementation of required functionality.
|
116
30
|
UndefinedCallError = Class.new(Error)
|
117
31
|
|
118
|
-
|
119
|
-
# Raised when an unknown or unsupported coercion type is specified.
|
120
|
-
# This exception occurs when parameter definitions reference type coercions
|
121
|
-
# that don't exist or aren't registered in the CMDx coercion system.
|
122
|
-
#
|
123
|
-
# This error helps catch typos in type specifications and ensures that
|
124
|
-
# only supported data types are used in parameter definitions.
|
32
|
+
# Raised when attempting to use an unregistered callback.
|
125
33
|
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
|
130
|
-
|
131
|
-
#
|
132
|
-
# # => CMDx::UnknownCoercionError: unknown coercion unknown_type
|
133
|
-
#
|
134
|
-
# @example Common typos
|
135
|
-
# class TaskWithTypo < CMDx::Task
|
136
|
-
# required :count, type: :integr # Should be :integer
|
137
|
-
# required :flag, type: :bool # Should be :boolean
|
138
|
-
# required :data, type: :json # Should be :hash
|
139
|
-
# end
|
140
|
-
#
|
141
|
-
# @example Supported types
|
142
|
-
# class ProperTask < CMDx::Task
|
143
|
-
# required :id, type: :integer
|
144
|
-
# required :active, type: :boolean
|
145
|
-
# required :metadata, type: :hash
|
146
|
-
# required :tags, type: :array
|
147
|
-
# required :name, type: :string
|
148
|
-
# required :score, type: :float
|
149
|
-
# required :created_at, type: :date_time
|
150
|
-
# end
|
151
|
-
#
|
152
|
-
# @example Handling unknown coercion errors
|
153
|
-
# begin
|
154
|
-
# MyTask.call(params)
|
155
|
-
# rescue CMDx::UnknownCoercionError => e
|
156
|
-
# # This indicates a programming error in parameter definition
|
157
|
-
# logger.error "Invalid type specification: #{e.message}"
|
158
|
-
# raise # Re-raise as this should be fixed in code
|
159
|
-
# end
|
34
|
+
# This error occurs when trying to reference a callback that hasn't been
|
35
|
+
# registered in the callback registry. It indicates that the callback name
|
36
|
+
# is not recognized or was misspelled.
|
37
|
+
UnknownCallbackError = Class.new(Error)
|
38
|
+
|
39
|
+
# Raised when attempting to use an unregistered coercion type.
|
160
40
|
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
41
|
+
# This error occurs when trying to use a parameter type that doesn't have
|
42
|
+
# a corresponding coercion handler registered. It indicates that the specified
|
43
|
+
# type is not supported by the coercion system.
|
164
44
|
UnknownCoercionError = Class.new(Error)
|
165
45
|
|
166
|
-
|
167
|
-
# Raised when a parameter value fails validation rules.
|
168
|
-
# This exception occurs during parameter processing when values don't meet
|
169
|
-
# the specified validation criteria, such as format requirements, length
|
170
|
-
# constraints, or custom validation logic.
|
171
|
-
#
|
172
|
-
# ValidationError provides detailed feedback about why validation failed,
|
173
|
-
# helping developers and users understand what corrections are needed.
|
174
|
-
#
|
175
|
-
# @example Presence validation failure
|
176
|
-
# class CreateUserTask < CMDx::Task
|
177
|
-
# required :email, type: :string, presence: true
|
178
|
-
# end
|
179
|
-
#
|
180
|
-
# CreateUserTask.call(email: "")
|
181
|
-
# # => CMDx::ValidationError: cannot be empty
|
46
|
+
# Raised when attempting to use an unregistered validator.
|
182
47
|
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
|
187
|
-
|
188
|
-
#
|
189
|
-
# # => CMDx::ValidationError: is an invalid format
|
190
|
-
#
|
191
|
-
# @example Length validation failure
|
192
|
-
# class SetPasswordTask < CMDx::Task
|
193
|
-
# required :password, type: :string, length: { min: 8 }
|
194
|
-
# end
|
195
|
-
#
|
196
|
-
# SetPasswordTask.call(password: "short")
|
197
|
-
# # => CMDx::ValidationError: length must be at least 8
|
198
|
-
#
|
199
|
-
# @example Custom validation failure
|
200
|
-
# class ProcessOrderTask < CMDx::Task
|
201
|
-
# required :quantity, type: :integer, custom: -> (val) { val > 0 }
|
202
|
-
# end
|
203
|
-
#
|
204
|
-
# ProcessOrderTask.call(quantity: -1)
|
205
|
-
# # => CMDx::ValidationError: is not valid
|
206
|
-
#
|
207
|
-
# @example Handling validation errors
|
208
|
-
# begin
|
209
|
-
# CreateUserTask.call(email: "", password: "short")
|
210
|
-
# rescue CMDx::ValidationError => e
|
211
|
-
# # Provide user-friendly feedback
|
212
|
-
# render json: {
|
213
|
-
# error: "Validation failed",
|
214
|
-
# message: e.message,
|
215
|
-
# field: extract_field_from_context(e)
|
216
|
-
# }
|
217
|
-
# end
|
48
|
+
# This error occurs when trying to reference a validator that hasn't been
|
49
|
+
# registered in the validator registry. It indicates that the validator name
|
50
|
+
# is not recognized or was misspelled.
|
51
|
+
UnknownValidatorError = Class.new(Error)
|
52
|
+
|
53
|
+
# Raised when parameter validation fails during task execution.
|
218
54
|
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
# @since 1.0.0
|
55
|
+
# This error occurs when a parameter value doesn't meet the validation criteria
|
56
|
+
# defined by the validator. It indicates that the provided value violates
|
57
|
+
# business rules or data integrity constraints.
|
223
58
|
ValidationError = Class.new(Error)
|
224
59
|
|
225
60
|
end
|