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/lib/cmdx/correlator.rb
CHANGED
@@ -1,89 +1,110 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Thread-
|
4
|
+
# Thread-safe correlation ID management for distributed tracing and request tracking.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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.
|
9
10
|
module Correlator
|
10
11
|
|
11
12
|
THREAD_KEY = :cmdx_correlation_id
|
12
13
|
|
13
14
|
module_function
|
14
15
|
|
15
|
-
# Generates a new
|
16
|
-
# Prefers UUID v7 when available, falls back to UUID v4.
|
16
|
+
# Generates a new correlation ID using the best available UUID algorithm.
|
17
17
|
#
|
18
|
-
#
|
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.
|
19
21
|
#
|
20
|
-
# @
|
21
|
-
#
|
22
|
+
# @return [String] a new UUID correlation ID
|
23
|
+
#
|
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
|
22
30
|
def generate
|
23
31
|
return SecureRandom.uuid_v7 if SecureRandom.respond_to?(:uuid_v7)
|
24
32
|
|
25
33
|
SecureRandom.uuid
|
26
34
|
end
|
27
35
|
|
28
|
-
# Retrieves the current
|
36
|
+
# Retrieves the current correlation ID for the active thread.
|
29
37
|
#
|
30
|
-
#
|
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.
|
31
41
|
#
|
32
|
-
# @
|
33
|
-
# CMDx::Correlator.id #=> "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
42
|
+
# @return [String, nil] the current thread's correlation ID, or nil if not set
|
34
43
|
#
|
35
|
-
# @example
|
36
|
-
#
|
44
|
+
# @example Get current correlation ID
|
45
|
+
# Correlator.id #=> "01234567-89ab-7def-0123-456789abcdef"
|
37
46
|
def id
|
38
47
|
Thread.current[THREAD_KEY]
|
39
48
|
end
|
40
49
|
|
41
|
-
# Sets the current thread
|
50
|
+
# Sets the correlation ID for the current thread.
|
42
51
|
#
|
43
|
-
#
|
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.
|
44
55
|
#
|
45
|
-
# @
|
56
|
+
# @param value [String, Symbol] the correlation ID to set for this thread
|
46
57
|
#
|
47
|
-
# @
|
48
|
-
#
|
49
|
-
#
|
58
|
+
# @return [String, Symbol] the assigned correlation ID value
|
59
|
+
#
|
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
|
50
65
|
def id=(value)
|
51
66
|
Thread.current[THREAD_KEY] = value
|
52
67
|
end
|
53
68
|
|
54
|
-
# Clears the current thread
|
69
|
+
# Clears the correlation ID for the current thread.
|
55
70
|
#
|
56
|
-
#
|
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.
|
74
|
+
#
|
75
|
+
# @return [nil] always returns nil after clearing
|
57
76
|
#
|
58
77
|
# @example Clear correlation ID
|
59
|
-
#
|
60
|
-
#
|
78
|
+
# Correlator.clear
|
79
|
+
# Correlator.id #=> nil
|
61
80
|
def clear
|
62
81
|
Thread.current[THREAD_KEY] = nil
|
63
82
|
end
|
64
83
|
|
65
|
-
# Temporarily
|
66
|
-
#
|
84
|
+
# Temporarily sets a correlation ID for the duration of a block execution.
|
85
|
+
#
|
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.
|
67
89
|
#
|
68
|
-
# @param value [String, Symbol] the correlation ID to use during block execution
|
90
|
+
# @param value [String, Symbol] the temporary correlation ID to use during block execution
|
69
91
|
#
|
70
|
-
# @return [Object] the
|
92
|
+
# @return [Object] the return value of the executed block
|
71
93
|
#
|
72
|
-
# @raise [TypeError] if value is not a String or Symbol
|
94
|
+
# @raise [TypeError] if the provided value is not a String or Symbol
|
73
95
|
#
|
74
96
|
# @example Use temporary correlation ID
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
97
|
+
# Correlator.use("temp-id-123") do
|
98
|
+
# logger.info "Processing with temporary ID"
|
99
|
+
# perform_operation
|
78
100
|
# end
|
79
|
-
# # Previous correlation ID is restored
|
80
101
|
#
|
81
|
-
# @example
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
102
|
+
# @example Nested correlation contexts
|
103
|
+
# Correlator.id = "parent-id"
|
104
|
+
# Correlator.use("child-id") do
|
105
|
+
# puts Correlator.id #=> "child-id"
|
85
106
|
# end
|
86
|
-
#
|
107
|
+
# puts Correlator.id #=> "parent-id"
|
87
108
|
def use(value)
|
88
109
|
unless value.is_a?(String) || value.is_a?(Symbol)
|
89
110
|
raise TypeError,
|
data/lib/cmdx/errors.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# providing a flexible API for adding, querying, and formatting validation
|
8
|
-
# errors. It supports both individual error messages and collections of
|
9
|
-
# errors per attribute, with various convenience methods for error handling
|
10
|
-
# and display.
|
4
|
+
# Container for collecting and managing validation and execution errors by attribute.
|
5
|
+
# Provides a comprehensive API for adding, querying, and formatting error messages
|
6
|
+
# with support for multiple errors per attribute and various output formats.
|
11
7
|
class Errors
|
12
8
|
|
13
9
|
cmdx_attr_delegator :clear, :delete, :empty?, :key?, :keys, :size, :values,
|
@@ -31,42 +27,34 @@ module CMDx
|
|
31
27
|
# Alias for {#key?}. Checks if an attribute has error messages.
|
32
28
|
alias include? key?
|
33
29
|
|
34
|
-
# Creates a new
|
30
|
+
# Creates a new empty errors collection.
|
35
31
|
#
|
36
|
-
# @return [Errors]
|
32
|
+
# @return [Errors] a new errors instance with empty internal hash
|
37
33
|
#
|
38
|
-
# @example Create
|
34
|
+
# @example Create new errors collection
|
39
35
|
# errors = CMDx::Errors.new
|
40
36
|
# errors.empty? # => true
|
41
37
|
def initialize
|
42
38
|
@errors = {}
|
43
39
|
end
|
44
40
|
|
45
|
-
# Adds an error message to the specified attribute.
|
46
|
-
#
|
47
|
-
# If the attribute already has errors, the new message is appended to the
|
48
|
-
# existing array. Duplicate messages are automatically removed to ensure
|
49
|
-
# each error message appears only once per attribute.
|
41
|
+
# Adds an error message to the specified attribute. Automatically handles
|
42
|
+
# array initialization and prevents duplicate messages for the same attribute.
|
50
43
|
#
|
51
44
|
# @param key [Symbol, String] the attribute name to associate the error with
|
52
|
-
# @param value [String] the error message to add
|
45
|
+
# @param value [String, Object] the error message or error object to add
|
53
46
|
#
|
54
|
-
# @return [Array
|
47
|
+
# @return [Array] the updated array of error messages for the attribute
|
55
48
|
#
|
56
|
-
# @example Add
|
57
|
-
# errors
|
58
|
-
# errors.add(:name, "is
|
59
|
-
# errors
|
60
|
-
#
|
61
|
-
# @example
|
62
|
-
# errors.add(:email, "is
|
63
|
-
# errors.add(:email, "
|
64
|
-
# errors
|
65
|
-
#
|
66
|
-
# @example Duplicate errors are automatically removed
|
67
|
-
# errors.add(:age, "must be positive")
|
68
|
-
# errors.add(:age, "must be positive")
|
69
|
-
# errors[:age] # => ["must be positive"]
|
49
|
+
# @example Add error to attribute
|
50
|
+
# errors.add(:name, "can't be blank")
|
51
|
+
# errors.add(:name, "is too short")
|
52
|
+
# errors.messages_for(:name) # => ["can't be blank", "is too short"]
|
53
|
+
#
|
54
|
+
# @example Prevent duplicate errors
|
55
|
+
# errors.add(:email, "is invalid")
|
56
|
+
# errors.add(:email, "is invalid")
|
57
|
+
# errors.messages_for(:email) # => ["is invalid"]
|
70
58
|
def add(key, value)
|
71
59
|
errors[key] ||= []
|
72
60
|
errors[key] << value
|
@@ -77,18 +65,17 @@ module CMDx
|
|
77
65
|
# Checks if a specific error message has been added to an attribute.
|
78
66
|
#
|
79
67
|
# @param key [Symbol, String] the attribute name to check
|
80
|
-
# @param val [String] the error message to look for
|
68
|
+
# @param val [String, Object] the error message to look for
|
81
69
|
#
|
82
|
-
# @return [Boolean] true if the
|
70
|
+
# @return [Boolean] true if the error exists for the attribute, false otherwise
|
83
71
|
#
|
84
|
-
# @example Check
|
85
|
-
# errors
|
86
|
-
# errors.
|
87
|
-
# errors.added?(:name, "is required") # => true
|
72
|
+
# @example Check for specific error
|
73
|
+
# errors.add(:name, "can't be blank")
|
74
|
+
# errors.added?(:name, "can't be blank") # => true
|
88
75
|
# errors.added?(:name, "is invalid") # => false
|
89
76
|
#
|
90
|
-
# @example Check
|
91
|
-
# errors.added?(:
|
77
|
+
# @example Check non-existent attribute
|
78
|
+
# errors.added?(:nonexistent, "error") # => false
|
92
79
|
def added?(key, val)
|
93
80
|
return false unless key?(key)
|
94
81
|
|
@@ -96,19 +83,20 @@ module CMDx
|
|
96
83
|
end
|
97
84
|
alias of_kind? added?
|
98
85
|
|
99
|
-
# Iterates over
|
86
|
+
# Iterates over each error, yielding the attribute name and error message.
|
100
87
|
#
|
101
|
-
# @yield [
|
88
|
+
# @yield [key, value] gives the attribute name and error message for each error
|
89
|
+
# @yieldparam key [Symbol, String] the attribute name
|
90
|
+
# @yieldparam value [String, Object] the error message
|
102
91
|
#
|
103
|
-
# @return [
|
92
|
+
# @return [Hash] the errors hash when no block given
|
104
93
|
#
|
105
94
|
# @example Iterate over all errors
|
106
|
-
# errors
|
107
|
-
# errors.add(:name, "is required")
|
95
|
+
# errors.add(:name, "can't be blank")
|
108
96
|
# errors.add(:email, "is invalid")
|
109
97
|
# errors.each { |attr, msg| puts "#{attr}: #{msg}" }
|
110
98
|
# # Output:
|
111
|
-
# # name:
|
99
|
+
# # name: can't be blank
|
112
100
|
# # email: is invalid
|
113
101
|
def each
|
114
102
|
errors.each_key do |key|
|
@@ -116,35 +104,30 @@ module CMDx
|
|
116
104
|
end
|
117
105
|
end
|
118
106
|
|
119
|
-
# Formats an
|
107
|
+
# Formats an error message by combining the attribute name and error value.
|
120
108
|
#
|
121
109
|
# @param key [Symbol, String] the attribute name
|
122
|
-
# @param value [String] the error message
|
110
|
+
# @param value [String, Object] the error message
|
123
111
|
#
|
124
112
|
# @return [String] the formatted full error message
|
125
113
|
#
|
126
|
-
# @example Format
|
127
|
-
# errors
|
128
|
-
# errors.full_message(:
|
129
|
-
#
|
130
|
-
# @example Format with different attribute types
|
131
|
-
# errors.full_message("email", "must be valid") # => "email must be valid"
|
114
|
+
# @example Format error message
|
115
|
+
# errors.full_message(:name, "can't be blank") # => "name can't be blank"
|
116
|
+
# errors.full_message(:email, "is invalid") # => "email is invalid"
|
132
117
|
def full_message(key, value)
|
133
118
|
"#{key} #{value}"
|
134
119
|
end
|
135
120
|
|
136
|
-
# Returns
|
121
|
+
# Returns all error messages formatted with their attribute names.
|
137
122
|
#
|
138
123
|
# @return [Array<String>] array of formatted error messages
|
139
124
|
#
|
140
|
-
# @example Get all
|
141
|
-
# errors
|
142
|
-
# errors.add(:name, "is required")
|
125
|
+
# @example Get all formatted messages
|
126
|
+
# errors.add(:name, "can't be blank")
|
143
127
|
# errors.add(:email, "is invalid")
|
144
|
-
# errors.full_messages # => ["name
|
128
|
+
# errors.full_messages # => ["name can't be blank", "email is invalid"]
|
145
129
|
#
|
146
|
-
# @example Empty errors
|
147
|
-
# errors = CMDx::Errors.new
|
130
|
+
# @example Empty errors collection
|
148
131
|
# errors.full_messages # => []
|
149
132
|
def full_messages
|
150
133
|
errors.each_with_object([]) do |(key, arr), memo|
|
@@ -153,89 +136,80 @@ module CMDx
|
|
153
136
|
end
|
154
137
|
alias to_a full_messages
|
155
138
|
|
156
|
-
# Returns
|
139
|
+
# Returns formatted error messages for a specific attribute.
|
157
140
|
#
|
158
141
|
# @param key [Symbol, String] the attribute name to get messages for
|
159
142
|
#
|
160
143
|
# @return [Array<String>] array of formatted error messages for the attribute
|
161
144
|
#
|
162
|
-
# @example Get
|
163
|
-
# errors
|
164
|
-
# errors.add(:name, "is required")
|
145
|
+
# @example Get messages for existing attribute
|
146
|
+
# errors.add(:name, "can't be blank")
|
165
147
|
# errors.add(:name, "is too short")
|
166
|
-
# errors.full_messages_for(:name) # => ["name
|
148
|
+
# errors.full_messages_for(:name) # => ["name can't be blank", "name is too short"]
|
167
149
|
#
|
168
|
-
# @example Get messages for attribute
|
169
|
-
# errors.full_messages_for(:
|
150
|
+
# @example Get messages for non-existent attribute
|
151
|
+
# errors.full_messages_for(:nonexistent) # => []
|
170
152
|
def full_messages_for(key)
|
171
153
|
return [] unless key?(key)
|
172
154
|
|
173
155
|
errors[key].map { |val| full_message(key, val) }
|
174
156
|
end
|
175
157
|
|
176
|
-
# Checks if the
|
158
|
+
# Checks if the errors collection contains any validation errors.
|
177
159
|
#
|
178
|
-
# @return [Boolean] true if there are any errors present
|
160
|
+
# @return [Boolean] true if there are any errors present, false otherwise
|
179
161
|
#
|
180
|
-
# @example Check
|
181
|
-
# errors
|
182
|
-
# errors.invalid? # => false
|
183
|
-
# errors.add(:name, "is required")
|
162
|
+
# @example Check invalid state
|
163
|
+
# errors.add(:name, "can't be blank")
|
184
164
|
# errors.invalid? # => true
|
165
|
+
#
|
166
|
+
# @example Check valid state
|
167
|
+
# errors.invalid? # => false
|
185
168
|
def invalid?
|
186
169
|
!valid?
|
187
170
|
end
|
188
171
|
|
189
|
-
#
|
190
|
-
#
|
191
|
-
# Similar to {#each}, but returns an array of the block's return values
|
192
|
-
# instead of iterating without collecting results.
|
172
|
+
# Transforms each error using the provided block and returns results as an array.
|
193
173
|
#
|
194
|
-
# @yield [
|
195
|
-
# @
|
174
|
+
# @yield [key, value] gives the attribute name and error message for transformation
|
175
|
+
# @yieldparam key [Symbol, String] the attribute name
|
176
|
+
# @yieldparam value [String, Object] the error message
|
177
|
+
# @yieldreturn [Object] the transformed value to include in result array
|
196
178
|
#
|
197
|
-
# @return [Array
|
179
|
+
# @return [Array] array of transformed error values
|
198
180
|
#
|
199
|
-
# @example Transform
|
200
|
-
# errors
|
201
|
-
# errors.add(:name, "is required")
|
181
|
+
# @example Transform errors to uppercase messages
|
182
|
+
# errors.add(:name, "can't be blank")
|
202
183
|
# errors.add(:email, "is invalid")
|
203
|
-
#
|
204
|
-
# result # => ["NAME: is required", "EMAIL: is invalid"]
|
205
|
-
#
|
206
|
-
# @example Extract only attribute names with errors
|
207
|
-
# errors.map { |attr, _msg| attr } # => [:name, :email]
|
184
|
+
# errors.map { |attr, msg| msg.upcase } # => ["CAN'T BE BLANK", "IS INVALID"]
|
208
185
|
#
|
209
|
-
# @example
|
210
|
-
#
|
211
|
-
#
|
186
|
+
# @example Create custom error objects
|
187
|
+
# errors.map { |attr, msg| { attribute: attr, message: msg } }
|
188
|
+
# # => [{ attribute: :name, message: "can't be blank" }]
|
212
189
|
def map
|
213
190
|
errors.each_with_object([]) do |(key, _arr), memo|
|
214
191
|
memo.concat(errors[key].map { |val| yield(key, val) })
|
215
192
|
end
|
216
193
|
end
|
217
194
|
|
218
|
-
# Merges another hash
|
195
|
+
# Merges another errors hash into this collection, combining arrays for duplicate keys.
|
219
196
|
#
|
220
|
-
#
|
221
|
-
# are combined and duplicates are removed.
|
197
|
+
# @param hash [Hash] hash of errors to merge, with attribute keys and message arrays as values
|
222
198
|
#
|
223
|
-
# @
|
199
|
+
# @return [Hash] the updated internal errors hash
|
224
200
|
#
|
225
|
-
# @
|
226
|
-
#
|
227
|
-
# @example Merge errors from another hash
|
228
|
-
# errors = CMDx::Errors.new
|
229
|
-
# errors.add(:name, "is required")
|
201
|
+
# @example Merge additional errors
|
202
|
+
# errors.add(:name, "can't be blank")
|
230
203
|
# other_errors = { email: ["is invalid"], name: ["is too short"] }
|
231
204
|
# errors.merge!(other_errors)
|
232
|
-
# errors
|
233
|
-
# errors
|
234
|
-
#
|
235
|
-
# @example Merge with duplicate
|
236
|
-
# errors.add(:
|
237
|
-
#
|
238
|
-
# errors
|
205
|
+
# errors.messages_for(:name) # => ["can't be blank", "is too short"]
|
206
|
+
# errors.messages_for(:email) # => ["is invalid"]
|
207
|
+
#
|
208
|
+
# @example Merge with duplicate prevention
|
209
|
+
# errors.add(:name, "can't be blank")
|
210
|
+
# duplicate_errors = { name: ["can't be blank", "is required"] }
|
211
|
+
# errors.merge!(duplicate_errors)
|
212
|
+
# errors.messages_for(:name) # => ["can't be blank", "is required"]
|
239
213
|
def merge!(hash)
|
240
214
|
errors.merge!(hash) do |_, arr1, arr2|
|
241
215
|
arr3 = arr1 + arr2
|
@@ -244,20 +218,19 @@ module CMDx
|
|
244
218
|
end
|
245
219
|
end
|
246
220
|
|
247
|
-
# Returns the raw error messages for a specific attribute.
|
221
|
+
# Returns the raw error messages for a specific attribute without formatting.
|
248
222
|
#
|
249
223
|
# @param key [Symbol, String] the attribute name to get messages for
|
250
224
|
#
|
251
|
-
# @return [Array
|
225
|
+
# @return [Array] array of raw error messages for the attribute
|
252
226
|
#
|
253
|
-
# @example Get raw messages for
|
254
|
-
# errors
|
255
|
-
# errors.add(:name, "is required")
|
227
|
+
# @example Get raw messages for existing attribute
|
228
|
+
# errors.add(:name, "can't be blank")
|
256
229
|
# errors.add(:name, "is too short")
|
257
|
-
# errors.messages_for(:name) # => ["
|
230
|
+
# errors.messages_for(:name) # => ["can't be blank", "is too short"]
|
258
231
|
#
|
259
|
-
# @example Get messages for attribute
|
260
|
-
# errors.messages_for(:
|
232
|
+
# @example Get messages for non-existent attribute
|
233
|
+
# errors.messages_for(:nonexistent) # => []
|
261
234
|
def messages_for(key)
|
262
235
|
return [] unless key?(key)
|
263
236
|
|
@@ -265,35 +238,36 @@ module CMDx
|
|
265
238
|
end
|
266
239
|
alias [] messages_for
|
267
240
|
|
268
|
-
# Checks if the
|
241
|
+
# Checks if the errors collection contains any validation errors.
|
269
242
|
#
|
270
|
-
# @return [Boolean] true if there are any errors present
|
243
|
+
# @return [Boolean] true if there are any errors present, false otherwise
|
271
244
|
#
|
272
|
-
# @example Check
|
273
|
-
# errors
|
274
|
-
# errors.present? # => false
|
275
|
-
# errors.add(:name, "is required")
|
245
|
+
# @example Check for errors presence
|
246
|
+
# errors.add(:name, "can't be blank")
|
276
247
|
# errors.present? # => true
|
248
|
+
#
|
249
|
+
# @example Check empty collection
|
250
|
+
# errors.present? # => false
|
277
251
|
def present?
|
278
252
|
!blank?
|
279
253
|
end
|
280
254
|
|
281
|
-
# Converts the
|
255
|
+
# Converts the errors collection to a hash format, optionally with full formatted messages.
|
282
256
|
#
|
283
|
-
# @param full_messages [Boolean] whether to
|
257
|
+
# @param full_messages [Boolean] whether to format messages with attribute names
|
284
258
|
#
|
285
259
|
# @return [Hash] hash representation of errors
|
260
|
+
# @option return [Array<String>] attribute_name array of error messages (raw or formatted)
|
286
261
|
#
|
287
|
-
# @example Get raw
|
288
|
-
# errors
|
289
|
-
# errors.add(:
|
290
|
-
# errors.to_hash # => { name: ["is
|
262
|
+
# @example Get raw errors hash
|
263
|
+
# errors.add(:name, "can't be blank")
|
264
|
+
# errors.add(:email, "is invalid")
|
265
|
+
# errors.to_hash # => { :name => ["can't be blank"], :email => ["is invalid"] }
|
291
266
|
#
|
292
|
-
# @example Get
|
293
|
-
# errors.to_hash(true) # => { name
|
267
|
+
# @example Get formatted errors hash
|
268
|
+
# errors.to_hash(true) # => { :name => ["name can't be blank"], :email => ["email is invalid"] }
|
294
269
|
#
|
295
|
-
# @example Empty errors
|
296
|
-
# errors = CMDx::Errors.new
|
270
|
+
# @example Empty errors collection
|
297
271
|
# errors.to_hash # => {}
|
298
272
|
def to_hash(full_messages = false)
|
299
273
|
return errors unless full_messages
|