cmdx 1.0.0 → 1.1.0
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/rspec.md +20 -0
- data/.cursor/prompts/yardoc.md +8 -0
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +101 -49
- data/README.md +2 -1
- data/docs/ai_prompts.md +10 -0
- data/docs/basics/call.md +11 -2
- data/docs/basics/chain.md +10 -1
- data/docs/basics/context.md +9 -0
- data/docs/basics/setup.md +9 -0
- data/docs/callbacks.md +14 -37
- data/docs/configuration.md +68 -27
- data/docs/getting_started.md +11 -0
- data/docs/internationalization.md +148 -0
- data/docs/interruptions/exceptions.md +10 -1
- data/docs/interruptions/faults.md +11 -2
- data/docs/interruptions/halt.md +9 -0
- data/docs/logging.md +14 -4
- data/docs/middlewares.md +53 -43
- data/docs/outcomes/result.md +9 -0
- data/docs/outcomes/states.md +9 -0
- data/docs/outcomes/statuses.md +9 -0
- data/docs/parameters/coercions.md +58 -38
- data/docs/parameters/defaults.md +10 -1
- data/docs/parameters/definitions.md +9 -0
- data/docs/parameters/namespacing.md +9 -0
- data/docs/parameters/validations.md +8 -67
- data/docs/testing.md +22 -13
- data/docs/tips_and_tricks.md +9 -0
- data/docs/workflows.md +14 -4
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +36 -56
- data/lib/cmdx/callback_registry.rb +82 -73
- data/lib/cmdx/chain.rb +65 -122
- data/lib/cmdx/chain_inspector.rb +22 -115
- data/lib/cmdx/chain_serializer.rb +17 -148
- data/lib/cmdx/coercion.rb +49 -0
- data/lib/cmdx/coercion_registry.rb +94 -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 +57 -171
- data/lib/cmdx/context.rb +22 -165
- 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 +40 -156
- data/lib/cmdx/error.rb +37 -202
- data/lib/cmdx/errors.rb +165 -202
- data/lib/cmdx/fault.rb +55 -158
- data/lib/cmdx/faults.rb +26 -137
- data/lib/cmdx/immutator.rb +22 -109
- data/lib/cmdx/lazy_struct.rb +103 -187
- 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 +20 -82
- data/lib/cmdx/logger_ansi.rb +18 -75
- data/lib/cmdx/logger_serializer.rb +24 -114
- data/lib/cmdx/middleware.rb +38 -60
- data/lib/cmdx/middleware_registry.rb +81 -77
- data/lib/cmdx/middlewares/correlate.rb +41 -226
- data/lib/cmdx/middlewares/timeout.rb +46 -185
- data/lib/cmdx/parameter.rb +120 -198
- data/lib/cmdx/parameter_evaluator.rb +231 -0
- data/lib/cmdx/parameter_inspector.rb +25 -56
- data/lib/cmdx/parameter_registry.rb +59 -84
- data/lib/cmdx/parameter_serializer.rb +23 -74
- data/lib/cmdx/railtie.rb +24 -107
- data/lib/cmdx/result.rb +254 -260
- data/lib/cmdx/result_ansi.rb +19 -85
- data/lib/cmdx/result_inspector.rb +27 -68
- data/lib/cmdx/result_logger.rb +18 -81
- data/lib/cmdx/result_serializer.rb +28 -132
- 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 +213 -425
- data/lib/cmdx/task_deprecator.rb +55 -0
- data/lib/cmdx/task_processor.rb +245 -0
- data/lib/cmdx/task_serializer.rb +22 -70
- 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 +13 -63
- data/lib/cmdx/utils/name_affix.rb +21 -71
- data/lib/cmdx/validator.rb +48 -0
- data/lib/cmdx/validator_registry.rb +86 -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 +46 -339
- 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 +61 -11
- data/lib/generators/cmdx/workflow_generator.rb +41 -66
- data/lib/locales/ar.yml +35 -0
- data/lib/locales/cs.yml +35 -0
- data/lib/locales/da.yml +35 -0
- data/lib/locales/de.yml +35 -0
- data/lib/locales/el.yml +35 -0
- data/lib/locales/en.yml +19 -20
- data/lib/locales/es.yml +19 -20
- data/lib/locales/fi.yml +35 -0
- data/lib/locales/fr.yml +35 -0
- data/lib/locales/he.yml +35 -0
- data/lib/locales/hi.yml +35 -0
- data/lib/locales/it.yml +35 -0
- data/lib/locales/ja.yml +35 -0
- data/lib/locales/ko.yml +35 -0
- data/lib/locales/nl.yml +35 -0
- data/lib/locales/no.yml +35 -0
- data/lib/locales/pl.yml +35 -0
- data/lib/locales/pt.yml +35 -0
- data/lib/locales/ru.yml +35 -0
- data/lib/locales/sv.yml +35 -0
- data/lib/locales/th.yml +35 -0
- data/lib/locales/tr.yml +35 -0
- data/lib/locales/vi.yml +35 -0
- data/lib/locales/zh.yml +35 -0
- metadata +57 -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,72 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
|
5
|
-
# Errors provides a collection-like interface for managing validation and execution errors
|
6
|
-
# within CMDx tasks. It offers Rails-inspired methods for adding, querying, and formatting
|
7
|
-
# error messages, making it easy to accumulate and present multiple error conditions.
|
4
|
+
# Error collection and validation system for CMDx tasks.
|
8
5
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# error
|
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
|
6
|
+
# This class manages error messages associated with specific attributes,
|
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.
|
92
11
|
class Errors
|
93
12
|
|
94
|
-
|
95
|
-
|
13
|
+
cmdx_attr_delegator :clear, :delete, :empty?, :key?, :keys, :size, :values,
|
14
|
+
to: :errors
|
96
15
|
|
97
|
-
|
98
|
-
# @!attribute [r] errors
|
99
|
-
# @return [Hash] internal hash storing error messages by attribute
|
16
|
+
# @return [Hash] internal hash storing error messages by attribute
|
100
17
|
attr_reader :errors
|
101
18
|
|
102
|
-
|
103
|
-
# @!method attribute_names
|
104
|
-
# @return [Array<Symbol>] list of attributes that have errors
|
19
|
+
# @return [Array<Symbol>] list of attributes that have errors
|
105
20
|
alias attribute_names keys
|
106
21
|
|
107
|
-
|
108
|
-
# @!method blank?
|
109
|
-
# @return [Boolean] true if no errors are present
|
22
|
+
# @return [Boolean] true if no errors are present
|
110
23
|
alias blank? empty?
|
111
24
|
|
112
|
-
|
113
|
-
# @!method valid?
|
114
|
-
# @return [Boolean] true if no errors are present
|
25
|
+
# @return [Boolean] true if no errors are present
|
115
26
|
alias valid? empty?
|
116
27
|
|
117
|
-
##
|
118
28
|
# Alias for {#key?}. Checks if an attribute has error messages.
|
119
29
|
alias has_key? key?
|
120
30
|
|
121
|
-
##
|
122
31
|
# Alias for {#key?}. Checks if an attribute has error messages.
|
123
32
|
alias include? key?
|
124
33
|
|
125
|
-
|
126
|
-
#
|
127
|
-
#
|
34
|
+
# Creates a new error collection with an empty internal hash.
|
35
|
+
#
|
36
|
+
# @return [Errors] the newly created error collection
|
128
37
|
#
|
129
|
-
# @example
|
130
|
-
# errors = Errors.new
|
131
|
-
# errors.empty?
|
38
|
+
# @example Create a new error collection
|
39
|
+
# errors = CMDx::Errors.new
|
40
|
+
# errors.empty? # => true
|
132
41
|
def initialize
|
133
42
|
@errors = {}
|
134
43
|
end
|
135
44
|
|
136
|
-
##
|
137
45
|
# Adds an error message to the specified attribute.
|
138
|
-
# Messages are stored in arrays and automatically deduplicated.
|
139
46
|
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
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.
|
50
|
+
#
|
51
|
+
# @param key [Symbol, String] the attribute name to associate the error with
|
52
|
+
# @param value [String] the error message to add
|
53
|
+
#
|
54
|
+
# @return [Array<String>] the array of error messages for the attribute
|
143
55
|
#
|
144
|
-
# @example
|
56
|
+
# @example Add an error to an attribute
|
57
|
+
# errors = CMDx::Errors.new
|
58
|
+
# errors.add(:name, "is required")
|
59
|
+
# errors[:name] # => ["is required"]
|
60
|
+
#
|
61
|
+
# @example Add multiple errors to the same attribute
|
145
62
|
# errors.add(:email, "is required")
|
146
|
-
# errors.add(:email, "
|
147
|
-
# errors
|
148
|
-
#
|
63
|
+
# errors.add(:email, "must be valid")
|
64
|
+
# errors[:email] # => ["is required", "must be valid"]
|
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"]
|
149
70
|
def add(key, value)
|
150
71
|
errors[key] ||= []
|
151
72
|
errors[key] << value
|
@@ -153,18 +74,21 @@ module CMDx
|
|
153
74
|
end
|
154
75
|
alias []= add
|
155
76
|
|
156
|
-
##
|
157
77
|
# Checks if a specific error message has been added to an attribute.
|
158
78
|
#
|
159
|
-
# @param key [Symbol, String] the attribute name
|
160
|
-
# @param val [String] the error message to
|
161
|
-
# @return [Boolean] true if the specific error exists
|
79
|
+
# @param key [Symbol, String] the attribute name to check
|
80
|
+
# @param val [String] the error message to look for
|
162
81
|
#
|
163
|
-
# @
|
82
|
+
# @return [Boolean] true if the specific error message exists for the attribute
|
83
|
+
#
|
84
|
+
# @example Check if a specific error exists
|
85
|
+
# errors = CMDx::Errors.new
|
164
86
|
# errors.add(:name, "is required")
|
165
|
-
# errors.added?(:name, "is required")
|
166
|
-
# errors.added?(:name, "is
|
167
|
-
#
|
87
|
+
# errors.added?(:name, "is required") # => true
|
88
|
+
# errors.added?(:name, "is invalid") # => false
|
89
|
+
#
|
90
|
+
# @example Check error on attribute without errors
|
91
|
+
# errors.added?(:missing, "any error") # => false
|
168
92
|
def added?(key, val)
|
169
93
|
return false unless key?(key)
|
170
94
|
|
@@ -172,15 +96,14 @@ module CMDx
|
|
172
96
|
end
|
173
97
|
alias of_kind? added?
|
174
98
|
|
175
|
-
|
176
|
-
# Iterates over each error, yielding the attribute and message.
|
177
|
-
# Flattens the error structure so each message is yielded individually.
|
99
|
+
# Iterates over all error messages, yielding the attribute and message.
|
178
100
|
#
|
179
|
-
# @
|
180
|
-
# @yieldparam val [String] the error message
|
181
|
-
# @return [Enumerator] if no block given
|
101
|
+
# @yield [Symbol, String] the attribute name and error message
|
182
102
|
#
|
183
|
-
# @
|
103
|
+
# @return [void]
|
104
|
+
#
|
105
|
+
# @example Iterate over all errors
|
106
|
+
# errors = CMDx::Errors.new
|
184
107
|
# errors.add(:name, "is required")
|
185
108
|
# errors.add(:email, "is invalid")
|
186
109
|
# errors.each { |attr, msg| puts "#{attr}: #{msg}" }
|
@@ -193,32 +116,36 @@ module CMDx
|
|
193
116
|
end
|
194
117
|
end
|
195
118
|
|
196
|
-
|
197
|
-
# Generates a full error message by combining attribute name and message.
|
119
|
+
# Formats an attribute and error message into a full error message.
|
198
120
|
#
|
199
121
|
# @param key [Symbol, String] the attribute name
|
200
122
|
# @param value [String] the error message
|
201
|
-
# @return [String] formatted full message
|
202
123
|
#
|
203
|
-
# @
|
204
|
-
#
|
205
|
-
#
|
124
|
+
# @return [String] the formatted full error message
|
125
|
+
#
|
126
|
+
# @example Format a full error message
|
127
|
+
# errors = CMDx::Errors.new
|
128
|
+
# errors.full_message(:name, "is required") # => "name is required"
|
129
|
+
#
|
130
|
+
# @example Format with different attribute types
|
131
|
+
# errors.full_message("email", "must be valid") # => "email must be valid"
|
206
132
|
def full_message(key, value)
|
207
133
|
"#{key} #{value}"
|
208
134
|
end
|
209
135
|
|
210
|
-
|
211
|
-
# Returns an array of all full error messages.
|
212
|
-
# Combines attribute names with their error messages.
|
136
|
+
# Returns an array of all full error messages across all attributes.
|
213
137
|
#
|
214
138
|
# @return [Array<String>] array of formatted error messages
|
215
139
|
#
|
216
|
-
# @example
|
217
|
-
# errors
|
140
|
+
# @example Get all full error messages
|
141
|
+
# errors = CMDx::Errors.new
|
142
|
+
# errors.add(:name, "is required")
|
218
143
|
# errors.add(:email, "is invalid")
|
219
|
-
# errors.
|
220
|
-
#
|
221
|
-
#
|
144
|
+
# errors.full_messages # => ["name is required", "email is invalid"]
|
145
|
+
#
|
146
|
+
# @example Empty errors return empty array
|
147
|
+
# errors = CMDx::Errors.new
|
148
|
+
# errors.full_messages # => []
|
222
149
|
def full_messages
|
223
150
|
errors.each_with_object([]) do |(key, arr), memo|
|
224
151
|
arr.each { |val| memo << full_message(key, val) }
|
@@ -226,54 +153,89 @@ module CMDx
|
|
226
153
|
end
|
227
154
|
alias to_a full_messages
|
228
155
|
|
229
|
-
##
|
230
156
|
# Returns full error messages for a specific attribute.
|
231
157
|
#
|
232
|
-
# @param key [Symbol, String] the attribute name
|
233
|
-
# @return [Array<String>] array of full messages for the attribute
|
158
|
+
# @param key [Symbol, String] the attribute name to get messages for
|
234
159
|
#
|
235
|
-
# @
|
236
|
-
#
|
237
|
-
#
|
238
|
-
# errors.
|
239
|
-
#
|
240
|
-
# errors.
|
160
|
+
# @return [Array<String>] array of formatted error messages for the attribute
|
161
|
+
#
|
162
|
+
# @example Get full messages for a specific attribute
|
163
|
+
# errors = CMDx::Errors.new
|
164
|
+
# errors.add(:name, "is required")
|
165
|
+
# errors.add(:name, "is too short")
|
166
|
+
# errors.full_messages_for(:name) # => ["name is required", "name is too short"]
|
167
|
+
#
|
168
|
+
# @example Get messages for attribute without errors
|
169
|
+
# errors.full_messages_for(:missing) # => []
|
241
170
|
def full_messages_for(key)
|
242
171
|
return [] unless key?(key)
|
243
172
|
|
244
173
|
errors[key].map { |val| full_message(key, val) }
|
245
174
|
end
|
246
175
|
|
247
|
-
|
248
|
-
# Checks if any errors are present.
|
176
|
+
# Checks if the error collection contains any errors.
|
249
177
|
#
|
250
|
-
# @return [Boolean] true if errors
|
178
|
+
# @return [Boolean] true if there are any errors present
|
251
179
|
#
|
252
|
-
# @example
|
253
|
-
# errors = Errors.new
|
254
|
-
# errors.invalid?
|
180
|
+
# @example Check if errors are present
|
181
|
+
# errors = CMDx::Errors.new
|
182
|
+
# errors.invalid? # => false
|
255
183
|
# errors.add(:name, "is required")
|
256
|
-
# errors.invalid?
|
184
|
+
# errors.invalid? # => true
|
257
185
|
def invalid?
|
258
186
|
!valid?
|
259
187
|
end
|
260
188
|
|
261
|
-
|
189
|
+
# Maps over all error messages, yielding the attribute and message to a block.
|
190
|
+
#
|
191
|
+
# Similar to {#each}, but returns an array of the block's return values
|
192
|
+
# instead of iterating without collecting results.
|
193
|
+
#
|
194
|
+
# @yield [Symbol, String] the attribute name and error message
|
195
|
+
# @yieldreturn [Object] the transformed value for each error message
|
196
|
+
#
|
197
|
+
# @return [Array<Object>] array of transformed values from the block
|
198
|
+
#
|
199
|
+
# @example Transform error messages to a custom format
|
200
|
+
# errors = CMDx::Errors.new
|
201
|
+
# errors.add(:name, "is required")
|
202
|
+
# errors.add(:email, "is invalid")
|
203
|
+
# result = errors.map { |attr, msg| "#{attr.upcase}: #{msg}" }
|
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]
|
208
|
+
#
|
209
|
+
# @example Return empty array for no errors
|
210
|
+
# empty_errors = CMDx::Errors.new
|
211
|
+
# empty_errors.map { |attr, msg| [attr, msg] } # => []
|
212
|
+
def map
|
213
|
+
errors.each_with_object([]) do |(key, _arr), memo|
|
214
|
+
memo.concat(errors[key].map { |val| yield(key, val) })
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
262
218
|
# Merges another hash of errors into this collection.
|
263
|
-
# Combines arrays of messages for attributes that exist in both collections.
|
264
219
|
#
|
265
|
-
#
|
266
|
-
#
|
220
|
+
# When the same attribute exists in both collections, the error arrays
|
221
|
+
# are combined and duplicates are removed.
|
267
222
|
#
|
268
|
-
# @
|
269
|
-
# errors1 = Errors.new
|
270
|
-
# errors1.add(:email, "is required")
|
223
|
+
# @param hash [Hash] hash of errors to merge, with attribute names as keys
|
271
224
|
#
|
272
|
-
#
|
273
|
-
# errors1.merge!(errors2)
|
225
|
+
# @return [Hash] the merged errors hash
|
274
226
|
#
|
275
|
-
#
|
276
|
-
#
|
227
|
+
# @example Merge errors from another hash
|
228
|
+
# errors = CMDx::Errors.new
|
229
|
+
# errors.add(:name, "is required")
|
230
|
+
# other_errors = { email: ["is invalid"], name: ["is too short"] }
|
231
|
+
# errors.merge!(other_errors)
|
232
|
+
# errors[:name] # => ["is required", "is too short"]
|
233
|
+
# errors[:email] # => ["is invalid"]
|
234
|
+
#
|
235
|
+
# @example Merge with duplicate errors
|
236
|
+
# errors.add(:age, "must be positive")
|
237
|
+
# errors.merge!(age: ["must be positive", "must be an integer"])
|
238
|
+
# errors[:age] # => ["must be positive", "must be an integer"]
|
277
239
|
def merge!(hash)
|
278
240
|
errors.merge!(hash) do |_, arr1, arr2|
|
279
241
|
arr3 = arr1 + arr2
|
@@ -282,17 +244,20 @@ module CMDx
|
|
282
244
|
end
|
283
245
|
end
|
284
246
|
|
285
|
-
|
286
|
-
# Returns error messages for a specific attribute.
|
247
|
+
# Returns the raw error messages for a specific attribute.
|
287
248
|
#
|
288
|
-
# @param key [Symbol, String] the attribute name
|
289
|
-
# @return [Array<String>] array of error messages for the attribute
|
249
|
+
# @param key [Symbol, String] the attribute name to get messages for
|
290
250
|
#
|
291
|
-
# @
|
292
|
-
#
|
293
|
-
#
|
294
|
-
# errors
|
295
|
-
# errors
|
251
|
+
# @return [Array<String>] array of raw error messages for the attribute
|
252
|
+
#
|
253
|
+
# @example Get raw messages for an attribute
|
254
|
+
# errors = CMDx::Errors.new
|
255
|
+
# errors.add(:name, "is required")
|
256
|
+
# errors.add(:name, "is too short")
|
257
|
+
# errors.messages_for(:name) # => ["is required", "is too short"]
|
258
|
+
#
|
259
|
+
# @example Get messages for attribute without errors
|
260
|
+
# errors.messages_for(:missing) # => []
|
296
261
|
def messages_for(key)
|
297
262
|
return [] unless key?(key)
|
298
263
|
|
@@ -300,38 +265,36 @@ module CMDx
|
|
300
265
|
end
|
301
266
|
alias [] messages_for
|
302
267
|
|
303
|
-
|
304
|
-
# Checks if any errors are present.
|
268
|
+
# Checks if the error collection contains any errors.
|
305
269
|
#
|
306
|
-
# @return [Boolean] true if errors
|
270
|
+
# @return [Boolean] true if there are any errors present
|
307
271
|
#
|
308
|
-
# @example
|
309
|
-
# errors = Errors.new
|
310
|
-
# errors.present?
|
272
|
+
# @example Check if errors are present
|
273
|
+
# errors = CMDx::Errors.new
|
274
|
+
# errors.present? # => false
|
311
275
|
# errors.add(:name, "is required")
|
312
|
-
# errors.present?
|
276
|
+
# errors.present? # => true
|
313
277
|
def present?
|
314
278
|
!blank?
|
315
279
|
end
|
316
280
|
|
317
|
-
|
318
|
-
# Converts the errors collection to a hash representation.
|
281
|
+
# Converts the error collection to a hash representation.
|
319
282
|
#
|
320
283
|
# @param full_messages [Boolean] whether to include full formatted messages
|
284
|
+
#
|
321
285
|
# @return [Hash] hash representation of errors
|
322
286
|
#
|
323
|
-
# @example
|
324
|
-
# errors
|
325
|
-
# errors.
|
287
|
+
# @example Get raw error messages hash
|
288
|
+
# errors = CMDx::Errors.new
|
289
|
+
# errors.add(:name, "is required")
|
290
|
+
# errors.to_hash # => { name: ["is required"] }
|
326
291
|
#
|
327
|
-
# @example
|
328
|
-
# errors.
|
329
|
-
# errors.to_hash(true) #=> {:email => ["email is required"]}
|
292
|
+
# @example Get full formatted messages hash
|
293
|
+
# errors.to_hash(true) # => { name: ["name is required"] }
|
330
294
|
#
|
331
|
-
# @example
|
332
|
-
# errors
|
333
|
-
# errors.
|
334
|
-
# errors.as_json #=> same as to_hash
|
295
|
+
# @example Empty errors return empty hash
|
296
|
+
# errors = CMDx::Errors.new
|
297
|
+
# errors.to_hash # => {}
|
335
298
|
def to_hash(full_messages = false)
|
336
299
|
return errors unless full_messages
|
337
300
|
|