cmdx 1.1.1 → 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.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +4 -1
  4. data/.cursor/prompts/llms.md +20 -0
  5. data/.cursor/prompts/rspec.md +4 -1
  6. data/.cursor/prompts/yardoc.md +3 -2
  7. data/.cursor/rules/cursor-instructions.mdc +56 -1
  8. data/.irbrc +6 -0
  9. data/.rubocop.yml +29 -18
  10. data/.ruby-version +1 -1
  11. data/CHANGELOG.md +6 -128
  12. data/LLM.md +3317 -0
  13. data/README.md +68 -44
  14. data/docs/attributes/coercions.md +162 -0
  15. data/docs/attributes/defaults.md +90 -0
  16. data/docs/attributes/definitions.md +281 -0
  17. data/docs/attributes/naming.md +78 -0
  18. data/docs/attributes/validations.md +309 -0
  19. data/docs/basics/chain.md +56 -249
  20. data/docs/basics/context.md +56 -289
  21. data/docs/basics/execution.md +114 -0
  22. data/docs/basics/setup.md +37 -334
  23. data/docs/callbacks.md +89 -467
  24. data/docs/deprecation.md +91 -174
  25. data/docs/getting_started.md +212 -202
  26. data/docs/internationalization.md +11 -647
  27. data/docs/interruptions/exceptions.md +23 -198
  28. data/docs/interruptions/faults.md +71 -151
  29. data/docs/interruptions/halt.md +109 -186
  30. data/docs/logging.md +44 -256
  31. data/docs/middlewares.md +113 -426
  32. data/docs/outcomes/result.md +81 -228
  33. data/docs/outcomes/states.md +33 -221
  34. data/docs/outcomes/statuses.md +21 -311
  35. data/docs/tips_and_tricks.md +120 -70
  36. data/docs/workflows.md +99 -283
  37. data/lib/cmdx/.DS_Store +0 -0
  38. data/lib/cmdx/attribute.rb +229 -0
  39. data/lib/cmdx/attribute_registry.rb +94 -0
  40. data/lib/cmdx/attribute_value.rb +193 -0
  41. data/lib/cmdx/callback_registry.rb +69 -77
  42. data/lib/cmdx/chain.rb +56 -73
  43. data/lib/cmdx/coercion_registry.rb +52 -68
  44. data/lib/cmdx/coercions/array.rb +19 -18
  45. data/lib/cmdx/coercions/big_decimal.rb +20 -24
  46. data/lib/cmdx/coercions/boolean.rb +26 -25
  47. data/lib/cmdx/coercions/complex.rb +21 -22
  48. data/lib/cmdx/coercions/date.rb +25 -23
  49. data/lib/cmdx/coercions/date_time.rb +24 -25
  50. data/lib/cmdx/coercions/float.rb +25 -22
  51. data/lib/cmdx/coercions/hash.rb +31 -32
  52. data/lib/cmdx/coercions/integer.rb +30 -24
  53. data/lib/cmdx/coercions/rational.rb +29 -24
  54. data/lib/cmdx/coercions/string.rb +19 -22
  55. data/lib/cmdx/coercions/symbol.rb +37 -0
  56. data/lib/cmdx/coercions/time.rb +26 -25
  57. data/lib/cmdx/configuration.rb +49 -108
  58. data/lib/cmdx/context.rb +222 -44
  59. data/lib/cmdx/deprecator.rb +61 -0
  60. data/lib/cmdx/errors.rb +42 -252
  61. data/lib/cmdx/exceptions.rb +39 -0
  62. data/lib/cmdx/faults.rb +78 -39
  63. data/lib/cmdx/freezer.rb +51 -0
  64. data/lib/cmdx/identifier.rb +30 -0
  65. data/lib/cmdx/locale.rb +52 -0
  66. data/lib/cmdx/log_formatters/json.rb +21 -22
  67. data/lib/cmdx/log_formatters/key_value.rb +20 -22
  68. data/lib/cmdx/log_formatters/line.rb +15 -22
  69. data/lib/cmdx/log_formatters/logstash.rb +22 -23
  70. data/lib/cmdx/log_formatters/raw.rb +16 -22
  71. data/lib/cmdx/middleware_registry.rb +70 -74
  72. data/lib/cmdx/middlewares/correlate.rb +90 -54
  73. data/lib/cmdx/middlewares/runtime.rb +58 -0
  74. data/lib/cmdx/middlewares/timeout.rb +48 -68
  75. data/lib/cmdx/railtie.rb +12 -45
  76. data/lib/cmdx/result.rb +229 -314
  77. data/lib/cmdx/task.rb +194 -366
  78. data/lib/cmdx/utils/call.rb +49 -0
  79. data/lib/cmdx/utils/condition.rb +71 -0
  80. data/lib/cmdx/utils/format.rb +61 -0
  81. data/lib/cmdx/validator_registry.rb +63 -72
  82. data/lib/cmdx/validators/exclusion.rb +38 -67
  83. data/lib/cmdx/validators/format.rb +48 -49
  84. data/lib/cmdx/validators/inclusion.rb +43 -74
  85. data/lib/cmdx/validators/length.rb +91 -154
  86. data/lib/cmdx/validators/numeric.rb +87 -162
  87. data/lib/cmdx/validators/presence.rb +37 -50
  88. data/lib/cmdx/version.rb +1 -1
  89. data/lib/cmdx/worker.rb +178 -0
  90. data/lib/cmdx/workflow.rb +85 -81
  91. data/lib/cmdx.rb +19 -13
  92. data/lib/generators/cmdx/install_generator.rb +14 -13
  93. data/lib/generators/cmdx/task_generator.rb +25 -50
  94. data/lib/generators/cmdx/templates/install.rb +11 -46
  95. data/lib/generators/cmdx/templates/task.rb.tt +3 -2
  96. data/lib/locales/en.yml +18 -4
  97. data/src/cmdx-logo.png +0 -0
  98. metadata +32 -116
  99. data/docs/ai_prompts.md +0 -393
  100. data/docs/basics/call.md +0 -317
  101. data/docs/configuration.md +0 -344
  102. data/docs/parameters/coercions.md +0 -396
  103. data/docs/parameters/defaults.md +0 -335
  104. data/docs/parameters/definitions.md +0 -446
  105. data/docs/parameters/namespacing.md +0 -378
  106. data/docs/parameters/validations.md +0 -405
  107. data/docs/testing.md +0 -553
  108. data/lib/cmdx/callback.rb +0 -53
  109. data/lib/cmdx/chain_inspector.rb +0 -56
  110. data/lib/cmdx/chain_serializer.rb +0 -63
  111. data/lib/cmdx/coercion.rb +0 -57
  112. data/lib/cmdx/coercions/virtual.rb +0 -29
  113. data/lib/cmdx/core_ext/hash.rb +0 -83
  114. data/lib/cmdx/core_ext/module.rb +0 -98
  115. data/lib/cmdx/core_ext/object.rb +0 -125
  116. data/lib/cmdx/correlator.rb +0 -122
  117. data/lib/cmdx/error.rb +0 -60
  118. data/lib/cmdx/fault.rb +0 -140
  119. data/lib/cmdx/immutator.rb +0 -52
  120. data/lib/cmdx/lazy_struct.rb +0 -246
  121. data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
  122. data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
  123. data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
  124. data/lib/cmdx/logger.rb +0 -49
  125. data/lib/cmdx/logger_ansi.rb +0 -68
  126. data/lib/cmdx/logger_serializer.rb +0 -116
  127. data/lib/cmdx/middleware.rb +0 -70
  128. data/lib/cmdx/parameter.rb +0 -312
  129. data/lib/cmdx/parameter_evaluator.rb +0 -231
  130. data/lib/cmdx/parameter_inspector.rb +0 -66
  131. data/lib/cmdx/parameter_registry.rb +0 -106
  132. data/lib/cmdx/parameter_serializer.rb +0 -59
  133. data/lib/cmdx/result_ansi.rb +0 -71
  134. data/lib/cmdx/result_inspector.rb +0 -71
  135. data/lib/cmdx/result_logger.rb +0 -59
  136. data/lib/cmdx/result_serializer.rb +0 -104
  137. data/lib/cmdx/rspec/matchers.rb +0 -28
  138. data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
  139. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
  140. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
  141. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
  142. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
  143. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
  144. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
  145. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
  146. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
  147. data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
  148. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
  149. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
  150. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
  151. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
  152. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
  153. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
  154. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
  155. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
  156. data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
  157. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
  158. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
  159. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
  160. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
  161. data/lib/cmdx/task_deprecator.rb +0 -52
  162. data/lib/cmdx/task_processor.rb +0 -246
  163. data/lib/cmdx/task_serializer.rb +0 -57
  164. data/lib/cmdx/utils/ansi_color.rb +0 -73
  165. data/lib/cmdx/utils/log_timestamp.rb +0 -36
  166. data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
  167. data/lib/cmdx/utils/name_affix.rb +0 -52
  168. data/lib/cmdx/validator.rb +0 -57
  169. data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
  170. data/lib/generators/cmdx/workflow_generator.rb +0 -84
  171. data/lib/locales/ar.yml +0 -35
  172. data/lib/locales/cs.yml +0 -35
  173. data/lib/locales/da.yml +0 -35
  174. data/lib/locales/de.yml +0 -35
  175. data/lib/locales/el.yml +0 -35
  176. data/lib/locales/es.yml +0 -35
  177. data/lib/locales/fi.yml +0 -35
  178. data/lib/locales/fr.yml +0 -35
  179. data/lib/locales/he.yml +0 -35
  180. data/lib/locales/hi.yml +0 -35
  181. data/lib/locales/it.yml +0 -35
  182. data/lib/locales/ja.yml +0 -35
  183. data/lib/locales/ko.yml +0 -35
  184. data/lib/locales/nl.yml +0 -35
  185. data/lib/locales/no.yml +0 -35
  186. data/lib/locales/pl.yml +0 -35
  187. data/lib/locales/pt.yml +0 -35
  188. data/lib/locales/ru.yml +0 -35
  189. data/lib/locales/sv.yml +0 -35
  190. data/lib/locales/th.yml +0 -35
  191. data/lib/locales/tr.yml +0 -35
  192. data/lib/locales/vi.yml +0 -35
  193. 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 execution chains for task results with thread-local storage support.
5
- #
6
- # Chain provides a mechanism to track and correlate multiple task executions
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
- THREAD_KEY = :cmdx_correlation_chain
9
+ extend Forwardable
14
10
 
15
- cmdx_attr_delegator :index, :first, :last, :size,
16
- to: :results
17
- cmdx_attr_delegator :state, :status, :outcome, :runtime,
18
- to: :first
11
+ THREAD_KEY = :cmdx_chain
19
12
 
20
- # @return [String] the unique identifier for this chain
21
- attr_reader :id
13
+ attr_reader :id, :results
22
14
 
23
- # @return [Array<CMDx::Result>] the collection of task results in this chain
24
- attr_reader :results
15
+ def_delegators :results, :index, :first, :last, :size
16
+ def_delegators :first, :state, :status, :outcome, :runtime
25
17
 
26
- # Creates a new execution chain with optional attributes.
18
+ # Creates a new chain with a unique identifier and empty results collection.
27
19
  #
28
- # @param attributes [Hash] optional attributes for chain initialization
29
- # @option attributes [String] :id custom chain identifier, defaults to current correlation ID or generates new one
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
- # Gets the current execution chain from thread-local storage.
28
+ # Retrieves the current chain for the current thread.
48
29
  #
49
- # @return [Chain, nil] the current chain or nil if none is set
30
+ # @return [Chain, nil] The current chain or nil if none exists
50
31
  #
51
- # @example Access current chain
52
- # chain = CMDx::Chain.current
53
- # chain.id if chain #=> "current-chain-id"
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 execution chain in thread-local storage.
41
+ # Sets the current chain for the current thread.
59
42
  #
60
- # @param chain [Chain, nil] the chain to set as current
43
+ # @param chain [Chain] The chain to set as current
61
44
  #
62
- # @return [Chain, nil] the chain that was set
45
+ # @return [Chain] The set chain
63
46
  #
64
- # @example Set current chain
65
- # new_chain = CMDx::Chain.new
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 execution chain from thread-local storage.
53
+ # Clears the current chain for the current thread.
73
54
  #
74
- # @return [nil] always returns nil
55
+ # @return [nil] Always returns nil
75
56
  #
76
- # @example Clear current chain
77
- # CMDx::Chain.clear
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 execution chain with a new result.
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 [CMDx::Result] the result to add to the chain
66
+ # @param result [Result] The task execution result to add
86
67
  #
87
- # @return [Chain] the current chain with the result added
68
+ # @return [Chain] The current chain (newly created or existing)
88
69
  #
89
- # @raise [TypeError] if result is not a Result instance
70
+ # @raise [TypeError] If result is not a CMDx::Result instance
90
71
  #
91
- # @example Build chain with result
92
- # task = MyTask.new
93
- # result = CMDx::Result.new(task)
94
- # chain = CMDx::Chain.build(result)
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 using the serializer.
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] serialized hash representation of the chain
92
+ # @option return [Array<Hash>] :results Array of result hashes
109
93
  #
110
- # @example Convert to hash
111
- # chain.to_h #=> { id: "abc123", results: [...], state: "complete" }
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
- ChainSerializer.call(self)
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 formatted string representation.
105
+ # Converts the chain to a string representation.
118
106
  #
119
- # @return [String] formatted string representation of the chain
107
+ # @return [String] Formatted string representation of the chain
120
108
  #
121
- # @example Convert to string
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
- ChainInspector.call(self)
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 parameter type coercion functionality.
4
+ # Registry for managing type coercion handlers.
5
5
  #
6
- # CoercionRegistry provides a centralized system for storing, accessing, and
7
- # executing type coercions during task parameter processing. It maintains an
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
- # Creates a new coercion registry with built-in coercion types.
13
+ # Initialize a new coercion registry.
17
14
  #
18
- # Initializes the registry with all standard framework coercions including
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
- # @return [CoercionRegistry] a new registry instance with built-in coercions
24
- #
25
- # @example Create a new coercion registry
17
+ # @example
26
18
  # registry = CoercionRegistry.new
27
- # registry.registry.keys
28
- # #=> [:array, :big_decimal, :boolean, :complex, :date, :datetime, :float, :hash, :integer, :rational, :string, :time, :virtual]
29
- def initialize
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
- # Registers a new coercion type in the registry.
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
- # @param type [Symbol] the coercion type identifier to register
55
- # @param coercion [Class, Proc, Symbol, String] the coercion implementation
39
+ # @return [CoercionRegistry] a new instance with duplicated registry hash
56
40
  #
57
- # @return [CoercionRegistry] self for method chaining
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
- # @example Register a custom coercion class
60
- # registry.register(:temperature, TemperatureCoercion)
49
+ # @param name [Symbol, String] the type name to register
50
+ # @param coercion [Class] the coercion class to handle this type
61
51
  #
62
- # @example Register a coercion proc
63
- # registry.register(:upcase, proc { |value, options| value.to_s.upcase })
52
+ # @return [CoercionRegistry] self for method chaining
64
53
  #
65
- # @example Register a method symbol
66
- # registry.register(:custom_parse, :parse_custom_format)
67
- def register(type, coercion)
68
- registry[type] = coercion
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
- # Executes a coercion by type on the provided value.
62
+ # Remove a coercion handler for a type.
73
63
  #
74
- # Looks up and executes the coercion implementation for the specified type,
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
- # @param task [CMDx::Task] the task instance for context when calling methods
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
- # @return [Object] the coerced value
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
- # @raise [UnknownCoercionError] when the specified coercion type is not registered
88
- # @raise [CoercionError] when the coercion fails to convert the value
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
- # @example Execute a built-in coercion
91
- # registry.call(task, :integer, "123")
92
- # #=> 123
83
+ # @return [Object] the coerced value
93
84
  #
94
- # @example Execute with options
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 Handle unknown coercion type
99
- # registry.call(task, :unknown_type, "value")
100
- # #=> raises UnknownCoercionError
101
- def call(task, type, value, options = {})
102
- raise UnknownCoercionError, "unknown coercion #{type}" unless registry.key?(type)
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
- case coercion = registry[type]
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
@@ -2,30 +2,31 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to arrays.
5
+ # Converts various input types to Array format
6
6
  #
7
- # This coercion handles conversion of various types to arrays, with special
8
- # handling for JSON-formatted strings that start with "[".
9
- class Array < Coercion
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
- # Converts the given value to an array.
12
- #
13
- # @param value [Object] the value to convert to an array
14
- # @param _options [Hash] optional configuration (currently unused)
11
+ extend self
12
+
13
+ # Converts a value to an Array
15
14
  #
16
- # @return [Array] the converted array value
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
- # @raise [JSON::ParserError] if value is a JSON string that cannot be parsed
19
- # @raise [TypeError] if the value cannot be converted to an array
19
+ # @return [Array] The converted array value
20
20
  #
21
- # @example Converting a JSON string
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 Converting other values
25
- # Coercions::Array.call("hello") #=> ["hello"]
26
- # Coercions::Array.call(123) #=> [123]
27
- # Coercions::Array.call(nil) #=> []
28
- def call(value, _options = {})
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
- # Coercion class for converting values to BigDecimal.
5
+ # Converts various input types to BigDecimal format
6
6
  #
7
- # This coercion handles conversion of various types to BigDecimal with
8
- # configurable precision. It provides precise decimal arithmetic capabilities
9
- # for financial calculations and other use cases requiring exact decimal representation.
10
- class BigDecimal < Coercion
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 the given value to a BigDecimal.
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
- # @raise [CoercionError] if the value cannot be converted to a BigDecimal
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
- # @example Converting a string
25
- # Coercions::BigDecimal.call('123.45') #=> #<BigDecimal:...,'0.12345E3',18(27)>
21
+ # @return [BigDecimal] The converted BigDecimal value
26
22
  #
27
- # @example Converting with custom precision
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 Converting an integer
31
- # Coercions::BigDecimal.call(100) #=> #<BigDecimal:...,'0.1E3',9(18)>
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
- raise CoercionError, I18n.t(
36
- "cmdx.coercions.into_a",
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
- # Coercion class for converting values to booleans.
5
+ # Converts various input types to Boolean format
6
6
  #
7
- # This coercion handles conversion of various string representations to
8
- # boolean values, supporting common true/false variations like "yes/no",
9
- # "1/0", and "t/f".
10
- class Boolean < Coercion
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 the given value to a boolean.
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
- # @return [Boolean] the converted boolean value
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
- # @raise [CoercionError] if the value cannot be converted to a boolean
22
+ # @return [Boolean] The converted boolean value
23
23
  #
24
- # @example Converting truthy values
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 Converting falsey values
30
- # Coercions::Boolean.call('false') #=> false
31
- # Coercions::Boolean.call('no') #=> false
32
- # Coercions::Boolean.call('0') #=> false
33
- def call(value, _options = {})
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
- raise CoercionError, I18n.t(
39
- "cmdx.coercions.into_a",
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
- # Coercion class for converting values to complex numbers.
5
+ # Converts various input types to Complex number format
6
6
  #
7
- # This coercion handles conversion of various types to complex numbers,
8
- # including strings, integers, floats, and other numeric types.
9
- class Complex < Coercion
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
- # Converts the given value to a complex number.
12
- #
13
- # @param value [Object] the value to convert to a complex number
14
- # @param _options [Hash] optional configuration (currently unused)
11
+ extend self
12
+
13
+ # Converts a value to a Complex number
15
14
  #
16
- # @return [Complex] the converted complex number value
15
+ # @param value [Object] The value to convert to Complex
16
+ # @param options [Hash] Optional configuration parameters (currently unused)
17
17
  #
18
- # @raise [CoercionError] if the value cannot be converted to a complex number
18
+ # @return [Complex] The converted Complex number value
19
19
  #
20
- # @example Converting numeric values
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 Converting string representations
25
- # Coercions::Complex.call("2+3i") #=> (2+3i)
26
- # Coercions::Complex.call("1-2i") #=> (1-2i)
27
- def call(value, _options = {})
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
- raise CoercionError, I18n.t(
31
- "cmdx.coercions.into_a",
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