cmdx 1.1.2 → 1.5.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/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +4 -1
- data/.cursor/prompts/llms.md +20 -0
- data/.cursor/prompts/rspec.md +4 -1
- data/.cursor/prompts/yardoc.md +3 -2
- data/.cursor/rules/cursor-instructions.mdc +56 -1
- data/.irbrc +6 -0
- data/.rubocop.yml +29 -18
- data/CHANGELOG.md +5 -133
- data/LLM.md +3317 -0
- data/README.md +68 -44
- data/docs/attributes/coercions.md +162 -0
- data/docs/attributes/defaults.md +90 -0
- data/docs/attributes/definitions.md +281 -0
- data/docs/attributes/naming.md +78 -0
- data/docs/attributes/validations.md +309 -0
- data/docs/basics/chain.md +56 -249
- data/docs/basics/context.md +56 -289
- data/docs/basics/execution.md +114 -0
- data/docs/basics/setup.md +37 -334
- data/docs/callbacks.md +89 -467
- data/docs/deprecation.md +91 -174
- data/docs/getting_started.md +212 -202
- data/docs/internationalization.md +11 -647
- data/docs/interruptions/exceptions.md +23 -198
- data/docs/interruptions/faults.md +71 -151
- data/docs/interruptions/halt.md +109 -186
- data/docs/logging.md +44 -256
- data/docs/middlewares.md +113 -426
- data/docs/outcomes/result.md +81 -228
- data/docs/outcomes/states.md +33 -221
- data/docs/outcomes/statuses.md +21 -311
- data/docs/tips_and_tricks.md +120 -70
- data/docs/workflows.md +99 -283
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/attribute.rb +229 -0
- data/lib/cmdx/attribute_registry.rb +94 -0
- data/lib/cmdx/attribute_value.rb +193 -0
- data/lib/cmdx/callback_registry.rb +69 -77
- data/lib/cmdx/chain.rb +56 -73
- data/lib/cmdx/coercion_registry.rb +52 -68
- data/lib/cmdx/coercions/array.rb +19 -18
- data/lib/cmdx/coercions/big_decimal.rb +20 -24
- data/lib/cmdx/coercions/boolean.rb +26 -25
- data/lib/cmdx/coercions/complex.rb +21 -22
- data/lib/cmdx/coercions/date.rb +25 -23
- data/lib/cmdx/coercions/date_time.rb +24 -25
- data/lib/cmdx/coercions/float.rb +25 -22
- data/lib/cmdx/coercions/hash.rb +31 -32
- data/lib/cmdx/coercions/integer.rb +30 -24
- data/lib/cmdx/coercions/rational.rb +29 -24
- data/lib/cmdx/coercions/string.rb +19 -22
- data/lib/cmdx/coercions/symbol.rb +37 -0
- data/lib/cmdx/coercions/time.rb +26 -25
- data/lib/cmdx/configuration.rb +49 -108
- data/lib/cmdx/context.rb +222 -44
- data/lib/cmdx/deprecator.rb +61 -0
- data/lib/cmdx/errors.rb +42 -252
- data/lib/cmdx/exceptions.rb +39 -0
- data/lib/cmdx/faults.rb +78 -39
- data/lib/cmdx/freezer.rb +51 -0
- data/lib/cmdx/identifier.rb +30 -0
- data/lib/cmdx/locale.rb +52 -0
- data/lib/cmdx/log_formatters/json.rb +21 -22
- data/lib/cmdx/log_formatters/key_value.rb +20 -22
- data/lib/cmdx/log_formatters/line.rb +15 -22
- data/lib/cmdx/log_formatters/logstash.rb +22 -23
- data/lib/cmdx/log_formatters/raw.rb +16 -22
- data/lib/cmdx/middleware_registry.rb +70 -74
- data/lib/cmdx/middlewares/correlate.rb +90 -54
- data/lib/cmdx/middlewares/runtime.rb +58 -0
- data/lib/cmdx/middlewares/timeout.rb +48 -68
- data/lib/cmdx/railtie.rb +12 -45
- data/lib/cmdx/result.rb +229 -314
- data/lib/cmdx/task.rb +194 -366
- data/lib/cmdx/utils/call.rb +49 -0
- data/lib/cmdx/utils/condition.rb +71 -0
- data/lib/cmdx/utils/format.rb +61 -0
- data/lib/cmdx/validator_registry.rb +63 -72
- data/lib/cmdx/validators/exclusion.rb +38 -67
- data/lib/cmdx/validators/format.rb +48 -49
- data/lib/cmdx/validators/inclusion.rb +43 -74
- data/lib/cmdx/validators/length.rb +91 -154
- data/lib/cmdx/validators/numeric.rb +87 -162
- data/lib/cmdx/validators/presence.rb +37 -50
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/worker.rb +178 -0
- data/lib/cmdx/workflow.rb +85 -81
- data/lib/cmdx.rb +19 -13
- data/lib/generators/cmdx/install_generator.rb +14 -13
- data/lib/generators/cmdx/task_generator.rb +25 -50
- data/lib/generators/cmdx/templates/install.rb +11 -46
- data/lib/generators/cmdx/templates/task.rb.tt +3 -2
- data/lib/locales/en.yml +18 -4
- data/src/cmdx-logo.png +0 -0
- metadata +32 -116
- data/docs/ai_prompts.md +0 -393
- data/docs/basics/call.md +0 -317
- data/docs/configuration.md +0 -344
- data/docs/parameters/coercions.md +0 -396
- data/docs/parameters/defaults.md +0 -335
- data/docs/parameters/definitions.md +0 -446
- data/docs/parameters/namespacing.md +0 -378
- data/docs/parameters/validations.md +0 -405
- data/docs/testing.md +0 -553
- data/lib/cmdx/callback.rb +0 -53
- data/lib/cmdx/chain_inspector.rb +0 -56
- data/lib/cmdx/chain_serializer.rb +0 -63
- data/lib/cmdx/coercion.rb +0 -57
- data/lib/cmdx/coercions/virtual.rb +0 -29
- data/lib/cmdx/core_ext/hash.rb +0 -83
- data/lib/cmdx/core_ext/module.rb +0 -98
- data/lib/cmdx/core_ext/object.rb +0 -125
- data/lib/cmdx/correlator.rb +0 -122
- data/lib/cmdx/error.rb +0 -67
- data/lib/cmdx/fault.rb +0 -140
- data/lib/cmdx/immutator.rb +0 -52
- data/lib/cmdx/lazy_struct.rb +0 -246
- data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
- data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
- data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
- data/lib/cmdx/logger.rb +0 -49
- data/lib/cmdx/logger_ansi.rb +0 -68
- data/lib/cmdx/logger_serializer.rb +0 -116
- data/lib/cmdx/middleware.rb +0 -70
- data/lib/cmdx/parameter.rb +0 -312
- data/lib/cmdx/parameter_evaluator.rb +0 -231
- data/lib/cmdx/parameter_inspector.rb +0 -66
- data/lib/cmdx/parameter_registry.rb +0 -106
- data/lib/cmdx/parameter_serializer.rb +0 -59
- data/lib/cmdx/result_ansi.rb +0 -71
- data/lib/cmdx/result_inspector.rb +0 -71
- data/lib/cmdx/result_logger.rb +0 -59
- data/lib/cmdx/result_serializer.rb +0 -104
- data/lib/cmdx/rspec/matchers.rb +0 -28
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
- data/lib/cmdx/task_deprecator.rb +0 -58
- data/lib/cmdx/task_processor.rb +0 -246
- data/lib/cmdx/task_serializer.rb +0 -57
- data/lib/cmdx/utils/ansi_color.rb +0 -73
- data/lib/cmdx/utils/log_timestamp.rb +0 -36
- data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
- data/lib/cmdx/utils/name_affix.rb +0 -52
- data/lib/cmdx/validator.rb +0 -57
- data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
- data/lib/generators/cmdx/workflow_generator.rb +0 -84
- data/lib/locales/ar.yml +0 -35
- data/lib/locales/cs.yml +0 -35
- data/lib/locales/da.yml +0 -35
- data/lib/locales/de.yml +0 -35
- data/lib/locales/el.yml +0 -35
- data/lib/locales/es.yml +0 -35
- data/lib/locales/fi.yml +0 -35
- data/lib/locales/fr.yml +0 -35
- data/lib/locales/he.yml +0 -35
- data/lib/locales/hi.yml +0 -35
- data/lib/locales/it.yml +0 -35
- data/lib/locales/ja.yml +0 -35
- data/lib/locales/ko.yml +0 -35
- data/lib/locales/nl.yml +0 -35
- data/lib/locales/no.yml +0 -35
- data/lib/locales/pl.yml +0 -35
- data/lib/locales/pt.yml +0 -35
- data/lib/locales/ru.yml +0 -35
- data/lib/locales/sv.yml +0 -35
- data/lib/locales/th.yml +0 -35
- data/lib/locales/tr.yml +0 -35
- data/lib/locales/vi.yml +0 -35
- data/lib/locales/zh.yml +0 -35
@@ -2,232 +2,157 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Validators
|
5
|
-
#
|
5
|
+
# Validates numeric values against various constraints and ranges
|
6
6
|
#
|
7
7
|
# This validator ensures that numeric values meet specified criteria such as
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @param
|
17
|
-
# @
|
18
|
-
# @option options [Range] :
|
19
|
-
# @option options [Range] :
|
20
|
-
# @option options [Range] :
|
21
|
-
# @option options [Range] :
|
22
|
-
# @option options [Numeric] :
|
23
|
-
# @option options [Numeric] :
|
24
|
-
# @option options [Numeric] :
|
25
|
-
# @option options [Numeric] :
|
26
|
-
# @option options [String] :
|
27
|
-
# @option options [String] :
|
28
|
-
# @option options [String] :
|
29
|
-
# @option options [String] :
|
30
|
-
# @option options [String] :
|
31
|
-
# @option options [String] :
|
32
|
-
# @option options [String] :
|
33
|
-
#
|
34
|
-
# @
|
35
|
-
#
|
36
|
-
# @
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# @
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# @example
|
46
|
-
#
|
47
|
-
# #
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# #=> nil (no error raised)
|
52
|
-
#
|
53
|
-
# @example Minimum value validation
|
54
|
-
# Validators::Numeric.call(5, numeric: { min: 10 })
|
55
|
-
# # raises ValidationError: "must be at least 10"
|
56
|
-
#
|
57
|
-
# @example Exact value validation
|
58
|
-
# Validators::Numeric.call(42, numeric: { is: 42 })
|
59
|
-
# #=> nil (no error raised)
|
60
|
-
#
|
61
|
-
# @example Custom error message
|
62
|
-
# Validators::Numeric.call(5, numeric: { min: 10, message: "Age must be at least %{min}" })
|
63
|
-
# # raises ValidationError: "Age must be at least 10"
|
8
|
+
# minimum/maximum bounds, exact matches, or range inclusions. It supports
|
9
|
+
# both inclusive and exclusive range validations with customizable error messages.
|
10
|
+
module Numeric
|
11
|
+
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# Validates a numeric value against the specified options
|
15
|
+
#
|
16
|
+
# @param value [Numeric] The numeric value to validate
|
17
|
+
# @param options [Hash] Validation configuration options
|
18
|
+
# @option options [Range] :within Range that the value must fall within (inclusive)
|
19
|
+
# @option options [Range] :not_within Range that the value must not fall within
|
20
|
+
# @option options [Range] :in Alias for :within option
|
21
|
+
# @option options [Range] :not_in Alias for :not_within option
|
22
|
+
# @option options [Numeric] :min Minimum allowed value (inclusive)
|
23
|
+
# @option options [Numeric] :max Maximum allowed value (inclusive)
|
24
|
+
# @option options [Numeric] :is Exact value that must match
|
25
|
+
# @option options [Numeric] :is_not Value that must not match
|
26
|
+
# @option options [String] :message Custom error message template
|
27
|
+
# @option options [String] :within_message Custom message for range validations
|
28
|
+
# @option options [String] :not_within_message Custom message for exclusion validations
|
29
|
+
# @option options [String] :min_message Custom message for minimum validation
|
30
|
+
# @option options [String] :max_message Custom message for maximum validation
|
31
|
+
# @option options [String] :is_message Custom message for exact match validation
|
32
|
+
# @option options [String] :is_not_message Custom message for exclusion validation
|
33
|
+
#
|
34
|
+
# @return [nil] Returns nil if validation passes
|
35
|
+
#
|
36
|
+
# @raise [ValidationError] When the value fails validation
|
37
|
+
# @raise [ArgumentError] When unknown validator options are provided
|
38
|
+
#
|
39
|
+
# @example Validate value within a range
|
40
|
+
# Numeric.call(5, within: 1..10)
|
41
|
+
# # => nil (validation passes)
|
42
|
+
# @example Validate minimum and maximum bounds
|
43
|
+
# Numeric.call(15, min: 10, max: 20)
|
44
|
+
# # => nil (validation passes)
|
45
|
+
# @example Validate exact value match
|
46
|
+
# Numeric.call(42, is: 42)
|
47
|
+
# # => nil (validation passes)
|
48
|
+
# @example Validate value exclusion
|
49
|
+
# Numeric.call(5, not_in: 1..10)
|
50
|
+
# # => nil (validation passes - 5 is not in 1..10)
|
64
51
|
def call(value, options = {})
|
65
52
|
case options
|
66
|
-
in
|
53
|
+
in within:
|
67
54
|
raise_within_validation_error!(within.begin, within.end, options) unless within.cover?(value)
|
68
|
-
in
|
55
|
+
in not_within:
|
69
56
|
raise_not_within_validation_error!(not_within.begin, not_within.end, options) if not_within.cover?(value)
|
70
|
-
in
|
71
|
-
raise_within_validation_error!(
|
72
|
-
in
|
57
|
+
in in: xin
|
58
|
+
raise_within_validation_error!(xin.begin, xin.end, options) unless xin.cover?(value)
|
59
|
+
in not_in:
|
73
60
|
raise_not_within_validation_error!(not_in.begin, not_in.end, options) if not_in.cover?(value)
|
74
|
-
in
|
61
|
+
in min:, max:
|
75
62
|
raise_within_validation_error!(min, max, options) unless value.between?(min, max)
|
76
|
-
in
|
63
|
+
in min:
|
77
64
|
raise_min_validation_error!(min, options) unless min <= value
|
78
|
-
in
|
65
|
+
in max:
|
79
66
|
raise_max_validation_error!(max, options) unless value <= max
|
80
|
-
in
|
67
|
+
in is:
|
81
68
|
raise_is_validation_error!(is, options) unless value == is
|
82
|
-
in
|
69
|
+
in is_not:
|
83
70
|
raise_is_not_validation_error!(is_not, options) if value == is_not
|
84
71
|
else
|
85
|
-
raise ArgumentError, "
|
72
|
+
raise ArgumentError, "unknown numeric validator options given"
|
86
73
|
end
|
87
74
|
end
|
88
75
|
|
89
76
|
private
|
90
77
|
|
91
|
-
# Raises
|
78
|
+
# Raises validation error for range inclusion validation
|
92
79
|
#
|
93
|
-
# @param min [Numeric]
|
94
|
-
# @param max [Numeric]
|
95
|
-
# @param options [Hash]
|
80
|
+
# @param min [Numeric] The minimum value of the allowed range
|
81
|
+
# @param max [Numeric] The maximum value of the allowed range
|
82
|
+
# @param options [Hash] Validation options containing custom messages
|
96
83
|
#
|
97
|
-
# @
|
98
|
-
#
|
99
|
-
# @raise [ValidationError] always raised with appropriate message
|
100
|
-
#
|
101
|
-
# @example
|
102
|
-
# raise_within_validation_error!(1, 10, {})
|
103
|
-
# # raises ValidationError: "must be within 1 and 10"
|
84
|
+
# @raise [ValidationError] With appropriate error message
|
104
85
|
def raise_within_validation_error!(min, max, options)
|
105
86
|
message = options[:within_message] || options[:in_message] || options[:message]
|
106
87
|
message %= { min:, max: } unless message.nil?
|
107
88
|
|
108
|
-
raise ValidationError, message ||
|
109
|
-
"cmdx.validators.numeric.within",
|
110
|
-
min:,
|
111
|
-
max:,
|
112
|
-
default: "must be within #{min} and #{max}"
|
113
|
-
)
|
89
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.within", min:, max:)
|
114
90
|
end
|
115
91
|
|
116
|
-
# Raises
|
117
|
-
#
|
118
|
-
# @param min [Numeric] the minimum value of the excluded range
|
119
|
-
# @param max [Numeric] the maximum value of the excluded range
|
120
|
-
# @param options [Hash] validation options
|
92
|
+
# Raises validation error for range exclusion validation
|
121
93
|
#
|
122
|
-
# @
|
94
|
+
# @param min [Numeric] The minimum value of the excluded range
|
95
|
+
# @param max [Numeric] The maximum value of the excluded range
|
96
|
+
# @param options [Hash] Validation options containing custom messages
|
123
97
|
#
|
124
|
-
# @raise [ValidationError]
|
125
|
-
#
|
126
|
-
# @example
|
127
|
-
# raise_not_within_validation_error!(1, 10, {})
|
128
|
-
# # raises ValidationError: "must not be within 1 and 10"
|
98
|
+
# @raise [ValidationError] With appropriate error message
|
129
99
|
def raise_not_within_validation_error!(min, max, options)
|
130
100
|
message = options[:not_within_message] || options[:not_in_message] || options[:message]
|
131
101
|
message %= { min:, max: } unless message.nil?
|
132
102
|
|
133
|
-
raise ValidationError, message ||
|
134
|
-
"cmdx.validators.numeric.not_within",
|
135
|
-
min:,
|
136
|
-
max:,
|
137
|
-
default: "must not be within #{min} and #{max}"
|
138
|
-
)
|
103
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.not_within", min:, max:)
|
139
104
|
end
|
140
105
|
|
141
|
-
# Raises
|
142
|
-
#
|
143
|
-
# @param min [Numeric] the minimum allowed value
|
144
|
-
# @param options [Hash] validation options
|
145
|
-
#
|
146
|
-
# @return [void]
|
106
|
+
# Raises validation error for minimum value validation
|
147
107
|
#
|
148
|
-
# @
|
108
|
+
# @param min [Numeric] The minimum allowed value
|
109
|
+
# @param options [Hash] Validation options containing custom messages
|
149
110
|
#
|
150
|
-
# @
|
151
|
-
# raise_min_validation_error!(10, {})
|
152
|
-
# # raises ValidationError: "must be at least 10"
|
111
|
+
# @raise [ValidationError] With appropriate error message
|
153
112
|
def raise_min_validation_error!(min, options)
|
154
113
|
message = options[:min_message] || options[:message]
|
155
114
|
message %= { min: } unless message.nil?
|
156
115
|
|
157
|
-
raise ValidationError, message ||
|
158
|
-
"cmdx.validators.numeric.min",
|
159
|
-
min:,
|
160
|
-
default: "must be at least #{min}"
|
161
|
-
)
|
116
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.min", min:)
|
162
117
|
end
|
163
118
|
|
164
|
-
# Raises
|
119
|
+
# Raises validation error for maximum value validation
|
165
120
|
#
|
166
|
-
# @param max [Numeric]
|
167
|
-
# @param options [Hash]
|
121
|
+
# @param max [Numeric] The maximum allowed value
|
122
|
+
# @param options [Hash] Validation options containing custom messages
|
168
123
|
#
|
169
|
-
# @
|
170
|
-
#
|
171
|
-
# @raise [ValidationError] always raised with appropriate message
|
172
|
-
#
|
173
|
-
# @example
|
174
|
-
# raise_max_validation_error!(100, {})
|
175
|
-
# # raises ValidationError: "must be at most 100"
|
124
|
+
# @raise [ValidationError] With appropriate error message
|
176
125
|
def raise_max_validation_error!(max, options)
|
177
126
|
message = options[:max_message] || options[:message]
|
178
127
|
message %= { max: } unless message.nil?
|
179
128
|
|
180
|
-
raise ValidationError, message ||
|
181
|
-
"cmdx.validators.numeric.max",
|
182
|
-
max:,
|
183
|
-
default: "must be at most #{max}"
|
184
|
-
)
|
129
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.max", max:)
|
185
130
|
end
|
186
131
|
|
187
|
-
# Raises
|
188
|
-
#
|
189
|
-
# @param is [Numeric] the exact value required
|
190
|
-
# @param options [Hash] validation options
|
132
|
+
# Raises validation error for exact value match validation
|
191
133
|
#
|
192
|
-
# @
|
134
|
+
# @param is [Numeric] The exact value that was expected
|
135
|
+
# @param options [Hash] Validation options containing custom messages
|
193
136
|
#
|
194
|
-
# @raise [ValidationError]
|
195
|
-
#
|
196
|
-
# @example
|
197
|
-
# raise_is_validation_error!(42, {})
|
198
|
-
# # raises ValidationError: "must be 42"
|
137
|
+
# @raise [ValidationError] With appropriate error message
|
199
138
|
def raise_is_validation_error!(is, options)
|
200
139
|
message = options[:is_message] || options[:message]
|
201
140
|
message %= { is: } unless message.nil?
|
202
141
|
|
203
|
-
raise ValidationError, message ||
|
204
|
-
"cmdx.validators.numeric.is",
|
205
|
-
is:,
|
206
|
-
default: "must be #{is}"
|
207
|
-
)
|
142
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.is", is:)
|
208
143
|
end
|
209
144
|
|
210
|
-
# Raises
|
211
|
-
#
|
212
|
-
# @param is_not [Numeric] the exact value that is not allowed
|
213
|
-
# @param options [Hash] validation options
|
214
|
-
#
|
215
|
-
# @return [void]
|
145
|
+
# Raises validation error for value exclusion validation
|
216
146
|
#
|
217
|
-
# @
|
147
|
+
# @param is_not [Numeric] The value that was not allowed
|
148
|
+
# @param options [Hash] Validation options containing custom messages
|
218
149
|
#
|
219
|
-
# @
|
220
|
-
# raise_is_not_validation_error!(0, {})
|
221
|
-
# # raises ValidationError: "must not be 0"
|
150
|
+
# @raise [ValidationError] With appropriate error message
|
222
151
|
def raise_is_not_validation_error!(is_not, options)
|
223
152
|
message = options[:is_not_message] || options[:message]
|
224
153
|
message %= { is_not: } unless message.nil?
|
225
154
|
|
226
|
-
raise ValidationError, message ||
|
227
|
-
"cmdx.validators.numeric.is_not",
|
228
|
-
is_not:,
|
229
|
-
default: "must not be #{is_not}"
|
230
|
-
)
|
155
|
+
raise ValidationError, message || Locale.t("cmdx.validators.numeric.is_not", is_not:)
|
231
156
|
end
|
232
157
|
|
233
158
|
end
|
@@ -2,54 +2,44 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Validators
|
5
|
-
#
|
5
|
+
# Validates that a value is present and not empty
|
6
6
|
#
|
7
|
-
# This validator
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
|
7
|
+
# This validator ensures that the given value exists and contains meaningful content.
|
8
|
+
# It handles different value types appropriately:
|
9
|
+
# - Strings: checks for non-whitespace characters
|
10
|
+
# - Collections: checks for non-empty collections
|
11
|
+
# - Other objects: checks for non-nil values
|
12
|
+
module Presence
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# @
|
18
|
-
# @
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# @example
|
29
|
-
#
|
30
|
-
# # raises ValidationError
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# @example Validating an empty array
|
41
|
-
# Validators::Presence.call([], presence: {})
|
42
|
-
# # raises ValidationError: "cannot be empty"
|
43
|
-
#
|
44
|
-
# @example Validating a nil value
|
45
|
-
# Validators::Presence.call(nil, presence: {})
|
46
|
-
# # raises ValidationError: "cannot be empty"
|
47
|
-
#
|
48
|
-
# @example Using a custom message
|
49
|
-
# Validators::Presence.call("", presence: { message: "This field is required" })
|
50
|
-
# # raises ValidationError: "This field is required"
|
14
|
+
extend self
|
15
|
+
|
16
|
+
# Validates that a value is present and not empty
|
17
|
+
#
|
18
|
+
# @param value [Object] The value to validate for presence
|
19
|
+
# @param options [Hash] Validation configuration options
|
20
|
+
# @option options [String] :message Custom error message
|
21
|
+
#
|
22
|
+
# @return [nil] Returns nil if validation passes
|
23
|
+
#
|
24
|
+
# @raise [ValidationError] When the value is empty, nil, or contains only whitespace
|
25
|
+
#
|
26
|
+
# @example Validate string presence
|
27
|
+
# Presence.call("hello world")
|
28
|
+
# # => nil (validation passes)
|
29
|
+
# @example Validate empty string
|
30
|
+
# Presence.call(" ")
|
31
|
+
# # => raises ValidationError
|
32
|
+
# @example Validate array presence
|
33
|
+
# Presence.call([1, 2, 3])
|
34
|
+
# # => nil (validation passes)
|
35
|
+
# @example Validate empty array
|
36
|
+
# Presence.call([])
|
37
|
+
# # => raises ValidationError
|
38
|
+
# @example Validate with custom message
|
39
|
+
# Presence.call(nil, message: "Value cannot be blank")
|
40
|
+
# # => raises ValidationError with custom message
|
51
41
|
def call(value, options = {})
|
52
|
-
|
42
|
+
match =
|
53
43
|
if value.is_a?(String)
|
54
44
|
/\S/.match?(value)
|
55
45
|
elsif value.respond_to?(:empty?)
|
@@ -58,13 +48,10 @@ module CMDx
|
|
58
48
|
!value.nil?
|
59
49
|
end
|
60
50
|
|
61
|
-
return if
|
51
|
+
return if match
|
62
52
|
|
63
53
|
message = options[:message] if options.is_a?(Hash)
|
64
|
-
raise ValidationError, message ||
|
65
|
-
"cmdx.validators.presence",
|
66
|
-
default: "cannot be empty"
|
67
|
-
)
|
54
|
+
raise ValidationError, message || Locale.t("cmdx.validators.presence")
|
68
55
|
end
|
69
56
|
|
70
57
|
end
|
data/lib/cmdx/version.rb
CHANGED
data/lib/cmdx/worker.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
# Executes CMDx tasks with middleware support, error handling, and lifecycle management.
|
5
|
+
#
|
6
|
+
# The Worker class is responsible for orchestrating task execution, including
|
7
|
+
# pre-execution validation, execution with middleware, post-execution callbacks,
|
8
|
+
# and proper error handling for different types of failures.
|
9
|
+
class Worker
|
10
|
+
|
11
|
+
attr_reader :task
|
12
|
+
|
13
|
+
# @param task [CMDx::Task] The task to execute
|
14
|
+
#
|
15
|
+
# @return [CMDx::Worker] A new worker instance
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# worker = CMDx::Worker.new(my_task)
|
19
|
+
def initialize(task)
|
20
|
+
@task = task
|
21
|
+
end
|
22
|
+
|
23
|
+
# Executes a task with optional exception raising.
|
24
|
+
#
|
25
|
+
# @param task [CMDx::Task] The task to execute
|
26
|
+
# @param raise [Boolean] Whether to raise exceptions (default: false)
|
27
|
+
#
|
28
|
+
# @return [CMDx::Result] The execution result
|
29
|
+
#
|
30
|
+
# @raise [StandardError] When raise is true and execution fails
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# CMDx::Worker.execute(my_task)
|
34
|
+
# CMDx::Worker.execute(my_task, raise: true)
|
35
|
+
def self.execute(task, raise: false)
|
36
|
+
instance = new(task)
|
37
|
+
raise ? instance.execute! : instance.execute
|
38
|
+
end
|
39
|
+
|
40
|
+
# Executes the task with graceful error handling.
|
41
|
+
#
|
42
|
+
# @return [CMDx::Result] The execution result
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
# worker = CMDx::Worker.new(my_task)
|
46
|
+
# result = worker.execute
|
47
|
+
def execute
|
48
|
+
task.class.settings[:middlewares].call!(task) do
|
49
|
+
pre_execution!
|
50
|
+
execution!
|
51
|
+
rescue UndefinedMethodError => e
|
52
|
+
raise(e) # No need to clear the Chain since exception is not being re-raised
|
53
|
+
rescue Fault => e
|
54
|
+
task.result.throw!(e.result, halt: false, cause: e)
|
55
|
+
rescue StandardError => e
|
56
|
+
task.result.fail!("[#{e.class}] #{e.message}", halt: false, cause: e)
|
57
|
+
ensure
|
58
|
+
task.result.executed!
|
59
|
+
post_execution!
|
60
|
+
end
|
61
|
+
|
62
|
+
finalize_execution!
|
63
|
+
end
|
64
|
+
|
65
|
+
# Executes the task with exception raising on failure.
|
66
|
+
#
|
67
|
+
# @return [CMDx::Result] The execution result
|
68
|
+
#
|
69
|
+
# @raise [StandardError] When execution fails
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# worker = CMDx::Worker.new(my_task)
|
73
|
+
# result = worker.execute!
|
74
|
+
def execute!
|
75
|
+
task.class.settings[:middlewares].call!(task) do
|
76
|
+
pre_execution!
|
77
|
+
execution!
|
78
|
+
rescue UndefinedMethodError => e
|
79
|
+
raise_exception(e)
|
80
|
+
rescue Fault => e
|
81
|
+
task.result.throw!(e.result, halt: false, cause: e)
|
82
|
+
halt_execution?(e) ? raise_exception(e) : post_execution!
|
83
|
+
rescue StandardError => e
|
84
|
+
task.result.fail!("[#{e.class}] #{e.message}", halt: false, cause: e)
|
85
|
+
raise_exception(e)
|
86
|
+
else
|
87
|
+
task.result.executed!
|
88
|
+
post_execution!
|
89
|
+
end
|
90
|
+
|
91
|
+
finalize_execution!
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
# Determines if execution should halt based on breakpoint configuration.
|
97
|
+
#
|
98
|
+
# @param exception [Exception] The exception that occurred
|
99
|
+
#
|
100
|
+
# @return [Boolean] Whether execution should halt
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# halt_execution?(fault_exception)
|
104
|
+
def halt_execution?(exception)
|
105
|
+
breakpoints = task.class.settings[:breakpoints] || task.class.settings[:task_breakpoints]
|
106
|
+
breakpoints = Array(breakpoints).map(&:to_s).uniq
|
107
|
+
|
108
|
+
breakpoints.include?(exception.result.status)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Raises an exception and clears the chain.
|
112
|
+
#
|
113
|
+
# @param exception [Exception] The exception to raise
|
114
|
+
#
|
115
|
+
# @raise [Exception] The provided exception
|
116
|
+
#
|
117
|
+
# @example
|
118
|
+
# raise_exception(standard_error)
|
119
|
+
def raise_exception(exception)
|
120
|
+
Chain.clear
|
121
|
+
raise(exception)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Invokes callbacks of a specific type for the task.
|
125
|
+
#
|
126
|
+
# @param type [Symbol] The type of callback to invoke
|
127
|
+
#
|
128
|
+
# @return [void]
|
129
|
+
#
|
130
|
+
# @example
|
131
|
+
# invoke_callbacks(:before_execution)
|
132
|
+
def invoke_callbacks(type)
|
133
|
+
task.class.settings[:callbacks].invoke(type, task)
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
# Performs pre-execution tasks including validation and attribute verification.
|
139
|
+
def pre_execution!
|
140
|
+
invoke_callbacks(:before_validation)
|
141
|
+
|
142
|
+
task.class.settings[:attributes].define_and_verify(task)
|
143
|
+
return if task.errors.empty?
|
144
|
+
|
145
|
+
task.result.fail!(task.errors.to_s, messages: task.errors.to_h)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Executes the main task logic.
|
149
|
+
def execution!
|
150
|
+
invoke_callbacks(:before_execution)
|
151
|
+
|
152
|
+
task.result.executing!
|
153
|
+
task.work
|
154
|
+
end
|
155
|
+
|
156
|
+
# Performs post-execution tasks including callback invocation.
|
157
|
+
def post_execution!
|
158
|
+
invoke_callbacks(:"on_#{task.result.state}")
|
159
|
+
invoke_callbacks(:on_executed) if task.result.executed?
|
160
|
+
|
161
|
+
invoke_callbacks(:"on_#{task.result.status}")
|
162
|
+
invoke_callbacks(:on_good) if task.result.good?
|
163
|
+
invoke_callbacks(:on_bad) if task.result.bad?
|
164
|
+
end
|
165
|
+
|
166
|
+
# Finalizes execution by freezing the task and logging results.
|
167
|
+
def finalize_execution!
|
168
|
+
Freezer.immute(task)
|
169
|
+
|
170
|
+
task.logger.tap do |logger|
|
171
|
+
logger.with_level(:info) do
|
172
|
+
logger.info { task.result.to_h }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|