cmdx 1.21.0 → 2.0.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/CHANGELOG.md +118 -1
- data/README.md +37 -24
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callbacks.rb +179 -0
- data/lib/cmdx/chain.rb +78 -175
- data/lib/cmdx/coercions/array.rb +19 -33
- data/lib/cmdx/coercions/big_decimal.rb +12 -29
- data/lib/cmdx/coercions/boolean.rb +25 -45
- data/lib/cmdx/coercions/coerce.rb +32 -0
- data/lib/cmdx/coercions/complex.rb +12 -27
- data/lib/cmdx/coercions/date.rb +29 -33
- data/lib/cmdx/coercions/date_time.rb +29 -33
- data/lib/cmdx/coercions/float.rb +8 -29
- data/lib/cmdx/coercions/hash.rb +17 -43
- data/lib/cmdx/coercions/integer.rb +8 -32
- data/lib/cmdx/coercions/rational.rb +12 -33
- data/lib/cmdx/coercions/string.rb +6 -24
- data/lib/cmdx/coercions/symbol.rb +12 -26
- data/lib/cmdx/coercions/time.rb +31 -35
- data/lib/cmdx/coercions.rb +174 -0
- data/lib/cmdx/configuration.rb +45 -237
- data/lib/cmdx/context.rb +264 -243
- data/lib/cmdx/deprecation.rb +67 -0
- data/lib/cmdx/deprecators/error.rb +22 -0
- data/lib/cmdx/deprecators/log.rb +22 -0
- data/lib/cmdx/deprecators/warn.rb +21 -0
- data/lib/cmdx/deprecators.rb +101 -0
- data/lib/cmdx/errors.rb +145 -79
- data/lib/cmdx/executors/fiber.rb +42 -0
- data/lib/cmdx/executors/thread.rb +36 -0
- data/lib/cmdx/executors.rb +95 -0
- data/lib/cmdx/fault.rb +85 -78
- data/lib/cmdx/i18n_proxy.rb +104 -0
- data/lib/cmdx/input.rb +294 -0
- data/lib/cmdx/inputs.rb +218 -0
- data/lib/cmdx/log_formatters/json.rb +9 -20
- data/lib/cmdx/log_formatters/key_value.rb +10 -21
- data/lib/cmdx/log_formatters/line.rb +7 -19
- data/lib/cmdx/log_formatters/logstash.rb +8 -21
- data/lib/cmdx/log_formatters/raw.rb +8 -20
- data/lib/cmdx/logger_proxy.rb +30 -0
- data/lib/cmdx/mergers/deep_merge.rb +23 -0
- data/lib/cmdx/mergers/last_write_wins.rb +23 -0
- data/lib/cmdx/mergers/no_merge.rb +20 -0
- data/lib/cmdx/mergers.rb +95 -0
- data/lib/cmdx/middlewares.rb +128 -0
- data/lib/cmdx/output.rb +115 -0
- data/lib/cmdx/outputs.rb +66 -0
- data/lib/cmdx/pipeline.rb +144 -131
- data/lib/cmdx/railtie.rb +10 -36
- data/lib/cmdx/result.rb +247 -524
- data/lib/cmdx/retriers/bounded_random.rb +24 -0
- data/lib/cmdx/retriers/decorrelated_jitter.rb +28 -0
- data/lib/cmdx/retriers/exponential.rb +23 -0
- data/lib/cmdx/retriers/fibonacci.rb +39 -0
- data/lib/cmdx/retriers/full_random.rb +23 -0
- data/lib/cmdx/retriers/half_random.rb +24 -0
- data/lib/cmdx/retriers/linear.rb +23 -0
- data/lib/cmdx/retriers.rb +106 -0
- data/lib/cmdx/retry.rb +117 -138
- data/lib/cmdx/runtime.rb +251 -0
- data/lib/cmdx/settings.rb +68 -200
- data/lib/cmdx/signal.rb +165 -0
- data/lib/cmdx/task.rb +443 -343
- data/lib/cmdx/telemetry.rb +108 -0
- data/lib/cmdx/util.rb +73 -0
- data/lib/cmdx/validators/absence.rb +10 -39
- data/lib/cmdx/validators/exclusion.rb +33 -52
- data/lib/cmdx/validators/format.rb +19 -49
- data/lib/cmdx/validators/inclusion.rb +33 -54
- data/lib/cmdx/validators/length.rb +125 -127
- data/lib/cmdx/validators/numeric.rb +123 -123
- data/lib/cmdx/validators/presence.rb +10 -39
- data/lib/cmdx/validators/validate.rb +31 -0
- data/lib/cmdx/validators.rb +161 -0
- data/lib/cmdx/version.rb +2 -4
- data/lib/cmdx/workflow.rb +71 -96
- data/lib/cmdx.rb +111 -42
- data/lib/generators/cmdx/install_generator.rb +7 -17
- data/lib/generators/cmdx/task_generator.rb +12 -29
- data/lib/generators/cmdx/templates/install.rb +120 -48
- data/lib/generators/cmdx/templates/task.rb.tt +1 -1
- data/lib/generators/cmdx/templates/workflow.rb.tt +1 -2
- data/lib/generators/cmdx/workflow_generator.rb +12 -29
- data/lib/locales/en.yml +8 -7
- data/mkdocs.yml +25 -23
- metadata +39 -138
- data/lib/cmdx/attribute.rb +0 -440
- data/lib/cmdx/attribute_registry.rb +0 -185
- data/lib/cmdx/attribute_value.rb +0 -252
- data/lib/cmdx/callback_registry.rb +0 -169
- data/lib/cmdx/coercion_registry.rb +0 -138
- data/lib/cmdx/deprecator.rb +0 -77
- data/lib/cmdx/exception.rb +0 -46
- data/lib/cmdx/executor.rb +0 -378
- data/lib/cmdx/identifier.rb +0 -30
- data/lib/cmdx/locale.rb +0 -78
- data/lib/cmdx/middleware_registry.rb +0 -148
- data/lib/cmdx/middlewares/correlate.rb +0 -140
- data/lib/cmdx/middlewares/runtime.rb +0 -77
- data/lib/cmdx/middlewares/timeout.rb +0 -78
- data/lib/cmdx/parallelizer.rb +0 -100
- data/lib/cmdx/utils/call.rb +0 -53
- data/lib/cmdx/utils/condition.rb +0 -71
- data/lib/cmdx/utils/format.rb +0 -82
- data/lib/cmdx/utils/normalize.rb +0 -52
- data/lib/cmdx/utils/wrap.rb +0 -38
- data/lib/cmdx/validator_registry.rb +0 -143
- data/lib/generators/cmdx/locale_generator.rb +0 -39
- data/lib/locales/af.yml +0 -55
- data/lib/locales/ar.yml +0 -55
- data/lib/locales/az.yml +0 -55
- data/lib/locales/be.yml +0 -55
- data/lib/locales/bg.yml +0 -55
- data/lib/locales/bn.yml +0 -55
- data/lib/locales/bs.yml +0 -55
- data/lib/locales/ca.yml +0 -55
- data/lib/locales/cnr.yml +0 -55
- data/lib/locales/cs.yml +0 -55
- data/lib/locales/cy.yml +0 -55
- data/lib/locales/da.yml +0 -55
- data/lib/locales/de.yml +0 -55
- data/lib/locales/dz.yml +0 -55
- data/lib/locales/el.yml +0 -55
- data/lib/locales/eo.yml +0 -55
- data/lib/locales/es.yml +0 -55
- data/lib/locales/et.yml +0 -55
- data/lib/locales/eu.yml +0 -55
- data/lib/locales/fa.yml +0 -55
- data/lib/locales/fi.yml +0 -55
- data/lib/locales/fr.yml +0 -55
- data/lib/locales/fy.yml +0 -55
- data/lib/locales/gd.yml +0 -55
- data/lib/locales/gl.yml +0 -55
- data/lib/locales/he.yml +0 -55
- data/lib/locales/hi.yml +0 -55
- data/lib/locales/hr.yml +0 -55
- data/lib/locales/hu.yml +0 -55
- data/lib/locales/hy.yml +0 -55
- data/lib/locales/id.yml +0 -55
- data/lib/locales/is.yml +0 -55
- data/lib/locales/it.yml +0 -55
- data/lib/locales/ja.yml +0 -55
- data/lib/locales/ka.yml +0 -55
- data/lib/locales/kk.yml +0 -55
- data/lib/locales/km.yml +0 -55
- data/lib/locales/kn.yml +0 -55
- data/lib/locales/ko.yml +0 -55
- data/lib/locales/lb.yml +0 -55
- data/lib/locales/lo.yml +0 -55
- data/lib/locales/lt.yml +0 -55
- data/lib/locales/lv.yml +0 -55
- data/lib/locales/mg.yml +0 -55
- data/lib/locales/mk.yml +0 -55
- data/lib/locales/ml.yml +0 -55
- data/lib/locales/mn.yml +0 -55
- data/lib/locales/mr-IN.yml +0 -55
- data/lib/locales/ms.yml +0 -55
- data/lib/locales/nb.yml +0 -55
- data/lib/locales/ne.yml +0 -55
- data/lib/locales/nl.yml +0 -55
- data/lib/locales/nn.yml +0 -55
- data/lib/locales/oc.yml +0 -55
- data/lib/locales/or.yml +0 -55
- data/lib/locales/pa.yml +0 -55
- data/lib/locales/pl.yml +0 -55
- data/lib/locales/pt.yml +0 -55
- data/lib/locales/rm.yml +0 -55
- data/lib/locales/ro.yml +0 -55
- data/lib/locales/ru.yml +0 -55
- data/lib/locales/sc.yml +0 -55
- data/lib/locales/sk.yml +0 -55
- data/lib/locales/sl.yml +0 -55
- data/lib/locales/sq.yml +0 -55
- data/lib/locales/sr.yml +0 -55
- data/lib/locales/st.yml +0 -55
- data/lib/locales/sv.yml +0 -55
- data/lib/locales/sw.yml +0 -55
- data/lib/locales/ta.yml +0 -55
- data/lib/locales/te.yml +0 -55
- data/lib/locales/th.yml +0 -55
- data/lib/locales/tl.yml +0 -55
- data/lib/locales/tr.yml +0 -55
- data/lib/locales/tt.yml +0 -55
- data/lib/locales/ug.yml +0 -55
- data/lib/locales/uk.yml +0 -55
- data/lib/locales/ur.yml +0 -55
- data/lib/locales/uz.yml +0 -55
- data/lib/locales/vi.yml +0 -55
- data/lib/locales/wo.yml +0 -55
- data/lib/locales/zh-CN.yml +0 -55
- data/lib/locales/zh-HK.yml +0 -55
- data/lib/locales/zh-TW.yml +0 -55
- data/lib/locales/zh-YUE.yml +0 -55
|
@@ -1,80 +1,67 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CMDx
|
|
4
|
-
|
|
5
|
-
# Validates the length of
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
4
|
+
class Validators
|
|
5
|
+
# Validates the `#length` of `value` against one of: `:within` /
|
|
6
|
+
# `:not_within` / `:in` / `:not_in` (Range), `:min` + `:max`,
|
|
7
|
+
# `:gt` / `:lt` (strict comparison), or `:is` / `:is_not` (exact
|
|
8
|
+
# match). `:gte`, `:lte`, `:eq`, `:not_eq` are accepted as aliases
|
|
9
|
+
# of `:min`, `:max`, `:is`, `:is_not` respectively (with matching
|
|
10
|
+
# `_message` overrides). Values without `#length` fail with the
|
|
11
|
+
# `:nil_message` override or a default.
|
|
11
12
|
module Length
|
|
12
13
|
|
|
13
14
|
extend self
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# @
|
|
28
|
-
# @
|
|
29
|
-
# @option options [String] :
|
|
30
|
-
# @option options [String] :
|
|
31
|
-
# @option options [String] :
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# @
|
|
35
|
-
# @
|
|
36
|
-
#
|
|
37
|
-
# @return [nil] Returns nil if validation passes
|
|
38
|
-
#
|
|
39
|
-
# @raise [ValidationError] When validation fails
|
|
40
|
-
# @raise [ArgumentError] When unknown validation options are provided
|
|
41
|
-
#
|
|
42
|
-
# @example Exact length validation
|
|
43
|
-
# Length.call("hello", is: 5)
|
|
44
|
-
# # => nil (validation passes)
|
|
45
|
-
# @example Range-based validation
|
|
46
|
-
# Length.call("test", within: 3..6)
|
|
47
|
-
# # => nil (validation passes - length 4 is within range)
|
|
48
|
-
# @example Min/max validation
|
|
49
|
-
# Length.call("username", min: 3, max: 20)
|
|
50
|
-
# # => nil (validation passes - length 8 is between 3 and 20)
|
|
51
|
-
# @example Exclusion validation
|
|
52
|
-
# Length.call("short", not_in: 1..3)
|
|
53
|
-
# # => nil (validation passes - length 5 is not in excluded range)
|
|
54
|
-
#
|
|
55
|
-
# @rbs (untyped value, Hash[Symbol, untyped] options) -> nil
|
|
16
|
+
ALIASES = {
|
|
17
|
+
gte: :min,
|
|
18
|
+
lte: :max,
|
|
19
|
+
eq: :is,
|
|
20
|
+
not_eq: :is_not,
|
|
21
|
+
gte_message: :min_message,
|
|
22
|
+
lte_message: :max_message,
|
|
23
|
+
eq_message: :is_message,
|
|
24
|
+
not_eq_message: :is_not_message
|
|
25
|
+
}.freeze
|
|
26
|
+
private_constant :ALIASES
|
|
27
|
+
|
|
28
|
+
# @param value [#length, nil]
|
|
29
|
+
# @param options [Hash{Symbol => Object}] see module summary
|
|
30
|
+
# @option options [String] :message global failure-message override
|
|
31
|
+
# @option options [String] :nil_message override when `value` lacks `#length`
|
|
32
|
+
# @option options [String] :within_message, :in_message, :not_within_message,
|
|
33
|
+
# :not_in_message, :min_message, :max_message, :gt_message, :lt_message,
|
|
34
|
+
# :is_message, :is_not_message
|
|
35
|
+
# @return [Validators::Failure, nil]
|
|
36
|
+
# @raise [ArgumentError] when no recognized length option is given
|
|
56
37
|
def call(value, options = EMPTY_HASH)
|
|
57
|
-
|
|
38
|
+
return nil_failure(options) unless value.respond_to?(:length)
|
|
58
39
|
|
|
59
|
-
|
|
40
|
+
length = value.length
|
|
41
|
+
|
|
42
|
+
case options = options.transform_keys(ALIASES)
|
|
60
43
|
in within:
|
|
61
|
-
|
|
44
|
+
within_failure(within.begin, within.end, options) unless within.cover?(length)
|
|
62
45
|
in not_within:
|
|
63
|
-
|
|
46
|
+
not_within_failure(not_within.begin, not_within.end, options) if not_within.cover?(length)
|
|
64
47
|
in in: xin
|
|
65
|
-
|
|
48
|
+
within_failure(xin.begin, xin.end, options) unless xin.cover?(length)
|
|
66
49
|
in not_in:
|
|
67
|
-
|
|
50
|
+
not_within_failure(not_in.begin, not_in.end, options) if not_in.cover?(length)
|
|
68
51
|
in min:, max:
|
|
69
|
-
|
|
52
|
+
within_failure(min, max, options) unless length.between?(min, max)
|
|
70
53
|
in min:
|
|
71
|
-
|
|
54
|
+
min_failure(min, options) unless min <= length
|
|
72
55
|
in max:
|
|
73
|
-
|
|
56
|
+
max_failure(max, options) unless length <= max
|
|
57
|
+
in gt:
|
|
58
|
+
gt_failure(gt, options) unless gt < length
|
|
59
|
+
in lt:
|
|
60
|
+
lt_failure(lt, options) unless length < lt
|
|
74
61
|
in is:
|
|
75
|
-
|
|
62
|
+
is_failure(is, options) unless length == is
|
|
76
63
|
in is_not:
|
|
77
|
-
|
|
64
|
+
is_not_failure(is_not, options) if length == is_not
|
|
78
65
|
else
|
|
79
66
|
raise ArgumentError, "unknown length validator options given"
|
|
80
67
|
end
|
|
@@ -82,102 +69,113 @@ module CMDx
|
|
|
82
69
|
|
|
83
70
|
private
|
|
84
71
|
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# @
|
|
88
|
-
# @
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# @
|
|
95
|
-
|
|
72
|
+
# @param options [Hash{Symbol => Object}]
|
|
73
|
+
# @option options [String] :nil_message
|
|
74
|
+
# @option options [String] :message
|
|
75
|
+
# @return [Validators::Failure]
|
|
76
|
+
def nil_failure(options)
|
|
77
|
+
message = options[:nil_message] || options[:message]
|
|
78
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.nil_value"))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @param min [Object]
|
|
82
|
+
# @param max [Object]
|
|
83
|
+
# @param options [Hash{Symbol => Object}]
|
|
84
|
+
# @option options [String] :within_message
|
|
85
|
+
# @option options [String] :in_message
|
|
86
|
+
# @option options [String] :message
|
|
87
|
+
# @return [Validators::Failure]
|
|
88
|
+
def within_failure(min, max, options)
|
|
96
89
|
message = options[:within_message] || options[:in_message] || options[:message]
|
|
97
90
|
message %= { min:, max: } unless message.nil?
|
|
98
91
|
|
|
99
|
-
|
|
92
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.within", min:, max:))
|
|
100
93
|
end
|
|
101
94
|
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
# @param
|
|
105
|
-
# @
|
|
106
|
-
# @
|
|
107
|
-
# @option options [
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
#
|
|
111
|
-
# @rbs (Integer min, Integer max, Hash[Symbol, untyped] options) -> void
|
|
112
|
-
def raise_not_within_validation_error!(min, max, options)
|
|
95
|
+
# @param min [Object]
|
|
96
|
+
# @param max [Object]
|
|
97
|
+
# @param options [Hash{Symbol => Object}]
|
|
98
|
+
# @option options [String] :not_within_message
|
|
99
|
+
# @option options [String] :not_in_message
|
|
100
|
+
# @option options [String] :message
|
|
101
|
+
# @return [Validators::Failure]
|
|
102
|
+
def not_within_failure(min, max, options)
|
|
113
103
|
message = options[:not_within_message] || options[:not_in_message] || options[:message]
|
|
114
104
|
message %= { min:, max: } unless message.nil?
|
|
115
105
|
|
|
116
|
-
|
|
106
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.not_within", min:, max:))
|
|
117
107
|
end
|
|
118
108
|
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# @
|
|
122
|
-
# @
|
|
123
|
-
# @
|
|
124
|
-
|
|
125
|
-
# @raise [ValidationError] Always raised with appropriate message
|
|
126
|
-
#
|
|
127
|
-
# @rbs (Integer min, Hash[Symbol, untyped] options) -> void
|
|
128
|
-
def raise_min_validation_error!(min, options)
|
|
109
|
+
# @param min [Object]
|
|
110
|
+
# @param options [Hash{Symbol => Object}]
|
|
111
|
+
# @option options [String] :min_message
|
|
112
|
+
# @option options [String] :message
|
|
113
|
+
# @return [Validators::Failure]
|
|
114
|
+
def min_failure(min, options)
|
|
129
115
|
message = options[:min_message] || options[:message]
|
|
130
116
|
message %= { min: } unless message.nil?
|
|
131
117
|
|
|
132
|
-
|
|
118
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.min", min:))
|
|
133
119
|
end
|
|
134
120
|
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
# @
|
|
138
|
-
# @
|
|
139
|
-
# @
|
|
140
|
-
|
|
141
|
-
# @raise [ValidationError] Always raised with appropriate message
|
|
142
|
-
#
|
|
143
|
-
# @rbs (Integer max, Hash[Symbol, untyped] options) -> void
|
|
144
|
-
def raise_max_validation_error!(max, options)
|
|
121
|
+
# @param max [Object]
|
|
122
|
+
# @param options [Hash{Symbol => Object}]
|
|
123
|
+
# @option options [String] :max_message
|
|
124
|
+
# @option options [String] :message
|
|
125
|
+
# @return [Validators::Failure]
|
|
126
|
+
def max_failure(max, options)
|
|
145
127
|
message = options[:max_message] || options[:message]
|
|
146
128
|
message %= { max: } unless message.nil?
|
|
147
129
|
|
|
148
|
-
|
|
130
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.max", max:))
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @param gt [Object]
|
|
134
|
+
# @param options [Hash{Symbol => Object}]
|
|
135
|
+
# @option options [String] :gt_message
|
|
136
|
+
# @option options [String] :message
|
|
137
|
+
# @return [Validators::Failure]
|
|
138
|
+
def gt_failure(gt, options)
|
|
139
|
+
message = options[:gt_message] || options[:message]
|
|
140
|
+
message %= { gt: } unless message.nil?
|
|
141
|
+
|
|
142
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.gt", gt:))
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @param lt [Object]
|
|
146
|
+
# @param options [Hash{Symbol => Object}]
|
|
147
|
+
# @option options [String] :lt_message
|
|
148
|
+
# @option options [String] :message
|
|
149
|
+
# @return [Validators::Failure]
|
|
150
|
+
def lt_failure(lt, options)
|
|
151
|
+
message = options[:lt_message] || options[:message]
|
|
152
|
+
message %= { lt: } unless message.nil?
|
|
153
|
+
|
|
154
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.lt", lt:))
|
|
149
155
|
end
|
|
150
156
|
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
# @
|
|
154
|
-
# @
|
|
155
|
-
# @
|
|
156
|
-
#
|
|
157
|
-
# @raise [ValidationError] Always raised with appropriate message
|
|
158
|
-
#
|
|
159
|
-
# @rbs (Integer is, Hash[Symbol, untyped] options) -> void
|
|
160
|
-
def raise_is_validation_error!(is, options)
|
|
157
|
+
# @param is [Object]
|
|
158
|
+
# @param options [Hash{Symbol => Object}]
|
|
159
|
+
# @option options [String] :is_message
|
|
160
|
+
# @option options [String] :message
|
|
161
|
+
# @return [Validators::Failure]
|
|
162
|
+
def is_failure(is, options) # rubocop:disable Naming/PredicatePrefix
|
|
161
163
|
message = options[:is_message] || options[:message]
|
|
162
164
|
message %= { is: } unless message.nil?
|
|
163
165
|
|
|
164
|
-
|
|
166
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.is", is:))
|
|
165
167
|
end
|
|
166
168
|
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
# @
|
|
170
|
-
# @
|
|
171
|
-
# @
|
|
172
|
-
#
|
|
173
|
-
# @raise [ValidationError] Always raised with appropriate message
|
|
174
|
-
#
|
|
175
|
-
# @rbs (Integer is_not, Hash[Symbol, untyped] options) -> void
|
|
176
|
-
def raise_is_not_validation_error!(is_not, options)
|
|
169
|
+
# @param is_not [Object]
|
|
170
|
+
# @param options [Hash{Symbol => Object}]
|
|
171
|
+
# @option options [String] :is_not_message
|
|
172
|
+
# @option options [String] :message
|
|
173
|
+
# @return [Validators::Failure]
|
|
174
|
+
def is_not_failure(is_not, options) # rubocop:disable Naming/PredicatePrefix
|
|
177
175
|
message = options[:is_not_message] || options[:message]
|
|
178
176
|
message %= { is_not: } unless message.nil?
|
|
179
177
|
|
|
180
|
-
|
|
178
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.length.is_not", is_not:))
|
|
181
179
|
end
|
|
182
180
|
|
|
183
181
|
end
|
|
@@ -1,75 +1,64 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CMDx
|
|
4
|
-
|
|
5
|
-
# Validates numeric
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
4
|
+
class Validators
|
|
5
|
+
# Validates a numeric `value` against one of: `:within` / `:not_within`
|
|
6
|
+
# / `:in` / `:not_in` (Range), `:min` + `:max`, `:gt` / `:lt` (strict
|
|
7
|
+
# comparison), or `:is` / `:is_not` (exact match). `:gte`, `:lte`,
|
|
8
|
+
# `:eq`, `:not_eq` are accepted as aliases of `:min`, `:max`, `:is`,
|
|
9
|
+
# `:is_not` respectively (with matching `_message` overrides). `nil`
|
|
10
|
+
# fails with `:nil_message` override or default.
|
|
10
11
|
module Numeric
|
|
11
12
|
|
|
12
13
|
extend self
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# @
|
|
27
|
-
# @
|
|
28
|
-
# @option options [String] :
|
|
29
|
-
# @option options [String] :
|
|
30
|
-
# @option options [String] :
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# @
|
|
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)
|
|
51
|
-
#
|
|
52
|
-
# @rbs (Numeric value, Hash[Symbol, untyped] options) -> nil
|
|
15
|
+
ALIASES = {
|
|
16
|
+
gte: :min,
|
|
17
|
+
lte: :max,
|
|
18
|
+
eq: :is,
|
|
19
|
+
not_eq: :is_not,
|
|
20
|
+
gte_message: :min_message,
|
|
21
|
+
lte_message: :max_message,
|
|
22
|
+
eq_message: :is_message,
|
|
23
|
+
not_eq_message: :is_not_message
|
|
24
|
+
}.freeze
|
|
25
|
+
private_constant :ALIASES
|
|
26
|
+
|
|
27
|
+
# @param value [Numeric, nil]
|
|
28
|
+
# @param options [Hash{Symbol => Object}] see module summary
|
|
29
|
+
# @option options [String] :message global failure-message override
|
|
30
|
+
# @option options [String] :nil_message override when `value` is nil
|
|
31
|
+
# @option options [String] :within_message, :in_message, :not_within_message,
|
|
32
|
+
# :not_in_message, :min_message, :max_message, :gt_message, :lt_message,
|
|
33
|
+
# :is_message, :is_not_message
|
|
34
|
+
# @return [Validators::Failure, nil]
|
|
35
|
+
# @raise [ArgumentError] when no recognized numeric option is given
|
|
53
36
|
def call(value, options = EMPTY_HASH)
|
|
54
|
-
|
|
37
|
+
return nil_failure(options) if value.nil?
|
|
38
|
+
|
|
39
|
+
case options = options.transform_keys(ALIASES)
|
|
55
40
|
in within:
|
|
56
|
-
|
|
41
|
+
within_failure(within.begin, within.end, options) unless within.cover?(value)
|
|
57
42
|
in not_within:
|
|
58
|
-
|
|
43
|
+
not_within_failure(not_within.begin, not_within.end, options) if not_within.cover?(value)
|
|
59
44
|
in in: xin
|
|
60
|
-
|
|
45
|
+
within_failure(xin.begin, xin.end, options) unless xin.cover?(value)
|
|
61
46
|
in not_in:
|
|
62
|
-
|
|
47
|
+
not_within_failure(not_in.begin, not_in.end, options) if not_in.cover?(value)
|
|
63
48
|
in min:, max:
|
|
64
|
-
|
|
49
|
+
within_failure(min, max, options) unless value.between?(min, max)
|
|
65
50
|
in min:
|
|
66
|
-
|
|
51
|
+
min_failure(min, options) unless min <= value
|
|
67
52
|
in max:
|
|
68
|
-
|
|
53
|
+
max_failure(max, options) unless value <= max
|
|
54
|
+
in gt:
|
|
55
|
+
gt_failure(gt, options) unless gt < value
|
|
56
|
+
in lt:
|
|
57
|
+
lt_failure(lt, options) unless value < lt
|
|
69
58
|
in is:
|
|
70
|
-
|
|
59
|
+
is_failure(is, options) unless value == is
|
|
71
60
|
in is_not:
|
|
72
|
-
|
|
61
|
+
is_not_failure(is_not, options) if value == is_not
|
|
73
62
|
else
|
|
74
63
|
raise ArgumentError, "unknown numeric validator options given"
|
|
75
64
|
end
|
|
@@ -77,102 +66,113 @@ module CMDx
|
|
|
77
66
|
|
|
78
67
|
private
|
|
79
68
|
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
# @
|
|
83
|
-
# @
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# @
|
|
90
|
-
|
|
69
|
+
# @param options [Hash{Symbol => Object}]
|
|
70
|
+
# @option options [String] :nil_message
|
|
71
|
+
# @option options [String] :message
|
|
72
|
+
# @return [Validators::Failure]
|
|
73
|
+
def nil_failure(options)
|
|
74
|
+
message = options[:nil_message] || options[:message]
|
|
75
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.nil_value"))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @param min [Object]
|
|
79
|
+
# @param max [Object]
|
|
80
|
+
# @param options [Hash{Symbol => Object}]
|
|
81
|
+
# @option options [String] :within_message
|
|
82
|
+
# @option options [String] :in_message
|
|
83
|
+
# @option options [String] :message
|
|
84
|
+
# @return [Validators::Failure]
|
|
85
|
+
def within_failure(min, max, options)
|
|
91
86
|
message = options[:within_message] || options[:in_message] || options[:message]
|
|
92
87
|
message %= { min:, max: } unless message.nil?
|
|
93
88
|
|
|
94
|
-
|
|
89
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.within", min:, max:))
|
|
95
90
|
end
|
|
96
91
|
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
# @param
|
|
100
|
-
# @
|
|
101
|
-
# @
|
|
102
|
-
# @option options [
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
#
|
|
106
|
-
# @rbs (Numeric min, Numeric max, Hash[Symbol, untyped] options) -> void
|
|
107
|
-
def raise_not_within_validation_error!(min, max, options)
|
|
92
|
+
# @param min [Object]
|
|
93
|
+
# @param max [Object]
|
|
94
|
+
# @param options [Hash{Symbol => Object}]
|
|
95
|
+
# @option options [String] :not_within_message
|
|
96
|
+
# @option options [String] :not_in_message
|
|
97
|
+
# @option options [String] :message
|
|
98
|
+
# @return [Validators::Failure]
|
|
99
|
+
def not_within_failure(min, max, options)
|
|
108
100
|
message = options[:not_within_message] || options[:not_in_message] || options[:message]
|
|
109
101
|
message %= { min:, max: } unless message.nil?
|
|
110
102
|
|
|
111
|
-
|
|
103
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.not_within", min:, max:))
|
|
112
104
|
end
|
|
113
105
|
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
# @
|
|
117
|
-
# @
|
|
118
|
-
# @
|
|
119
|
-
|
|
120
|
-
# @raise [ValidationError] With appropriate error message
|
|
121
|
-
#
|
|
122
|
-
# @rbs (Numeric min, Hash[Symbol, untyped] options) -> void
|
|
123
|
-
def raise_min_validation_error!(min, options)
|
|
106
|
+
# @param min [Object]
|
|
107
|
+
# @param options [Hash{Symbol => Object}]
|
|
108
|
+
# @option options [String] :min_message
|
|
109
|
+
# @option options [String] :message
|
|
110
|
+
# @return [Validators::Failure]
|
|
111
|
+
def min_failure(min, options)
|
|
124
112
|
message = options[:min_message] || options[:message]
|
|
125
113
|
message %= { min: } unless message.nil?
|
|
126
114
|
|
|
127
|
-
|
|
115
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.min", min:))
|
|
128
116
|
end
|
|
129
117
|
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
# @
|
|
133
|
-
# @
|
|
134
|
-
# @
|
|
135
|
-
|
|
136
|
-
# @raise [ValidationError] With appropriate error message
|
|
137
|
-
#
|
|
138
|
-
# @rbs (Numeric max, Hash[Symbol, untyped] options) -> void
|
|
139
|
-
def raise_max_validation_error!(max, options)
|
|
118
|
+
# @param max [Object]
|
|
119
|
+
# @param options [Hash{Symbol => Object}]
|
|
120
|
+
# @option options [String] :max_message
|
|
121
|
+
# @option options [String] :message
|
|
122
|
+
# @return [Validators::Failure]
|
|
123
|
+
def max_failure(max, options)
|
|
140
124
|
message = options[:max_message] || options[:message]
|
|
141
125
|
message %= { max: } unless message.nil?
|
|
142
126
|
|
|
143
|
-
|
|
127
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.max", max:))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @param gt [Object]
|
|
131
|
+
# @param options [Hash{Symbol => Object}]
|
|
132
|
+
# @option options [String] :gt_message
|
|
133
|
+
# @option options [String] :message
|
|
134
|
+
# @return [Validators::Failure]
|
|
135
|
+
def gt_failure(gt, options)
|
|
136
|
+
message = options[:gt_message] || options[:message]
|
|
137
|
+
message %= { gt: } unless message.nil?
|
|
138
|
+
|
|
139
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.gt", gt:))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @param lt [Object]
|
|
143
|
+
# @param options [Hash{Symbol => Object}]
|
|
144
|
+
# @option options [String] :lt_message
|
|
145
|
+
# @option options [String] :message
|
|
146
|
+
# @return [Validators::Failure]
|
|
147
|
+
def lt_failure(lt, options)
|
|
148
|
+
message = options[:lt_message] || options[:message]
|
|
149
|
+
message %= { lt: } unless message.nil?
|
|
150
|
+
|
|
151
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.lt", lt:))
|
|
144
152
|
end
|
|
145
153
|
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
# @
|
|
149
|
-
# @
|
|
150
|
-
# @
|
|
151
|
-
#
|
|
152
|
-
# @raise [ValidationError] With appropriate error message
|
|
153
|
-
#
|
|
154
|
-
# @rbs (Numeric is, Hash[Symbol, untyped] options) -> void
|
|
155
|
-
def raise_is_validation_error!(is, options)
|
|
154
|
+
# @param is [Object]
|
|
155
|
+
# @param options [Hash{Symbol => Object}]
|
|
156
|
+
# @option options [String] :is_message
|
|
157
|
+
# @option options [String] :message
|
|
158
|
+
# @return [Validators::Failure]
|
|
159
|
+
def is_failure(is, options) # rubocop:disable Naming/PredicatePrefix
|
|
156
160
|
message = options[:is_message] || options[:message]
|
|
157
161
|
message %= { is: } unless message.nil?
|
|
158
162
|
|
|
159
|
-
|
|
163
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.is", is:))
|
|
160
164
|
end
|
|
161
165
|
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
# @
|
|
165
|
-
# @
|
|
166
|
-
# @
|
|
167
|
-
#
|
|
168
|
-
# @raise [ValidationError] With appropriate error message
|
|
169
|
-
#
|
|
170
|
-
# @rbs (Numeric is_not, Hash[Symbol, untyped] options) -> void
|
|
171
|
-
def raise_is_not_validation_error!(is_not, options)
|
|
166
|
+
# @param is_not [Object]
|
|
167
|
+
# @param options [Hash{Symbol => Object}]
|
|
168
|
+
# @option options [String] :is_not_message
|
|
169
|
+
# @option options [String] :message
|
|
170
|
+
# @return [Validators::Failure]
|
|
171
|
+
def is_not_failure(is_not, options) # rubocop:disable Naming/PredicatePrefix
|
|
172
172
|
message = options[:is_not_message] || options[:message]
|
|
173
173
|
message %= { is_not: } unless message.nil?
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Failure.new(message || I18nProxy.t("cmdx.validators.numeric.is_not", is_not:))
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
end
|