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/errors.rb
CHANGED
@@ -1,151 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# error messages, making it easy to accumulate and present multiple error conditions.
|
8
|
-
#
|
9
|
-
# The Errors class is designed to work seamlessly with CMDx's parameter validation system,
|
10
|
-
# automatically collecting validation failures and providing convenient methods for
|
11
|
-
# error reporting and user feedback.
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# @example Basic error management
|
15
|
-
# errors = Errors.new
|
16
|
-
# errors.add(:email, "is required")
|
17
|
-
# errors.add(:email, "is invalid format")
|
18
|
-
# errors.add(:password, "is too short")
|
19
|
-
#
|
20
|
-
# errors.empty? #=> false
|
21
|
-
# errors.size #=> 2 (attributes with errors)
|
22
|
-
# errors[:email] #=> ["is required", "is invalid format"]
|
23
|
-
# errors.full_messages #=> ["email is required", "email is invalid format", "password is too short"]
|
24
|
-
#
|
25
|
-
# @example Task integration
|
26
|
-
# class CreateUserTask < CMDx::Task
|
27
|
-
# required :email, type: :string
|
28
|
-
# required :password, type: :string
|
29
|
-
#
|
30
|
-
# def call
|
31
|
-
# validate_email
|
32
|
-
# validate_password
|
33
|
-
#
|
34
|
-
# if errors.present?
|
35
|
-
# fail!(reason: "Validation failed", validation_errors: errors.full_messages)
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# create_user
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# private
|
42
|
-
#
|
43
|
-
# def validate_email
|
44
|
-
# errors.add(:email, "is required") if email.blank?
|
45
|
-
# errors.add(:email, "is invalid") unless email.include?("@")
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# def validate_password
|
49
|
-
# errors.add(:password, "is too short") if password.length < 8
|
50
|
-
# end
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# @example Error querying and formatting
|
54
|
-
# errors = Errors.new
|
55
|
-
# errors.add(:name, "cannot be blank")
|
56
|
-
# errors.add(:age, "must be a number")
|
57
|
-
#
|
58
|
-
# # Checking for specific errors
|
59
|
-
# errors.key?(:name) #=> true
|
60
|
-
# errors.added?(:name, "cannot be blank") #=> true
|
61
|
-
# errors.of_kind?(:age, "must be positive") #=> false
|
62
|
-
#
|
63
|
-
# # Getting messages
|
64
|
-
# errors.messages_for(:name) #=> ["cannot be blank"]
|
65
|
-
# errors.full_messages_for(:name) #=> ["name cannot be blank"]
|
66
|
-
#
|
67
|
-
# # Converting to hash
|
68
|
-
# errors.to_hash #=> {:name => ["cannot be blank"], :age => ["must be a number"]}
|
69
|
-
# errors.to_hash(true) #=> {:name => ["name cannot be blank"], :age => ["age must be a number"]}
|
70
|
-
#
|
71
|
-
# @example Rails-style validation
|
72
|
-
# class ValidateUserTask < CMDx::Task
|
73
|
-
# required :user_data, type: :hash
|
74
|
-
#
|
75
|
-
# def call
|
76
|
-
# user = user_data
|
77
|
-
#
|
78
|
-
# errors.add(:email, "can't be blank") if user[:email].blank?
|
79
|
-
# errors.add(:email, "is invalid") unless valid_email?(user[:email])
|
80
|
-
# errors.add(:age, "must be at least 18") if user[:age] && user[:age] < 18
|
81
|
-
#
|
82
|
-
# return if errors.invalid?
|
83
|
-
#
|
84
|
-
# context.validated_user = user
|
85
|
-
# end
|
86
|
-
# end
|
87
|
-
#
|
88
|
-
# @see Task Task base class with errors attribute
|
89
|
-
# @see Parameter Parameter validation integration
|
90
|
-
# @see ValidationError Individual validation errors
|
91
|
-
# @since 1.0.0
|
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.
|
92
7
|
class Errors
|
93
8
|
|
94
|
-
|
95
|
-
|
9
|
+
cmdx_attr_delegator :clear, :delete, :empty?, :key?, :keys, :size, :values,
|
10
|
+
to: :errors
|
96
11
|
|
97
|
-
|
98
|
-
# @!attribute [r] errors
|
99
|
-
# @return [Hash] internal hash storing error messages by attribute
|
12
|
+
# @return [Hash] internal hash storing error messages by attribute
|
100
13
|
attr_reader :errors
|
101
14
|
|
102
|
-
|
103
|
-
# @!method attribute_names
|
104
|
-
# @return [Array<Symbol>] list of attributes that have errors
|
15
|
+
# @return [Array<Symbol>] list of attributes that have errors
|
105
16
|
alias attribute_names keys
|
106
17
|
|
107
|
-
|
108
|
-
# @!method blank?
|
109
|
-
# @return [Boolean] true if no errors are present
|
18
|
+
# @return [Boolean] true if no errors are present
|
110
19
|
alias blank? empty?
|
111
20
|
|
112
|
-
|
113
|
-
# @!method valid?
|
114
|
-
# @return [Boolean] true if no errors are present
|
21
|
+
# @return [Boolean] true if no errors are present
|
115
22
|
alias valid? empty?
|
116
23
|
|
117
|
-
##
|
118
24
|
# Alias for {#key?}. Checks if an attribute has error messages.
|
119
25
|
alias has_key? key?
|
120
26
|
|
121
|
-
##
|
122
27
|
# Alias for {#key?}. Checks if an attribute has error messages.
|
123
28
|
alias include? key?
|
124
29
|
|
125
|
-
|
126
|
-
# Initializes a new Errors collection.
|
127
|
-
# Creates an empty hash to store error messages by attribute.
|
30
|
+
# Creates a new empty errors collection.
|
128
31
|
#
|
129
|
-
# @
|
130
|
-
#
|
131
|
-
#
|
32
|
+
# @return [Errors] a new errors instance with empty internal hash
|
33
|
+
#
|
34
|
+
# @example Create new errors collection
|
35
|
+
# errors = CMDx::Errors.new
|
36
|
+
# errors.empty? # => true
|
132
37
|
def initialize
|
133
38
|
@errors = {}
|
134
39
|
end
|
135
40
|
|
136
|
-
|
137
|
-
#
|
138
|
-
# Messages are stored in arrays and automatically deduplicated.
|
41
|
+
# Adds an error message to the specified attribute. Automatically handles
|
42
|
+
# array initialization and prevents duplicate messages for the same attribute.
|
139
43
|
#
|
140
|
-
# @param key [Symbol, String] the attribute name
|
141
|
-
# @param value [String] the error message
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
# errors.add(:
|
147
|
-
# errors.add(:
|
148
|
-
# errors
|
44
|
+
# @param key [Symbol, String] the attribute name to associate the error with
|
45
|
+
# @param value [String, Object] the error message or error object to add
|
46
|
+
#
|
47
|
+
# @return [Array] the updated array of error messages for the attribute
|
48
|
+
#
|
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"]
|
149
58
|
def add(key, value)
|
150
59
|
errors[key] ||= []
|
151
60
|
errors[key] << value
|
@@ -153,18 +62,20 @@ module CMDx
|
|
153
62
|
end
|
154
63
|
alias []= add
|
155
64
|
|
156
|
-
##
|
157
65
|
# Checks if a specific error message has been added to an attribute.
|
158
66
|
#
|
159
|
-
# @param key [Symbol, String] the attribute name
|
160
|
-
# @param val [String] the error message to
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
# errors.
|
166
|
-
# errors.added?(:name, "
|
167
|
-
# errors.
|
67
|
+
# @param key [Symbol, String] the attribute name to check
|
68
|
+
# @param val [String, Object] the error message to look for
|
69
|
+
#
|
70
|
+
# @return [Boolean] true if the error exists for the attribute, false otherwise
|
71
|
+
#
|
72
|
+
# @example Check for specific error
|
73
|
+
# errors.add(:name, "can't be blank")
|
74
|
+
# errors.added?(:name, "can't be blank") # => true
|
75
|
+
# errors.added?(:name, "is invalid") # => false
|
76
|
+
#
|
77
|
+
# @example Check non-existent attribute
|
78
|
+
# errors.added?(:nonexistent, "error") # => false
|
168
79
|
def added?(key, val)
|
169
80
|
return false unless key?(key)
|
170
81
|
|
@@ -172,20 +83,20 @@ module CMDx
|
|
172
83
|
end
|
173
84
|
alias of_kind? added?
|
174
85
|
|
175
|
-
|
176
|
-
# Iterates over each error, yielding the attribute and message.
|
177
|
-
# Flattens the error structure so each message is yielded individually.
|
86
|
+
# Iterates over each error, yielding the attribute name and error message.
|
178
87
|
#
|
179
|
-
# @
|
180
|
-
# @yieldparam
|
181
|
-
# @
|
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
|
182
91
|
#
|
183
|
-
# @
|
184
|
-
#
|
92
|
+
# @return [Hash] the errors hash when no block given
|
93
|
+
#
|
94
|
+
# @example Iterate over all errors
|
95
|
+
# errors.add(:name, "can't be blank")
|
185
96
|
# errors.add(:email, "is invalid")
|
186
97
|
# errors.each { |attr, msg| puts "#{attr}: #{msg}" }
|
187
98
|
# # Output:
|
188
|
-
# # name:
|
99
|
+
# # name: can't be blank
|
189
100
|
# # email: is invalid
|
190
101
|
def each
|
191
102
|
errors.each_key do |key|
|
@@ -193,32 +104,31 @@ module CMDx
|
|
193
104
|
end
|
194
105
|
end
|
195
106
|
|
196
|
-
|
197
|
-
# Generates a full error message by combining attribute name and message.
|
107
|
+
# Formats an error message by combining the attribute name and error value.
|
198
108
|
#
|
199
109
|
# @param key [Symbol, String] the attribute name
|
200
|
-
# @param value [String] the error message
|
201
|
-
#
|
110
|
+
# @param value [String, Object] the error message
|
111
|
+
#
|
112
|
+
# @return [String] the formatted full error message
|
202
113
|
#
|
203
|
-
# @example
|
204
|
-
# errors.full_message(:
|
205
|
-
# errors.full_message(:
|
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"
|
206
117
|
def full_message(key, value)
|
207
118
|
"#{key} #{value}"
|
208
119
|
end
|
209
120
|
|
210
|
-
|
211
|
-
# Returns an array of all full error messages.
|
212
|
-
# Combines attribute names with their error messages.
|
121
|
+
# Returns all error messages formatted with their attribute names.
|
213
122
|
#
|
214
123
|
# @return [Array<String>] array of formatted error messages
|
215
124
|
#
|
216
|
-
# @example
|
217
|
-
# errors.add(:
|
125
|
+
# @example Get all formatted messages
|
126
|
+
# errors.add(:name, "can't be blank")
|
218
127
|
# errors.add(:email, "is invalid")
|
219
|
-
# errors.
|
220
|
-
#
|
221
|
-
#
|
128
|
+
# errors.full_messages # => ["name can't be blank", "email is invalid"]
|
129
|
+
#
|
130
|
+
# @example Empty errors collection
|
131
|
+
# errors.full_messages # => []
|
222
132
|
def full_messages
|
223
133
|
errors.each_with_object([]) do |(key, arr), memo|
|
224
134
|
arr.each { |val| memo << full_message(key, val) }
|
@@ -226,54 +136,80 @@ module CMDx
|
|
226
136
|
end
|
227
137
|
alias to_a full_messages
|
228
138
|
|
229
|
-
|
230
|
-
# Returns full error messages for a specific attribute.
|
139
|
+
# Returns formatted error messages for a specific attribute.
|
231
140
|
#
|
232
|
-
# @param key [Symbol, String] the attribute name
|
233
|
-
# @return [Array<String>] array of full messages for the attribute
|
141
|
+
# @param key [Symbol, String] the attribute name to get messages for
|
234
142
|
#
|
235
|
-
# @
|
236
|
-
#
|
237
|
-
#
|
238
|
-
# errors.
|
239
|
-
#
|
240
|
-
# errors.full_messages_for(:
|
143
|
+
# @return [Array<String>] array of formatted error messages for the attribute
|
144
|
+
#
|
145
|
+
# @example Get messages for existing attribute
|
146
|
+
# errors.add(:name, "can't be blank")
|
147
|
+
# errors.add(:name, "is too short")
|
148
|
+
# errors.full_messages_for(:name) # => ["name can't be blank", "name is too short"]
|
149
|
+
#
|
150
|
+
# @example Get messages for non-existent attribute
|
151
|
+
# errors.full_messages_for(:nonexistent) # => []
|
241
152
|
def full_messages_for(key)
|
242
153
|
return [] unless key?(key)
|
243
154
|
|
244
155
|
errors[key].map { |val| full_message(key, val) }
|
245
156
|
end
|
246
157
|
|
247
|
-
|
248
|
-
#
|
158
|
+
# Checks if the errors collection contains any validation errors.
|
159
|
+
#
|
160
|
+
# @return [Boolean] true if there are any errors present, false otherwise
|
249
161
|
#
|
250
|
-
# @
|
162
|
+
# @example Check invalid state
|
163
|
+
# errors.add(:name, "can't be blank")
|
164
|
+
# errors.invalid? # => true
|
251
165
|
#
|
252
|
-
# @example
|
253
|
-
# errors
|
254
|
-
# errors.invalid? #=> false
|
255
|
-
# errors.add(:name, "is required")
|
256
|
-
# errors.invalid? #=> true
|
166
|
+
# @example Check valid state
|
167
|
+
# errors.invalid? # => false
|
257
168
|
def invalid?
|
258
169
|
!valid?
|
259
170
|
end
|
260
171
|
|
261
|
-
|
262
|
-
#
|
263
|
-
#
|
172
|
+
# Transforms each error using the provided block and returns results as an array.
|
173
|
+
#
|
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
|
264
178
|
#
|
265
|
-
# @
|
266
|
-
#
|
179
|
+
# @return [Array] array of transformed error values
|
180
|
+
#
|
181
|
+
# @example Transform errors to uppercase messages
|
182
|
+
# errors.add(:name, "can't be blank")
|
183
|
+
# errors.add(:email, "is invalid")
|
184
|
+
# errors.map { |attr, msg| msg.upcase } # => ["CAN'T BE BLANK", "IS INVALID"]
|
185
|
+
#
|
186
|
+
# @example Create custom error objects
|
187
|
+
# errors.map { |attr, msg| { attribute: attr, message: msg } }
|
188
|
+
# # => [{ attribute: :name, message: "can't be blank" }]
|
189
|
+
def map
|
190
|
+
errors.each_with_object([]) do |(key, _arr), memo|
|
191
|
+
memo.concat(errors[key].map { |val| yield(key, val) })
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Merges another errors hash into this collection, combining arrays for duplicate keys.
|
267
196
|
#
|
268
|
-
# @
|
269
|
-
# errors1 = Errors.new
|
270
|
-
# errors1.add(:email, "is required")
|
197
|
+
# @param hash [Hash] hash of errors to merge, with attribute keys and message arrays as values
|
271
198
|
#
|
272
|
-
#
|
273
|
-
# errors1.merge!(errors2)
|
199
|
+
# @return [Hash] the updated internal errors hash
|
274
200
|
#
|
275
|
-
#
|
276
|
-
#
|
201
|
+
# @example Merge additional errors
|
202
|
+
# errors.add(:name, "can't be blank")
|
203
|
+
# other_errors = { email: ["is invalid"], name: ["is too short"] }
|
204
|
+
# errors.merge!(other_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"]
|
277
213
|
def merge!(hash)
|
278
214
|
errors.merge!(hash) do |_, arr1, arr2|
|
279
215
|
arr3 = arr1 + arr2
|
@@ -282,17 +218,19 @@ module CMDx
|
|
282
218
|
end
|
283
219
|
end
|
284
220
|
|
285
|
-
|
286
|
-
# Returns error messages for a specific attribute.
|
221
|
+
# Returns the raw error messages for a specific attribute without formatting.
|
287
222
|
#
|
288
|
-
# @param key [Symbol, String] the attribute name
|
289
|
-
# @return [Array<String>] array of error messages for the attribute
|
223
|
+
# @param key [Symbol, String] the attribute name to get messages for
|
290
224
|
#
|
291
|
-
# @
|
292
|
-
#
|
293
|
-
#
|
294
|
-
# errors.
|
295
|
-
# errors
|
225
|
+
# @return [Array] array of raw error messages for the attribute
|
226
|
+
#
|
227
|
+
# @example Get raw messages for existing attribute
|
228
|
+
# errors.add(:name, "can't be blank")
|
229
|
+
# errors.add(:name, "is too short")
|
230
|
+
# errors.messages_for(:name) # => ["can't be blank", "is too short"]
|
231
|
+
#
|
232
|
+
# @example Get messages for non-existent attribute
|
233
|
+
# errors.messages_for(:nonexistent) # => []
|
296
234
|
def messages_for(key)
|
297
235
|
return [] unless key?(key)
|
298
236
|
|
@@ -300,38 +238,37 @@ module CMDx
|
|
300
238
|
end
|
301
239
|
alias [] messages_for
|
302
240
|
|
303
|
-
|
304
|
-
#
|
241
|
+
# Checks if the errors collection contains any validation errors.
|
242
|
+
#
|
243
|
+
# @return [Boolean] true if there are any errors present, false otherwise
|
305
244
|
#
|
306
|
-
# @
|
245
|
+
# @example Check for errors presence
|
246
|
+
# errors.add(:name, "can't be blank")
|
247
|
+
# errors.present? # => true
|
307
248
|
#
|
308
|
-
# @example
|
309
|
-
# errors
|
310
|
-
# errors.present? #=> false
|
311
|
-
# errors.add(:name, "is required")
|
312
|
-
# errors.present? #=> true
|
249
|
+
# @example Check empty collection
|
250
|
+
# errors.present? # => false
|
313
251
|
def present?
|
314
252
|
!blank?
|
315
253
|
end
|
316
254
|
|
317
|
-
|
318
|
-
#
|
255
|
+
# Converts the errors collection to a hash format, optionally with full formatted messages.
|
256
|
+
#
|
257
|
+
# @param full_messages [Boolean] whether to format messages with attribute names
|
319
258
|
#
|
320
|
-
# @param full_messages [Boolean] whether to include full formatted messages
|
321
259
|
# @return [Hash] hash representation of errors
|
260
|
+
# @option return [Array<String>] attribute_name array of error messages (raw or formatted)
|
322
261
|
#
|
323
|
-
# @example
|
324
|
-
# errors.add(:
|
325
|
-
# errors.
|
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"] }
|
326
266
|
#
|
327
|
-
# @example
|
328
|
-
# errors.
|
329
|
-
# errors.to_hash(true) #=> {:email => ["email is required"]}
|
267
|
+
# @example Get formatted errors hash
|
268
|
+
# errors.to_hash(true) # => { :name => ["name can't be blank"], :email => ["email is invalid"] }
|
330
269
|
#
|
331
|
-
# @example
|
332
|
-
# errors.
|
333
|
-
# errors.group_by_attribute #=> same as to_hash
|
334
|
-
# errors.as_json #=> same as to_hash
|
270
|
+
# @example Empty errors collection
|
271
|
+
# errors.to_hash # => {}
|
335
272
|
def to_hash(full_messages = false)
|
336
273
|
return errors unless full_messages
|
337
274
|
|