cmdx 1.0.0 → 1.1.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/rspec.md +20 -0
  3. data/.cursor/prompts/yardoc.md +8 -0
  4. data/.rubocop.yml +5 -0
  5. data/CHANGELOG.md +101 -49
  6. data/README.md +2 -1
  7. data/docs/ai_prompts.md +10 -0
  8. data/docs/basics/call.md +11 -2
  9. data/docs/basics/chain.md +10 -1
  10. data/docs/basics/context.md +9 -0
  11. data/docs/basics/setup.md +9 -0
  12. data/docs/callbacks.md +14 -37
  13. data/docs/configuration.md +68 -27
  14. data/docs/getting_started.md +11 -0
  15. data/docs/internationalization.md +148 -0
  16. data/docs/interruptions/exceptions.md +10 -1
  17. data/docs/interruptions/faults.md +11 -2
  18. data/docs/interruptions/halt.md +9 -0
  19. data/docs/logging.md +14 -4
  20. data/docs/middlewares.md +53 -43
  21. data/docs/outcomes/result.md +9 -0
  22. data/docs/outcomes/states.md +9 -0
  23. data/docs/outcomes/statuses.md +9 -0
  24. data/docs/parameters/coercions.md +58 -38
  25. data/docs/parameters/defaults.md +10 -1
  26. data/docs/parameters/definitions.md +9 -0
  27. data/docs/parameters/namespacing.md +9 -0
  28. data/docs/parameters/validations.md +8 -67
  29. data/docs/testing.md +22 -13
  30. data/docs/tips_and_tricks.md +9 -0
  31. data/docs/workflows.md +14 -4
  32. data/lib/cmdx/.DS_Store +0 -0
  33. data/lib/cmdx/callback.rb +36 -56
  34. data/lib/cmdx/callback_registry.rb +82 -73
  35. data/lib/cmdx/chain.rb +65 -122
  36. data/lib/cmdx/chain_inspector.rb +22 -115
  37. data/lib/cmdx/chain_serializer.rb +17 -148
  38. data/lib/cmdx/coercion.rb +49 -0
  39. data/lib/cmdx/coercion_registry.rb +94 -0
  40. data/lib/cmdx/coercions/array.rb +18 -36
  41. data/lib/cmdx/coercions/big_decimal.rb +21 -33
  42. data/lib/cmdx/coercions/boolean.rb +21 -40
  43. data/lib/cmdx/coercions/complex.rb +18 -31
  44. data/lib/cmdx/coercions/date.rb +20 -39
  45. data/lib/cmdx/coercions/date_time.rb +22 -39
  46. data/lib/cmdx/coercions/float.rb +19 -32
  47. data/lib/cmdx/coercions/hash.rb +22 -41
  48. data/lib/cmdx/coercions/integer.rb +20 -33
  49. data/lib/cmdx/coercions/rational.rb +20 -32
  50. data/lib/cmdx/coercions/string.rb +23 -31
  51. data/lib/cmdx/coercions/time.rb +24 -40
  52. data/lib/cmdx/coercions/virtual.rb +14 -31
  53. data/lib/cmdx/configuration.rb +57 -171
  54. data/lib/cmdx/context.rb +22 -165
  55. data/lib/cmdx/core_ext/hash.rb +42 -67
  56. data/lib/cmdx/core_ext/module.rb +35 -79
  57. data/lib/cmdx/core_ext/object.rb +63 -98
  58. data/lib/cmdx/correlator.rb +40 -156
  59. data/lib/cmdx/error.rb +37 -202
  60. data/lib/cmdx/errors.rb +165 -202
  61. data/lib/cmdx/fault.rb +55 -158
  62. data/lib/cmdx/faults.rb +26 -137
  63. data/lib/cmdx/immutator.rb +22 -109
  64. data/lib/cmdx/lazy_struct.rb +103 -187
  65. data/lib/cmdx/log_formatters/json.rb +14 -40
  66. data/lib/cmdx/log_formatters/key_value.rb +14 -40
  67. data/lib/cmdx/log_formatters/line.rb +14 -48
  68. data/lib/cmdx/log_formatters/logstash.rb +14 -57
  69. data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
  70. data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
  71. data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
  72. data/lib/cmdx/log_formatters/raw.rb +19 -49
  73. data/lib/cmdx/logger.rb +20 -82
  74. data/lib/cmdx/logger_ansi.rb +18 -75
  75. data/lib/cmdx/logger_serializer.rb +24 -114
  76. data/lib/cmdx/middleware.rb +38 -60
  77. data/lib/cmdx/middleware_registry.rb +81 -77
  78. data/lib/cmdx/middlewares/correlate.rb +41 -226
  79. data/lib/cmdx/middlewares/timeout.rb +46 -185
  80. data/lib/cmdx/parameter.rb +120 -198
  81. data/lib/cmdx/parameter_evaluator.rb +231 -0
  82. data/lib/cmdx/parameter_inspector.rb +25 -56
  83. data/lib/cmdx/parameter_registry.rb +59 -84
  84. data/lib/cmdx/parameter_serializer.rb +23 -74
  85. data/lib/cmdx/railtie.rb +24 -107
  86. data/lib/cmdx/result.rb +254 -260
  87. data/lib/cmdx/result_ansi.rb +19 -85
  88. data/lib/cmdx/result_inspector.rb +27 -68
  89. data/lib/cmdx/result_logger.rb +18 -81
  90. data/lib/cmdx/result_serializer.rb +28 -132
  91. data/lib/cmdx/rspec/matchers.rb +28 -0
  92. data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
  93. data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
  94. data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
  95. data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
  96. data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
  97. data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
  98. data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
  99. data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
  100. data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
  101. data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
  102. data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
  103. data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
  104. data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
  105. data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
  106. data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
  107. data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
  108. data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
  109. data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
  110. data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
  111. data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
  112. data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
  113. data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
  114. data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
  115. data/lib/cmdx/task.rb +213 -425
  116. data/lib/cmdx/task_deprecator.rb +55 -0
  117. data/lib/cmdx/task_processor.rb +245 -0
  118. data/lib/cmdx/task_serializer.rb +22 -70
  119. data/lib/cmdx/utils/ansi_color.rb +13 -89
  120. data/lib/cmdx/utils/log_timestamp.rb +13 -42
  121. data/lib/cmdx/utils/monotonic_runtime.rb +13 -63
  122. data/lib/cmdx/utils/name_affix.rb +21 -71
  123. data/lib/cmdx/validator.rb +48 -0
  124. data/lib/cmdx/validator_registry.rb +86 -0
  125. data/lib/cmdx/validators/exclusion.rb +55 -94
  126. data/lib/cmdx/validators/format.rb +31 -85
  127. data/lib/cmdx/validators/inclusion.rb +65 -110
  128. data/lib/cmdx/validators/length.rb +117 -133
  129. data/lib/cmdx/validators/numeric.rb +123 -130
  130. data/lib/cmdx/validators/presence.rb +38 -79
  131. data/lib/cmdx/version.rb +1 -7
  132. data/lib/cmdx/workflow.rb +46 -339
  133. data/lib/cmdx.rb +1 -1
  134. data/lib/generators/cmdx/install_generator.rb +14 -31
  135. data/lib/generators/cmdx/task_generator.rb +39 -55
  136. data/lib/generators/cmdx/templates/install.rb +61 -11
  137. data/lib/generators/cmdx/workflow_generator.rb +41 -66
  138. data/lib/locales/ar.yml +35 -0
  139. data/lib/locales/cs.yml +35 -0
  140. data/lib/locales/da.yml +35 -0
  141. data/lib/locales/de.yml +35 -0
  142. data/lib/locales/el.yml +35 -0
  143. data/lib/locales/en.yml +19 -20
  144. data/lib/locales/es.yml +19 -20
  145. data/lib/locales/fi.yml +35 -0
  146. data/lib/locales/fr.yml +35 -0
  147. data/lib/locales/he.yml +35 -0
  148. data/lib/locales/hi.yml +35 -0
  149. data/lib/locales/it.yml +35 -0
  150. data/lib/locales/ja.yml +35 -0
  151. data/lib/locales/ko.yml +35 -0
  152. data/lib/locales/nl.yml +35 -0
  153. data/lib/locales/no.yml +35 -0
  154. data/lib/locales/pl.yml +35 -0
  155. data/lib/locales/pt.yml +35 -0
  156. data/lib/locales/ru.yml +35 -0
  157. data/lib/locales/sv.yml +35 -0
  158. data/lib/locales/th.yml +35 -0
  159. data/lib/locales/tr.yml +35 -0
  160. data/lib/locales/vi.yml +35 -0
  161. data/lib/locales/zh.yml +35 -0
  162. metadata +57 -8
  163. data/lib/cmdx/parameter_validator.rb +0 -81
  164. data/lib/cmdx/parameter_value.rb +0 -244
  165. data/lib/cmdx/parameters_inspector.rb +0 -72
  166. data/lib/cmdx/parameters_serializer.rb +0 -115
  167. data/lib/cmdx/rspec/result_matchers.rb +0 -917
  168. data/lib/cmdx/rspec/task_matchers.rb +0 -570
  169. data/lib/cmdx/validators/custom.rb +0 -102
@@ -2,47 +2,33 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coerces values to Hash type.
5
+ # Coercion class for converting values to hashes.
6
6
  #
7
- # The Hash coercion converts parameter values to Hash objects
8
- # with support for various input formats including JSON strings,
9
- # arrays (converted to hash), and Rails parameters.
10
- #
11
- # @example Basic hash coercion
12
- # class ProcessOrderTask < CMDx::Task
13
- # optional :metadata, type: :hash, default: {}
14
- # optional :options, type: :hash
15
- # end
16
- #
17
- # @example Coercion behavior
18
- # Coercions::Hash.call({a: 1}) # => {a: 1}
19
- # Coercions::Hash.call('{"a":1,"b":2}') # => {"a"=>1, "b"=>2} (JSON)
20
- # Coercions::Hash.call([:a, 1, :b, 2]) # => {:a=>1, :b=>2} (Array)
21
- # Coercions::Hash.call("invalid") # => raises CoercionError
22
- #
23
- # @see ParameterValue Parameter value coercion
24
- # @see Parameter Parameter type definitions
25
- module Hash
26
-
27
- extend self
7
+ # This coercion handles conversion of various types to hashes, with special
8
+ # handling for JSON-formatted strings that start with "{" and array-to-hash
9
+ # conversion using array splatting.
10
+ class Hash < Coercion
28
11
 
29
- # Coerce a value to Hash.
12
+ # Converts the given value to a hash.
30
13
  #
31
- # Supports multiple input formats:
32
- # - Hash objects (returned as-is)
33
- # - ActionController::Parameters (returned as-is)
34
- # - JSON strings starting with '{' (parsed as JSON)
35
- # - Arrays (converted using Hash[*array])
14
+ # @param value [Object] the value to convert to a hash
15
+ # @param _options [Hash] optional configuration (currently unused)
36
16
  #
37
- # @param value [Object] value to coerce to hash
38
- # @param _options [Hash] coercion options (unused)
39
- # @return [Hash] coerced hash value
40
- # @raise [CoercionError] if coercion fails
17
+ # @return [Hash] the converted hash value
41
18
  #
42
- # @example
43
- # Coercions::Hash.call({key: "value"}) # => {key: "value"}
44
- # Coercions::Hash.call('{"a": 1}') # => {"a" => 1}
45
- # Coercions::Hash.call([:a, 1, :b, 2]) # => {:a => 1, :b => 2}
19
+ # @raise [CoercionError] if the value cannot be converted to a hash
20
+ # @raise [JSON::ParserError] if value is a JSON string that cannot be parsed
21
+ # @raise [ArgumentError] if array cannot be converted to hash pairs
22
+ # @raise [TypeError] if the value type is not supported
23
+ #
24
+ # @example Converting a JSON string
25
+ # Coercions::Hash.call('{"a": 1, "b": 2}') #=> {"a" => 1, "b" => 2}
26
+ #
27
+ # @example Converting an array to hash
28
+ # Coercions::Hash.call(["a", 1, "b", 2]) #=> {"a" => 1, "b" => 2}
29
+ #
30
+ # @example Passing through existing hashes
31
+ # Coercions::Hash.call({"key" => "value"}) #=> {"key" => "value"}
46
32
  def call(value, _options = {})
47
33
  case value.class.name
48
34
  when "Hash", "ActionController::Parameters"
@@ -60,11 +46,6 @@ module CMDx
60
46
 
61
47
  private
62
48
 
63
- # Raise a standardized coercion error.
64
- #
65
- # @return [void]
66
- # @raise [CoercionError] always raises coercion error
67
- # @api private
68
49
  def raise_coercion_error!
69
50
  raise CoercionError, I18n.t(
70
51
  "cmdx.coercions.into_a",
@@ -2,45 +2,32 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coerces values to Integer type.
5
+ # Coercion class for converting values to integers.
6
6
  #
7
- # The Integer coercion converts parameter values to Integer objects
8
- # using Ruby's built-in Integer() method, with proper error handling
9
- # for values that cannot be converted.
10
- #
11
- # @example Basic integer coercion
12
- # class ProcessOrderTask < CMDx::Task
13
- # required :order_id, type: :integer
14
- # optional :quantity, type: :integer, default: 1
15
- # end
16
- #
17
- # @example Coercion behavior
18
- # Coercions::Integer.call("123") # => 123
19
- # Coercions::Integer.call("0x10") # => 16 (hex)
20
- # Coercions::Integer.call("0b1010") # => 10 (binary)
21
- # Coercions::Integer.call(45.7) # => 45 (truncated)
22
- # Coercions::Integer.call("invalid") # => raises CoercionError
23
- #
24
- # @see ParameterValue Parameter value coercion
25
- # @see Parameter Parameter type definitions
26
- module Integer
27
-
28
- module_function
7
+ # This coercion handles conversion of various types to integers using Ruby's
8
+ # built-in Integer() method, which provides strict type conversion.
9
+ class Integer < Coercion
29
10
 
30
- # Coerce a value to Integer.
11
+ # Converts the given value to an integer.
12
+ #
13
+ # @param value [Object] the value to convert to an integer
14
+ # @param _options [Hash] optional configuration (currently unused)
15
+ #
16
+ # @return [Integer] the converted integer value
17
+ #
18
+ # @raise [CoercionError] if the value cannot be converted to an integer
31
19
  #
32
- # @param value [Object] value to coerce to integer
33
- # @param _options [Hash] coercion options (unused)
34
- # @return [Integer] coerced integer value
35
- # @raise [CoercionError] if coercion fails
20
+ # @example Converting numeric strings
21
+ # Coercions::Integer.call("123") #=> 123
22
+ # Coercions::Integer.call("-456") #=> -456
36
23
  #
37
- # @example
38
- # Coercions::Integer.call("123") # => 123
39
- # Coercions::Integer.call(45.9) # => 45
40
- # Coercions::Integer.call("0xFF") # => 255
24
+ # @example Converting other numeric types
25
+ # Coercions::Integer.call(123.45) #=> 123
26
+ # Coercions::Integer.call(Time.now) #=> 1672574400 (timestamp)
27
+ # Coercions::Integer.call(Complex(42, 0)) #=> 42
41
28
  def call(value, _options = {})
42
29
  Integer(value)
43
- rescue ArgumentError, TypeError
30
+ rescue ArgumentError, FloatDomainError, RangeError, TypeError # rubocop:disable Lint/ShadowedException
44
31
  raise CoercionError, I18n.t(
45
32
  "cmdx.coercions.into_an",
46
33
  type: "integer",
@@ -2,44 +2,32 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coerces values to Rational type.
5
+ # Coercion class for converting values to rational numbers.
6
6
  #
7
- # The Rational coercion converts parameter values to Rational number objects
8
- # using Ruby's built-in Rational() method, with proper error handling
9
- # for values that cannot be converted to rational numbers.
10
- #
11
- # @example Basic rational coercion
12
- # class MathTask < CMDx::Task
13
- # required :fraction, type: :rational
14
- # optional :ratio, type: :rational, default: Rational(1, 2)
15
- # end
16
- #
17
- # @example Coercion behavior
18
- # Coercions::Rational.call("1/2") # => (1/2)
19
- # Coercions::Rational.call("3/4") # => (3/4)
20
- # Coercions::Rational.call(0.5) # => (1/2)
21
- # Coercions::Rational.call("invalid") # => raises CoercionError
22
- #
23
- # @see ParameterValue Parameter value coercion
24
- # @see Parameter Parameter type definitions
25
- module Rational
26
-
27
- module_function
7
+ # This coercion handles conversion of various types to rational numbers,
8
+ # using Ruby's built-in Rational() method for type conversion.
9
+ class Rational < Coercion
28
10
 
29
- # Coerce a value to Rational.
11
+ # Converts the given value to a rational number.
12
+ #
13
+ # @param value [Object] the value to convert to a rational number
14
+ # @param _options [Hash] optional configuration (currently unused)
15
+ #
16
+ # @return [Rational] the converted rational value
17
+ #
18
+ # @raise [CoercionError] if the value cannot be converted to a rational number
19
+ #
20
+ # @example Converting a string fraction
21
+ # Coercions::Rational.call('1/2') #=> (1/2)
30
22
  #
31
- # @param value [Object] value to coerce to rational number
32
- # @param _options [Hash] coercion options (unused)
33
- # @return [Rational] coerced rational number value
34
- # @raise [CoercionError] if coercion fails
23
+ # @example Converting an integer
24
+ # Coercions::Rational.call(5) #=> (5/1)
35
25
  #
36
- # @example
37
- # Coercions::Rational.call("1/2") # => (1/2)
38
- # Coercions::Rational.call(0.75) # => (3/4)
39
- # Coercions::Rational.call("3.5") # => (7/2)
26
+ # @example Converting a float
27
+ # Coercions::Rational.call(0.25) #=> (1/4)
40
28
  def call(value, _options = {})
41
29
  Rational(value)
42
- rescue ArgumentError, TypeError
30
+ rescue ArgumentError, FloatDomainError, RangeError, TypeError, ZeroDivisionError # rubocop:disable Lint/ShadowedException
43
31
  raise CoercionError, I18n.t(
44
32
  "cmdx.coercions.into_a",
45
33
  type: "rational",
@@ -2,41 +2,33 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coerces values to String type.
5
+ # Coercion class for converting values to strings.
6
6
  #
7
- # The String coercion converts parameter values to String objects
8
- # using Ruby's built-in String() method, which handles various
9
- # input types safely.
10
- #
11
- # @example Basic string coercion
12
- # class ProcessOrderTask < CMDx::Task
13
- # required :order_id, type: :string
14
- # optional :notes, type: :string
15
- # end
16
- #
17
- # @example Coercion behavior
18
- # Coercions::String.call(123) # => "123"
19
- # Coercions::String.call(:symbol) # => "symbol"
20
- # Coercions::String.call(true) # => "true"
21
- # Coercions::String.call(nil) # => ""
22
- # Coercions::String.call([1, 2]) # => "12" (array to_s)
23
- #
24
- # @see ParameterValue Parameter value coercion
25
- # @see Parameter Parameter type definitions
26
- module String
27
-
28
- module_function
7
+ # This coercion handles conversion of various types to strings using Ruby's
8
+ # built-in String() method, which provides consistent string conversion
9
+ # behavior across different object types.
10
+ class String < Coercion
29
11
 
30
- # Coerce a value to String.
12
+ # Converts the given value to a string.
13
+ #
14
+ # @param value [Object] the value to convert to a string
15
+ # @param _options [Hash] optional configuration (currently unused)
16
+ #
17
+ # @return [String] the converted string value
18
+ #
19
+ # @raise [TypeError] if the value cannot be converted to a string
20
+ #
21
+ # @example Converting numbers
22
+ # Coercions::String.call(123) #=> "123"
23
+ # Coercions::String.call(45.67) #=> "45.67"
31
24
  #
32
- # @param value [Object] value to coerce to string
33
- # @param _options [Hash] coercion options (unused)
34
- # @return [String] coerced string value
35
- # @raise [CoercionError] if coercion fails
25
+ # @example Converting symbols and nil
26
+ # Coercions::String.call(:symbol) #=> "symbol"
27
+ # Coercions::String.call(nil) #=> ""
36
28
  #
37
- # @example
38
- # Coercions::String.call(123) # => "123"
39
- # Coercions::String.call(:test) # => "test"
29
+ # @example Converting boolean values
30
+ # Coercions::String.call(true) #=> "true"
31
+ # Coercions::String.call(false) #=> "false"
40
32
  def call(value, _options = {})
41
33
  String(value)
42
34
  end
@@ -2,54 +2,38 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coerces values to Time type.
5
+ # Coercion class for converting values to Time objects.
6
6
  #
7
- # The Time coercion converts parameter values to Time objects
8
- # with support for time parsing, custom format strings, and
9
- # automatic handling of time-like objects.
10
- #
11
- # @example Basic time coercion
12
- # class ProcessOrderTask < CMDx::Task
13
- # required :created_at, type: :time
14
- # optional :scheduled_at, type: :time, format: "%Y-%m-%d %H:%M:%S"
15
- # end
16
- #
17
- # @example Coercion behavior
18
- # Coercions::Time.call("2023-12-25 14:30:00") # => Time object
19
- # Coercions::Time.call("25/12/2023 2:30 PM", format: "%d/%m/%Y %l:%M %p") # Custom format
20
- # Coercions::Time.call(Date.today) # => Time (from Date)
21
- # Coercions::Time.call("invalid") # => raises CoercionError
22
- #
23
- # @see ParameterValue Parameter value coercion
24
- # @see Parameter Parameter type definitions
25
- module Time
26
-
27
- # Time-compatible class names that are passed through unchanged
28
- # @return [Array<String>] class names that represent time-like objects
29
- ANALOG_TYPES = %w[Date DateTime Time].freeze
7
+ # This coercion handles conversion of various types to Time objects, with special
8
+ # handling for analog types (DateTime, Time) and custom format parsing.
9
+ class Time < Coercion
30
10
 
31
- module_function
11
+ ANALOG_TYPES = %w[DateTime Time].freeze
32
12
 
33
- # Coerce a value to Time.
13
+ # Converts the given value to a Time object.
14
+ #
15
+ # @param value [Object] the value to convert to a Time object
16
+ # @param options [Hash] optional configuration
17
+ # @option options [String] :strptime custom format string for parsing
18
+ #
19
+ # @return [Time] the converted Time object
20
+ #
21
+ # @raise [CoercionError] if the value cannot be converted to a Time object
34
22
  #
35
- # Handles multiple input formats:
36
- # - Date, DateTime, Time objects (returned as-is)
37
- # - String with custom format (parsed using strptime)
38
- # - String with standard format (parsed using Time.parse)
23
+ # @example Converting with custom format
24
+ # Coercions::Time.call('2023-12-25 14:30', strptime: '%Y-%m-%d %H:%M') #=> 2023-12-25 14:30:00
39
25
  #
40
- # @param value [Object] value to coerce to time
41
- # @param options [Hash] coercion options
42
- # @option options [String] :format custom time format string
43
- # @return [Time] coerced time value
44
- # @raise [CoercionError] if coercion fails
26
+ # @example Converting standard time strings
27
+ # Coercions::Time.call('2023-12-25 14:30:00') #=> 2023-12-25 14:30:00
28
+ # Coercions::Time.call('Dec 25, 2023') #=> 2023-12-25 00:00:00
45
29
  #
46
- # @example
47
- # Coercions::Time.call("2023-12-25 14:30:00") # => Time
48
- # Coercions::Time.call("25/12/2023 14:30", format: "%d/%m/%Y %H:%M") # => Time with custom format
49
- # Coercions::Time.call(DateTime.now) # => Time from DateTime
30
+ # @example Analog types pass through unchanged
31
+ # time = Time.now
32
+ # Coercions::Time.call(time) #=> time (unchanged)
50
33
  def call(value, options = {})
51
34
  return value if ANALOG_TYPES.include?(value.class.name)
52
- return ::Time.strptime(value, options[:format]) if options[:format]
35
+ return value.to_time if value.respond_to?(:to_time)
36
+ return ::Time.strptime(value, options[:strptime]) if options[:strptime]
53
37
 
54
38
  ::Time.parse(value)
55
39
  rescue ArgumentError, TypeError
@@ -2,41 +2,24 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Virtual coercion that returns values unchanged.
5
+ # Coercion class for virtual values that performs no conversion.
6
6
  #
7
- # The Virtual coercion is a pass-through that returns the input value
8
- # without any transformation. This is useful for parameters that should
9
- # not undergo type coercion or when you want to preserve the original
10
- # value type and structure.
11
- #
12
- # @example Virtual coercion usage
13
- # class ProcessOrderTask < CMDx::Task
14
- # required :order # defaults to virtual type
15
- # optional :metadata, type: :virtual
16
- # optional :config, type: :virtual
17
- # end
18
- #
19
- # @example Coercion behavior
20
- # Coercions::Virtual.call("string") # => "string"
21
- # Coercions::Virtual.call(123) # => 123
22
- # Coercions::Virtual.call([1, 2, 3]) # => [1, 2, 3]
23
- # Coercions::Virtual.call({a: 1}) # => {a: 1}
24
- # Coercions::Virtual.call(nil) # => nil
25
- #
26
- # @see ParameterValue Parameter value coercion
27
- # @see Parameter Parameter type definitions (defaults to virtual)
28
- module Virtual
7
+ # This coercion acts as a pass-through, returning the input value unchanged.
8
+ # It's useful when you want to maintain the original value type and format
9
+ # without any transformation.
10
+ class Virtual < Coercion
29
11
 
30
- module_function
31
-
32
- # Return the value unchanged (no coercion).
12
+ # Returns the given value unchanged.
13
+ #
14
+ # @param value [Object] the value to return as-is
15
+ # @param _options [Hash] optional configuration (currently unused)
33
16
  #
34
- # @param value [Object] value to pass through unchanged
35
- # @param _options [Hash] coercion options (unused)
36
- # @return [Object] the original value without modification
17
+ # @return [Object] the original value without any conversion
37
18
  #
38
- # @example
39
- # Coercions::Virtual.call(anything) # => anything
19
+ # @example Returning values unchanged
20
+ # Coercions::Virtual.call("hello") #=> "hello"
21
+ # Coercions::Virtual.call(123) #=> 123
22
+ # Coercions::Virtual.call(nil) #=> nil
40
23
  def call(value, _options = {})
41
24
  value
42
25
  end