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
data/lib/cmdx/chain.rb
CHANGED
@@ -1,100 +1,80 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Manages
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# within a single logical operation. It maintains a collection of results
|
8
|
-
# and provides thread-local storage for tracking the current execution chain.
|
9
|
-
# The chain automatically delegates common methods to its results collection
|
10
|
-
# and the first result for convenient access to execution state.
|
4
|
+
# Manages a collection of task execution results in a thread-safe manner.
|
5
|
+
# Chains provide a way to track related task executions and their outcomes
|
6
|
+
# within the same execution context.
|
11
7
|
class Chain
|
12
8
|
|
13
|
-
|
9
|
+
extend Forwardable
|
14
10
|
|
15
|
-
|
16
|
-
to: :results
|
17
|
-
cmdx_attr_delegator :state, :status, :outcome, :runtime,
|
18
|
-
to: :first
|
11
|
+
THREAD_KEY = :cmdx_chain
|
19
12
|
|
20
|
-
|
21
|
-
attr_reader :id
|
13
|
+
attr_reader :id, :results
|
22
14
|
|
23
|
-
|
24
|
-
|
15
|
+
def_delegators :results, :index, :first, :last, :size
|
16
|
+
def_delegators :first, :state, :status, :outcome, :runtime
|
25
17
|
|
26
|
-
# Creates a new
|
18
|
+
# Creates a new chain with a unique identifier and empty results collection.
|
27
19
|
#
|
28
|
-
# @
|
29
|
-
|
30
|
-
|
31
|
-
# @return [Chain] the newly created chain instance
|
32
|
-
#
|
33
|
-
# @example Create a chain with default ID
|
34
|
-
# chain = CMDx::Chain.new
|
35
|
-
# chain.id #=> "generated-uuid"
|
36
|
-
#
|
37
|
-
# @example Create a chain with custom ID
|
38
|
-
# chain = CMDx::Chain.new(id: "custom-123")
|
39
|
-
# chain.id #=> "custom-123"
|
40
|
-
def initialize(attributes = {})
|
41
|
-
@id = attributes[:id] || CMDx::Correlator.id || CMDx::Correlator.generate
|
20
|
+
# @return [Chain] A new chain instance
|
21
|
+
def initialize
|
22
|
+
@id = Identifier.generate
|
42
23
|
@results = []
|
43
24
|
end
|
44
25
|
|
45
26
|
class << self
|
46
27
|
|
47
|
-
#
|
28
|
+
# Retrieves the current chain for the current thread.
|
48
29
|
#
|
49
|
-
# @return [Chain, nil]
|
30
|
+
# @return [Chain, nil] The current chain or nil if none exists
|
50
31
|
#
|
51
|
-
# @example
|
52
|
-
# chain =
|
53
|
-
#
|
32
|
+
# @example
|
33
|
+
# chain = Chain.current
|
34
|
+
# if chain
|
35
|
+
# puts "Current chain: #{chain.id}"
|
36
|
+
# end
|
54
37
|
def current
|
55
38
|
Thread.current[THREAD_KEY]
|
56
39
|
end
|
57
40
|
|
58
|
-
# Sets the current
|
41
|
+
# Sets the current chain for the current thread.
|
59
42
|
#
|
60
|
-
# @param chain [Chain
|
43
|
+
# @param chain [Chain] The chain to set as current
|
61
44
|
#
|
62
|
-
# @return [Chain
|
45
|
+
# @return [Chain] The set chain
|
63
46
|
#
|
64
|
-
# @example
|
65
|
-
#
|
66
|
-
# CMDx::Chain.current = new_chain
|
67
|
-
# CMDx::Chain.current.id #=> new_chain.id
|
47
|
+
# @example
|
48
|
+
# Chain.current = my_chain
|
68
49
|
def current=(chain)
|
69
50
|
Thread.current[THREAD_KEY] = chain
|
70
51
|
end
|
71
52
|
|
72
|
-
# Clears the current
|
53
|
+
# Clears the current chain for the current thread.
|
73
54
|
#
|
74
|
-
# @return [nil]
|
55
|
+
# @return [nil] Always returns nil
|
75
56
|
#
|
76
|
-
# @example
|
77
|
-
#
|
78
|
-
# CMDx::Chain.current #=> nil
|
57
|
+
# @example
|
58
|
+
# Chain.clear
|
79
59
|
def clear
|
80
60
|
Thread.current[THREAD_KEY] = nil
|
81
61
|
end
|
82
62
|
|
83
|
-
# Builds or extends the current
|
63
|
+
# Builds or extends the current chain by adding a result.
|
64
|
+
# Creates a new chain if none exists, otherwise appends to the current one.
|
84
65
|
#
|
85
|
-
# @param result [
|
66
|
+
# @param result [Result] The task execution result to add
|
86
67
|
#
|
87
|
-
# @return [Chain]
|
68
|
+
# @return [Chain] The current chain (newly created or existing)
|
88
69
|
#
|
89
|
-
# @raise [TypeError]
|
70
|
+
# @raise [TypeError] If result is not a CMDx::Result instance
|
90
71
|
#
|
91
|
-
# @example
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
# chain.results.size #=> 1
|
72
|
+
# @example
|
73
|
+
# result = task.execute
|
74
|
+
# chain = Chain.build(result)
|
75
|
+
# puts "Chain size: #{chain.size}"
|
96
76
|
def build(result)
|
97
|
-
raise TypeError, "must be a Result" unless result.is_a?(Result)
|
77
|
+
raise TypeError, "must be a CMDx::Result" unless result.is_a?(Result)
|
98
78
|
|
99
79
|
self.current ||= new
|
100
80
|
current.results << result
|
@@ -103,30 +83,33 @@ module CMDx
|
|
103
83
|
|
104
84
|
end
|
105
85
|
|
106
|
-
# Converts the chain to a hash representation
|
86
|
+
# Converts the chain to a hash representation.
|
87
|
+
#
|
88
|
+
# @return [Hash] Hash containing chain id and serialized results
|
89
|
+
#
|
90
|
+
# @option return [String] :id The chain identifier
|
107
91
|
#
|
108
|
-
# @return [Hash]
|
92
|
+
# @option return [Array<Hash>] :results Array of result hashes
|
109
93
|
#
|
110
|
-
# @example
|
111
|
-
# chain.to_h
|
94
|
+
# @example
|
95
|
+
# chain_hash = chain.to_h
|
96
|
+
# puts chain_hash[:id]
|
97
|
+
# puts chain_hash[:results].size
|
112
98
|
def to_h
|
113
|
-
|
99
|
+
{
|
100
|
+
id: id,
|
101
|
+
results: results.map(&:to_h)
|
102
|
+
}
|
114
103
|
end
|
115
|
-
alias to_a to_h
|
116
104
|
|
117
|
-
# Converts the chain to a
|
105
|
+
# Converts the chain to a string representation.
|
118
106
|
#
|
119
|
-
# @return [String]
|
107
|
+
# @return [String] Formatted string representation of the chain
|
120
108
|
#
|
121
|
-
# @example
|
109
|
+
# @example
|
122
110
|
# puts chain.to_s
|
123
|
-
# # chain: abc123
|
124
|
-
# # ===================
|
125
|
-
# # {...}
|
126
|
-
# # ===================
|
127
|
-
# # state: complete | status: success | outcome: success | runtime: 0.001
|
128
111
|
def to_s
|
129
|
-
|
112
|
+
Utils::Format.to_str(to_h)
|
130
113
|
end
|
131
114
|
|
132
115
|
end
|
@@ -1,33 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
# Registry for managing
|
4
|
+
# Registry for managing type coercion handlers.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# internal registry of coercion type keys mapped to their corresponding coercion
|
9
|
-
# classes or callables, supporting both built-in framework coercions and custom
|
10
|
-
# user-defined coercions for flexible type conversion during task execution.
|
6
|
+
# Provides a centralized way to register, deregister, and execute type coercions
|
7
|
+
# for various data types including arrays, numbers, dates, and other primitives.
|
11
8
|
class CoercionRegistry
|
12
9
|
|
13
|
-
# @return [Hash] hash containing coercion type keys and coercion class/callable values
|
14
10
|
attr_reader :registry
|
11
|
+
alias to_h registry
|
15
12
|
|
16
|
-
#
|
13
|
+
# Initialize a new coercion registry.
|
17
14
|
#
|
18
|
-
#
|
19
|
-
# primitive types (string, integer, float, boolean), date/time types,
|
20
|
-
# collection types (array, hash), numeric types (big_decimal, rational, complex),
|
21
|
-
# and the virtual coercion type for parameter definitions without type conversion.
|
15
|
+
# @param registry [Hash<Symbol, Class>, nil] optional initial registry hash
|
22
16
|
#
|
23
|
-
# @
|
24
|
-
#
|
25
|
-
# @example Create a new coercion registry
|
17
|
+
# @example
|
26
18
|
# registry = CoercionRegistry.new
|
27
|
-
# registry.
|
28
|
-
|
29
|
-
|
30
|
-
@registry = {
|
19
|
+
# registry = CoercionRegistry.new(custom: CustomCoercion)
|
20
|
+
def initialize(registry = nil)
|
21
|
+
@registry = registry || {
|
31
22
|
array: Coercions::Array,
|
32
23
|
big_decimal: Coercions::BigDecimal,
|
33
24
|
boolean: Coercions::Boolean,
|
@@ -39,74 +30,67 @@ module CMDx
|
|
39
30
|
integer: Coercions::Integer,
|
40
31
|
rational: Coercions::Rational,
|
41
32
|
string: Coercions::String,
|
42
|
-
time: Coercions::Time
|
43
|
-
virtual: Coercions::Virtual
|
33
|
+
time: Coercions::Time
|
44
34
|
}
|
45
35
|
end
|
46
36
|
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# Adds or overwrites a coercion type mapping in the registry, allowing custom
|
50
|
-
# coercions to be used during task parameter processing. The coercion can be
|
51
|
-
# a class that responds to `call`, a callable object, or a symbol/string
|
52
|
-
# representing a method to invoke on the task instance.
|
37
|
+
# Create a duplicate of this registry.
|
53
38
|
#
|
54
|
-
# @
|
55
|
-
# @param coercion [Class, Proc, Symbol, String] the coercion implementation
|
39
|
+
# @return [CoercionRegistry] a new instance with duplicated registry hash
|
56
40
|
#
|
57
|
-
# @
|
41
|
+
# @example
|
42
|
+
# new_registry = registry.dup
|
43
|
+
def dup
|
44
|
+
self.class.new(registry.dup)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Register a new coercion handler for a type.
|
58
48
|
#
|
59
|
-
# @
|
60
|
-
#
|
49
|
+
# @param name [Symbol, String] the type name to register
|
50
|
+
# @param coercion [Class] the coercion class to handle this type
|
61
51
|
#
|
62
|
-
# @
|
63
|
-
# registry.register(:upcase, proc { |value, options| value.to_s.upcase })
|
52
|
+
# @return [CoercionRegistry] self for method chaining
|
64
53
|
#
|
65
|
-
# @example
|
66
|
-
# registry.register(:
|
67
|
-
|
68
|
-
|
54
|
+
# @example
|
55
|
+
# registry.register(:custom_type, CustomCoercion)
|
56
|
+
# registry.register("another_type", AnotherCoercion)
|
57
|
+
def register(name, coercion)
|
58
|
+
registry[name.to_sym] = coercion
|
69
59
|
self
|
70
60
|
end
|
71
61
|
|
72
|
-
#
|
62
|
+
# Remove a coercion handler for a type.
|
73
63
|
#
|
74
|
-
#
|
75
|
-
# applying it to the provided value with optional configuration. Handles
|
76
|
-
# different coercion implementation types including callable objects,
|
77
|
-
# method symbols/strings, and coercion classes.
|
64
|
+
# @param name [Symbol, String] the type name to deregister
|
78
65
|
#
|
79
|
-
# @
|
80
|
-
# @param type [Symbol] the coercion type to execute
|
81
|
-
# @param value [Object] the value to be coerced
|
82
|
-
# @param options [Hash] additional options passed to the coercion
|
83
|
-
# @option options [Object] any any additional configuration for the coercion
|
66
|
+
# @return [CoercionRegistry] self for method chaining
|
84
67
|
#
|
85
|
-
# @
|
68
|
+
# @example
|
69
|
+
# registry.deregister(:custom_type)
|
70
|
+
# registry.deregister("another_type")
|
71
|
+
def deregister(name)
|
72
|
+
registry.delete(name.to_sym)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
# Coerce a value to the specified type using the registered handler.
|
86
77
|
#
|
87
|
-
# @
|
88
|
-
# @
|
78
|
+
# @param type [Symbol] the type to coerce to
|
79
|
+
# @param task [Object] the task context for the coercion
|
80
|
+
# @param value [Object] the value to coerce
|
81
|
+
# @param options [Hash] additional options for the coercion
|
89
82
|
#
|
90
|
-
# @
|
91
|
-
# registry.call(task, :integer, "123")
|
92
|
-
# #=> 123
|
83
|
+
# @return [Object] the coerced value
|
93
84
|
#
|
94
|
-
# @
|
95
|
-
# registry.call(task, :date, "2024-01-15", format: "%Y-%m-%d")
|
96
|
-
# #=> #<Date: 2024-01-15>
|
85
|
+
# @raise [TypeError] when the type is not registered
|
97
86
|
#
|
98
|
-
# @example
|
99
|
-
# registry.
|
100
|
-
#
|
101
|
-
def
|
102
|
-
raise
|
87
|
+
# @example
|
88
|
+
# result = registry.coerce(:integer, task, "42")
|
89
|
+
# result = registry.coerce(:boolean, task, "true", strict: true)
|
90
|
+
def coerce(type, task, value, options = {})
|
91
|
+
raise TypeError, "unknown coercion type #{type.inspect}" unless registry.key?(type)
|
103
92
|
|
104
|
-
|
105
|
-
when Symbol, String, Proc
|
106
|
-
task.cmdx_try(coercion, value, options)
|
107
|
-
else
|
108
|
-
coercion.call(value, options)
|
109
|
-
end
|
93
|
+
Utils::Call.invoke(task, registry[type], value, options)
|
110
94
|
end
|
111
95
|
|
112
96
|
end
|
data/lib/cmdx/coercions/array.rb
CHANGED
@@ -2,30 +2,31 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Coercions
|
5
|
-
#
|
5
|
+
# Converts various input types to Array format
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
7
|
+
# Handles conversion from strings that look like JSON arrays and other
|
8
|
+
# values that can be converted to arrays using Ruby's Array() method.
|
9
|
+
module Array
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
# @param _options [Hash] optional configuration (currently unused)
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# Converts a value to an Array
|
15
14
|
#
|
16
|
-
# @
|
15
|
+
# @param value [Object] The value to convert to an array
|
16
|
+
# @param options [Hash] Optional configuration parameters (currently unused)
|
17
|
+
# @option options [Object] :unused Currently no options are used
|
17
18
|
#
|
18
|
-
# @
|
19
|
-
# @raise [TypeError] if the value cannot be converted to an array
|
19
|
+
# @return [Array] The converted array value
|
20
20
|
#
|
21
|
-
# @
|
22
|
-
# Coercions::Array.call('["a", "b", "c"]') #=> ["a", "b", "c"]
|
21
|
+
# @raise [JSON::ParserError] If the string value contains invalid JSON
|
23
22
|
#
|
24
|
-
# @example
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
|
23
|
+
# @example Convert a JSON-like string to an array
|
24
|
+
# Array.call("[1, 2, 3]") # => [1, 2, 3]
|
25
|
+
# @example Convert other values using Array()
|
26
|
+
# Array.call("hello") # => ["hello"]
|
27
|
+
# Array.call(42) # => [42]
|
28
|
+
# Array.call(nil) # => []
|
29
|
+
def call(value, options = {})
|
29
30
|
if value.is_a?(::String) && value.start_with?("[")
|
30
31
|
JSON.parse(value)
|
31
32
|
else
|
@@ -2,41 +2,37 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Coercions
|
5
|
-
#
|
5
|
+
# Converts various input types to BigDecimal format
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
7
|
+
# Handles conversion from numeric strings, integers, floats, and other
|
8
|
+
# values that can be converted to BigDecimal using Ruby's BigDecimal() method.
|
9
|
+
module BigDecimal
|
10
|
+
|
11
|
+
extend self
|
11
12
|
|
12
13
|
DEFAULT_PRECISION = 14
|
13
14
|
|
14
|
-
# Converts
|
15
|
-
#
|
16
|
-
# @param value [Object] the value to convert to a BigDecimal
|
17
|
-
# @param options [Hash] optional configuration
|
18
|
-
# @option options [Integer] :precision the precision for the BigDecimal (defaults to 14)
|
19
|
-
#
|
20
|
-
# @return [BigDecimal] the converted BigDecimal value
|
15
|
+
# Converts a value to a BigDecimal
|
21
16
|
#
|
22
|
-
# @
|
17
|
+
# @param value [Object] The value to convert to BigDecimal
|
18
|
+
# @param options [Hash] Optional configuration parameters
|
19
|
+
# @option options [Integer] :precision The precision to use (defaults to DEFAULT_PRECISION)
|
23
20
|
#
|
24
|
-
# @
|
25
|
-
# Coercions::BigDecimal.call('123.45') #=> #<BigDecimal:...,'0.12345E3',18(27)>
|
21
|
+
# @return [BigDecimal] The converted BigDecimal value
|
26
22
|
#
|
27
|
-
# @
|
28
|
-
# Coercions::BigDecimal.call('123.456789', precision: 10) #=> #<BigDecimal:...,'0.123456789E3',18(27)>
|
23
|
+
# @raise [CoercionError] If the value cannot be converted to BigDecimal
|
29
24
|
#
|
30
|
-
# @example
|
31
|
-
#
|
25
|
+
# @example Convert numeric strings to BigDecimal
|
26
|
+
# BigDecimal.call("123.45") # => #<BigDecimal:7f8b8c0d8e0f '0.12345E3',9(18)>
|
27
|
+
# BigDecimal.call("0.001", precision: 6) # => #<BigDecimal:7f8b8c0d8e0f '0.1E-2',9(18)>
|
28
|
+
# @example Convert other numeric types
|
29
|
+
# BigDecimal.call(42) # => #<BigDecimal:7f8b8c0d8e0f '0.42E2',9(18)>
|
30
|
+
# BigDecimal.call(3.14159) # => #<BigDecimal:7f8b8c0d8e0f '0.314159E1',9(18)>
|
32
31
|
def call(value, options = {})
|
33
32
|
BigDecimal(value, options[:precision] || DEFAULT_PRECISION)
|
34
33
|
rescue ArgumentError, TypeError
|
35
|
-
|
36
|
-
|
37
|
-
type: "big decimal",
|
38
|
-
default: "could not coerce into a big decimal"
|
39
|
-
)
|
34
|
+
type = Locale.t("cmdx.types.big_decimal")
|
35
|
+
raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
|
40
36
|
end
|
41
37
|
|
42
38
|
end
|
@@ -2,44 +2,45 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Coercions
|
5
|
-
#
|
5
|
+
# Converts various input types to Boolean format
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
7
|
+
# Handles conversion from strings, numbers, and other values to boolean
|
8
|
+
# using predefined truthy and falsey patterns.
|
9
|
+
module Boolean
|
10
|
+
|
11
|
+
extend self
|
11
12
|
|
12
13
|
FALSEY = /^(false|f|no|n|0)$/i
|
13
14
|
TRUTHY = /^(true|t|yes|y|1)$/i
|
14
15
|
|
15
|
-
# Converts
|
16
|
-
#
|
17
|
-
# @param value [Object] the value to convert to a boolean
|
18
|
-
# @param _options [Hash] optional configuration (currently unused)
|
16
|
+
# Converts a value to a Boolean
|
19
17
|
#
|
20
|
-
# @
|
18
|
+
# @param value [Object] The value to convert to boolean
|
19
|
+
# @param options [Hash] Optional configuration parameters (currently unused)
|
20
|
+
# @option options [Object] :unused Currently no options are used
|
21
21
|
#
|
22
|
-
# @
|
22
|
+
# @return [Boolean] The converted boolean value
|
23
23
|
#
|
24
|
-
# @
|
25
|
-
# Coercions::Boolean.call('true') #=> true
|
26
|
-
# Coercions::Boolean.call('yes') #=> true
|
27
|
-
# Coercions::Boolean.call('1') #=> true
|
24
|
+
# @raise [CoercionError] If the value cannot be converted to boolean
|
28
25
|
#
|
29
|
-
# @example
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
|
26
|
+
# @example Convert truthy strings to true
|
27
|
+
# Boolean.call("true") # => true
|
28
|
+
# Boolean.call("yes") # => true
|
29
|
+
# Boolean.call("1") # => true
|
30
|
+
# @example Convert falsey strings to false
|
31
|
+
# Boolean.call("false") # => false
|
32
|
+
# Boolean.call("no") # => false
|
33
|
+
# Boolean.call("0") # => false
|
34
|
+
# @example Handle case-insensitive input
|
35
|
+
# Boolean.call("TRUE") # => true
|
36
|
+
# Boolean.call("False") # => false
|
37
|
+
def call(value, options = {})
|
34
38
|
case value.to_s.downcase
|
35
39
|
when FALSEY then false
|
36
40
|
when TRUTHY then true
|
37
41
|
else
|
38
|
-
|
39
|
-
|
40
|
-
type: "boolean",
|
41
|
-
default: "could not coerce into a boolean"
|
42
|
-
)
|
42
|
+
type = Locale.t("cmdx.types.boolean")
|
43
|
+
raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -2,36 +2,35 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
module Coercions
|
5
|
-
#
|
5
|
+
# Converts various input types to Complex number format
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
7
|
+
# Handles conversion from numeric strings, integers, floats, and other
|
8
|
+
# values that can be converted to Complex using Ruby's Complex() method.
|
9
|
+
module Complex
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
# @param _options [Hash] optional configuration (currently unused)
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# Converts a value to a Complex number
|
15
14
|
#
|
16
|
-
# @
|
15
|
+
# @param value [Object] The value to convert to Complex
|
16
|
+
# @param options [Hash] Optional configuration parameters (currently unused)
|
17
17
|
#
|
18
|
-
# @
|
18
|
+
# @return [Complex] The converted Complex number value
|
19
19
|
#
|
20
|
-
# @
|
21
|
-
# Coercions::Complex.call(5) #=> (5+0i)
|
22
|
-
# Coercions::Complex.call(3.14) #=> (3.14+0i)
|
20
|
+
# @raise [CoercionError] If the value cannot be converted to Complex
|
23
21
|
#
|
24
|
-
# @example
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
22
|
+
# @example Convert numeric strings to Complex
|
23
|
+
# Complex.call("3+4i") # => (3+4i)
|
24
|
+
# Complex.call("2.5") # => (2.5+0i)
|
25
|
+
# @example Convert other numeric types
|
26
|
+
# Complex.call(5) # => (5+0i)
|
27
|
+
# Complex.call(3.14) # => (3.14+0i)
|
28
|
+
# Complex.call(Complex(1, 2)) # => (1+2i)
|
29
|
+
def call(value, options = {})
|
28
30
|
Complex(value)
|
29
31
|
rescue ArgumentError, TypeError
|
30
|
-
|
31
|
-
|
32
|
-
type: "complex",
|
33
|
-
default: "could not coerce into a complex"
|
34
|
-
)
|
32
|
+
type = Locale.t("cmdx.types.complex")
|
33
|
+
raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
|
35
34
|
end
|
36
35
|
|
37
36
|
end
|