cmdx 1.18.0 → 1.19.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 +11 -0
- data/lib/cmdx/attribute.rb +10 -5
- data/lib/cmdx/attribute_value.rb +6 -1
- data/lib/cmdx/chain.rb +14 -0
- data/lib/cmdx/coercions/array.rb +6 -1
- data/lib/cmdx/coercions/boolean.rb +5 -1
- data/lib/cmdx/coercions/date.rb +1 -6
- data/lib/cmdx/coercions/date_time.rb +1 -6
- data/lib/cmdx/coercions/integer.rb +3 -4
- data/lib/cmdx/coercions/time.rb +0 -6
- data/lib/cmdx/executor.rb +3 -3
- data/lib/cmdx/task.rb +3 -1
- data/lib/cmdx/validator_registry.rb +1 -1
- data/lib/cmdx/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ead1d181ed1eac565ea3287eeaaca3216e5d24a40f4071000539584435fc1327
|
|
4
|
+
data.tar.gz: ba0273c00286e10621f06fc5b0ba7be760afa99dd8d3fbfc6fc7da1c3c11891f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30e8c09228e765f2ac8e9b4f8db854da21a13e3a2d7e67b9ad61ecad66d09dd7f8ca9327ac9a8ef8777e78d56d5844a06f52e55d282cc1d78d7ddb9141b9acc2
|
|
7
|
+
data.tar.gz: 922de5ad8342195dc94bf8137e7023612db4df09b3979581c0e77aecf599cae971004e64b9ab71261ea6795feb8ca8b7fe3fe4fc3f37a570ed50157c404aff33
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [UNRELEASED]
|
|
8
8
|
|
|
9
|
+
### Changed
|
|
10
|
+
- Add attribute `source` fallback to `:context` when no task is given
|
|
11
|
+
- Improve falsy attribute derived Hash value lookup
|
|
12
|
+
- Freeze chain results
|
|
13
|
+
- Fix missing fault cause no method error issue
|
|
14
|
+
- Add context respond_to? with setter methods
|
|
15
|
+
- Fix validator `allow_nil` inverted logic
|
|
16
|
+
- Array coercion JSON parse error no returns CoercionError
|
|
17
|
+
- Boolean coercions now return `false` for `nil` and `""`
|
|
18
|
+
- Coerce anaglous date, datetime, and time class checks to rely on `to_date`, `to_time`, `to_datetime` methods
|
|
19
|
+
|
|
9
20
|
## [1.18.0] - 2025-03-09
|
|
10
21
|
|
|
11
22
|
### Changed
|
data/lib/cmdx/attribute.rb
CHANGED
|
@@ -208,7 +208,8 @@ module CMDx
|
|
|
208
208
|
!!@required
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
# Determines the source of the attribute value.
|
|
211
|
+
# Determines the source of the attribute value. Returns :context
|
|
212
|
+
# as a safe fallback when task is not yet set (e.g., schema introspection).
|
|
212
213
|
#
|
|
213
214
|
# @return [Symbol] The source identifier for the attribute value
|
|
214
215
|
#
|
|
@@ -217,13 +218,15 @@ module CMDx
|
|
|
217
218
|
#
|
|
218
219
|
# @rbs () -> untyped
|
|
219
220
|
def source
|
|
220
|
-
@source
|
|
221
|
+
return @source if defined?(@source)
|
|
222
|
+
|
|
223
|
+
@source = parent&.method_name || begin
|
|
221
224
|
value = options[:source]
|
|
222
225
|
|
|
223
226
|
if value.is_a?(Proc)
|
|
224
|
-
task.instance_eval(&value)
|
|
227
|
+
task ? task.instance_eval(&value) : :context
|
|
225
228
|
elsif value.respond_to?(:call)
|
|
226
|
-
value.call(task)
|
|
229
|
+
task ? value.call(task) : :context
|
|
227
230
|
else
|
|
228
231
|
value || :context
|
|
229
232
|
end
|
|
@@ -239,7 +242,9 @@ module CMDx
|
|
|
239
242
|
#
|
|
240
243
|
# @rbs () -> Symbol
|
|
241
244
|
def method_name
|
|
242
|
-
@method_name
|
|
245
|
+
return @method_name if defined?(@method_name)
|
|
246
|
+
|
|
247
|
+
@method_name = options[:as] || begin
|
|
243
248
|
prefix = AFFIX.call(options[:prefix]) { "#{source}_" }
|
|
244
249
|
suffix = AFFIX.call(options[:suffix]) { "_#{source}" }
|
|
245
250
|
|
data/lib/cmdx/attribute_value.rb
CHANGED
|
@@ -166,7 +166,12 @@ module CMDx
|
|
|
166
166
|
derived_value =
|
|
167
167
|
case source_value
|
|
168
168
|
when Context then source_value[name]
|
|
169
|
-
when Hash
|
|
169
|
+
when Hash
|
|
170
|
+
if source_value.key?(name.to_s)
|
|
171
|
+
source_value[name.to_s]
|
|
172
|
+
elsif source_value.key?(name.to_sym)
|
|
173
|
+
source_value[name.to_sym]
|
|
174
|
+
end
|
|
170
175
|
when Symbol then source_value.send(name)
|
|
171
176
|
when Proc then task.instance_exec(name, &source_value)
|
|
172
177
|
else
|
data/lib/cmdx/chain.rb
CHANGED
|
@@ -136,6 +136,20 @@ module CMDx
|
|
|
136
136
|
!!@dry_run
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
+
# Freezes the chain and its internal results to prevent modifications.
|
|
140
|
+
#
|
|
141
|
+
# @return [Chain] the frozen chain
|
|
142
|
+
#
|
|
143
|
+
# @example
|
|
144
|
+
# chain.freeze
|
|
145
|
+
# chain.results << result # => raises FrozenError
|
|
146
|
+
#
|
|
147
|
+
# @rbs () -> self
|
|
148
|
+
def freeze
|
|
149
|
+
results.freeze
|
|
150
|
+
super
|
|
151
|
+
end
|
|
152
|
+
|
|
139
153
|
# Converts the chain to a hash representation.
|
|
140
154
|
#
|
|
141
155
|
# @option return [String] :id The chain identifier
|
data/lib/cmdx/coercions/array.rb
CHANGED
|
@@ -18,7 +18,7 @@ module CMDx
|
|
|
18
18
|
#
|
|
19
19
|
# @return [Array] The converted array value
|
|
20
20
|
#
|
|
21
|
-
# @raise [
|
|
21
|
+
# @raise [CoercionError] If the value cannot be converted to an array
|
|
22
22
|
#
|
|
23
23
|
# @example Convert a JSON-like string to an array
|
|
24
24
|
# Array.call("[1, 2, 3]") # => [1, 2, 3]
|
|
@@ -26,6 +26,8 @@ module CMDx
|
|
|
26
26
|
# Array.call("hello") # => ["hello"]
|
|
27
27
|
# Array.call(42) # => [42]
|
|
28
28
|
# Array.call(nil) # => []
|
|
29
|
+
# @example Handle invalid JSON-like strings
|
|
30
|
+
# Array.call("[not json") # => raises CoercionError
|
|
29
31
|
#
|
|
30
32
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> Array[untyped]
|
|
31
33
|
def call(value, options = {})
|
|
@@ -37,6 +39,9 @@ module CMDx
|
|
|
37
39
|
else
|
|
38
40
|
Array(value)
|
|
39
41
|
end
|
|
42
|
+
rescue JSON::ParserError
|
|
43
|
+
type = Locale.t("cmdx.types.array")
|
|
44
|
+
raise CoercionError, Locale.t("cmdx.coercions.into_an", type:)
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
end
|
|
@@ -34,14 +34,18 @@ module CMDx
|
|
|
34
34
|
# Boolean.call("false") # => false
|
|
35
35
|
# Boolean.call("no") # => false
|
|
36
36
|
# Boolean.call("0") # => false
|
|
37
|
+
# Boolean.call(nil) # => false
|
|
38
|
+
# Boolean.call("") # => false
|
|
37
39
|
# @example Handle case-insensitive input
|
|
38
40
|
# Boolean.call("TRUE") # => true
|
|
39
41
|
# Boolean.call("False") # => false
|
|
42
|
+
# @example Handle edge cases
|
|
43
|
+
# Boolean.call("abc") # => raises CoercionError
|
|
40
44
|
#
|
|
41
45
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> bool
|
|
42
46
|
def call(value, options = {})
|
|
43
47
|
case value.to_s
|
|
44
|
-
when FALSEY then false
|
|
48
|
+
when FALSEY, "" then false
|
|
45
49
|
when TRUTHY then true
|
|
46
50
|
else
|
|
47
51
|
type = Locale.t("cmdx.types.boolean")
|
data/lib/cmdx/coercions/date.rb
CHANGED
|
@@ -11,11 +11,6 @@ module CMDx
|
|
|
11
11
|
|
|
12
12
|
extend self
|
|
13
13
|
|
|
14
|
-
# Types that are already date-like and don't need conversion
|
|
15
|
-
#
|
|
16
|
-
# @rbs ANALOG_TYPES: Array[String]
|
|
17
|
-
ANALOG_TYPES = %w[Date DateTime Time].freeze
|
|
18
|
-
|
|
19
14
|
# Converts a value to a Date object
|
|
20
15
|
#
|
|
21
16
|
# @param value [Object] The value to convert to a Date
|
|
@@ -38,7 +33,7 @@ module CMDx
|
|
|
38
33
|
#
|
|
39
34
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> Date
|
|
40
35
|
def call(value, options = {})
|
|
41
|
-
return value if
|
|
36
|
+
return value.to_date if value.respond_to?(:to_date)
|
|
42
37
|
return ::Date.strptime(value, options[:strptime]) if options[:strptime]
|
|
43
38
|
|
|
44
39
|
::Date.parse(value)
|
|
@@ -11,11 +11,6 @@ module CMDx
|
|
|
11
11
|
|
|
12
12
|
extend self
|
|
13
13
|
|
|
14
|
-
# Types that are already date-time-like and don't need conversion
|
|
15
|
-
#
|
|
16
|
-
# @rbs ANALOG_TYPES: Array[String]
|
|
17
|
-
ANALOG_TYPES = %w[Date DateTime Time].freeze
|
|
18
|
-
|
|
19
14
|
# Converts a value to a DateTime
|
|
20
15
|
#
|
|
21
16
|
# @param value [Object] The value to convert to DateTime
|
|
@@ -38,7 +33,7 @@ module CMDx
|
|
|
38
33
|
#
|
|
39
34
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> DateTime
|
|
40
35
|
def call(value, options = {})
|
|
41
|
-
return value if
|
|
36
|
+
return value.to_datetime if value.respond_to?(:to_datetime)
|
|
42
37
|
return ::DateTime.strptime(value, options[:strptime]) if options[:strptime]
|
|
43
38
|
|
|
44
39
|
::DateTime.parse(value)
|
|
@@ -30,10 +30,9 @@ module CMDx
|
|
|
30
30
|
# Integer.call(3.14) # => 3
|
|
31
31
|
# Integer.call(0.0) # => 0
|
|
32
32
|
# @example Handle edge cases
|
|
33
|
-
# Integer.call("") # =>
|
|
34
|
-
# Integer.call(nil) # =>
|
|
35
|
-
# Integer.call(
|
|
36
|
-
# Integer.call(true) # => 1
|
|
33
|
+
# Integer.call("") # => raises CoercionError
|
|
34
|
+
# Integer.call(nil) # => raises CoercionError
|
|
35
|
+
# Integer.call("abc") # => raises CoercionError
|
|
37
36
|
#
|
|
38
37
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> Integer
|
|
39
38
|
def call(value, options = {})
|
data/lib/cmdx/coercions/time.rb
CHANGED
|
@@ -11,11 +11,6 @@ module CMDx
|
|
|
11
11
|
|
|
12
12
|
extend self
|
|
13
13
|
|
|
14
|
-
# Types that are already time-like and don't need conversion
|
|
15
|
-
#
|
|
16
|
-
# @rbs ANALOG_TYPES: Array[String]
|
|
17
|
-
ANALOG_TYPES = %w[DateTime Time].freeze
|
|
18
|
-
|
|
19
14
|
# Converts a value to a Time object
|
|
20
15
|
#
|
|
21
16
|
# @param value [Object] The value to convert to a Time object
|
|
@@ -40,7 +35,6 @@ module CMDx
|
|
|
40
35
|
#
|
|
41
36
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> Time
|
|
42
37
|
def call(value, options = {})
|
|
43
|
-
return value if ANALOG_TYPES.include?(value.class.name)
|
|
44
38
|
return value.to_time if value.respond_to?(:to_time)
|
|
45
39
|
return ::Time.strptime(value, options[:strptime]) if options[:strptime]
|
|
46
40
|
|
data/lib/cmdx/executor.rb
CHANGED
|
@@ -169,7 +169,7 @@ module CMDx
|
|
|
169
169
|
jitter.to_f * current_retry
|
|
170
170
|
end
|
|
171
171
|
|
|
172
|
-
sleep(jitter) if jitter.positive?
|
|
172
|
+
sleep(jitter) if Float(jitter).positive?
|
|
173
173
|
|
|
174
174
|
true
|
|
175
175
|
end
|
|
@@ -291,8 +291,8 @@ module CMDx
|
|
|
291
291
|
def log_backtrace!
|
|
292
292
|
return unless result.failed?
|
|
293
293
|
|
|
294
|
-
exception = result.caused_failure
|
|
295
|
-
return if exception.is_a?(Fault)
|
|
294
|
+
exception = result.caused_failure&.cause
|
|
295
|
+
return if exception.nil? || exception.is_a?(Fault)
|
|
296
296
|
|
|
297
297
|
task.logger.error do
|
|
298
298
|
"[#{exception.class}] #{exception.message}\n" <<
|
data/lib/cmdx/task.rb
CHANGED
|
@@ -95,7 +95,9 @@ module CMDx
|
|
|
95
95
|
@id = Identifier.generate
|
|
96
96
|
@context = Context.build(context)
|
|
97
97
|
@result = Result.new(self)
|
|
98
|
-
|
|
98
|
+
|
|
99
|
+
dry_run = @context.delete(:dry_run)
|
|
100
|
+
@chain = Chain.build(@result, dry_run:)
|
|
99
101
|
end
|
|
100
102
|
|
|
101
103
|
class << self
|
data/lib/cmdx/version.rb
CHANGED