cmdx 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/rules/cursor-instructions.mdc +6 -0
  4. data/.rubocop.yml +16 -1
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +31 -1
  7. data/README.md +72 -25
  8. data/docs/ai_prompts.md +309 -0
  9. data/docs/basics/call.md +225 -14
  10. data/docs/basics/chain.md +271 -0
  11. data/docs/basics/context.md +232 -33
  12. data/docs/basics/setup.md +76 -12
  13. data/docs/callbacks.md +273 -0
  14. data/docs/configuration.md +158 -28
  15. data/docs/getting_started.md +134 -22
  16. data/docs/interruptions/exceptions.md +189 -11
  17. data/docs/interruptions/faults.md +187 -44
  18. data/docs/interruptions/halt.md +179 -35
  19. data/docs/logging.md +194 -53
  20. data/docs/middlewares.md +735 -0
  21. data/docs/outcomes/result.md +296 -10
  22. data/docs/outcomes/states.md +203 -31
  23. data/docs/outcomes/statuses.md +275 -30
  24. data/docs/parameters/coercions.md +402 -29
  25. data/docs/parameters/defaults.md +249 -25
  26. data/docs/parameters/definitions.md +238 -72
  27. data/docs/parameters/namespacing.md +250 -27
  28. data/docs/parameters/validations.md +193 -168
  29. data/docs/testing.md +550 -0
  30. data/docs/tips_and_tricks.md +95 -43
  31. data/docs/workflows.md +319 -0
  32. data/lib/cmdx/.DS_Store +0 -0
  33. data/lib/cmdx/callback.rb +69 -0
  34. data/lib/cmdx/callback_registry.rb +106 -0
  35. data/lib/cmdx/chain.rb +190 -0
  36. data/lib/cmdx/chain_inspector.rb +149 -0
  37. data/lib/cmdx/chain_serializer.rb +175 -0
  38. data/lib/cmdx/coercions/array.rb +37 -0
  39. data/lib/cmdx/coercions/big_decimal.rb +33 -0
  40. data/lib/cmdx/coercions/boolean.rb +41 -1
  41. data/lib/cmdx/coercions/complex.rb +31 -0
  42. data/lib/cmdx/coercions/date.rb +39 -0
  43. data/lib/cmdx/coercions/date_time.rb +39 -0
  44. data/lib/cmdx/coercions/float.rb +31 -0
  45. data/lib/cmdx/coercions/hash.rb +42 -0
  46. data/lib/cmdx/coercions/integer.rb +32 -0
  47. data/lib/cmdx/coercions/rational.rb +31 -0
  48. data/lib/cmdx/coercions/string.rb +31 -0
  49. data/lib/cmdx/coercions/time.rb +39 -0
  50. data/lib/cmdx/coercions/virtual.rb +31 -0
  51. data/lib/cmdx/configuration.rb +217 -9
  52. data/lib/cmdx/context.rb +173 -2
  53. data/lib/cmdx/core_ext/hash.rb +72 -0
  54. data/lib/cmdx/core_ext/module.rb +94 -0
  55. data/lib/cmdx/core_ext/object.rb +105 -0
  56. data/lib/cmdx/correlator.rb +217 -0
  57. data/lib/cmdx/error.rb +210 -8
  58. data/lib/cmdx/errors.rb +256 -1
  59. data/lib/cmdx/fault.rb +177 -2
  60. data/lib/cmdx/faults.rb +158 -2
  61. data/lib/cmdx/immutator.rb +121 -2
  62. data/lib/cmdx/lazy_struct.rb +261 -18
  63. data/lib/cmdx/log_formatters/json.rb +46 -0
  64. data/lib/cmdx/log_formatters/key_value.rb +46 -0
  65. data/lib/cmdx/log_formatters/line.rb +54 -0
  66. data/lib/cmdx/log_formatters/logstash.rb +64 -0
  67. data/lib/cmdx/log_formatters/pretty_json.rb +57 -0
  68. data/lib/cmdx/log_formatters/pretty_key_value.rb +51 -0
  69. data/lib/cmdx/log_formatters/pretty_line.rb +60 -0
  70. data/lib/cmdx/log_formatters/raw.rb +54 -0
  71. data/lib/cmdx/logger.rb +85 -0
  72. data/lib/cmdx/logger_ansi.rb +93 -7
  73. data/lib/cmdx/logger_serializer.rb +116 -0
  74. data/lib/cmdx/middleware.rb +74 -0
  75. data/lib/cmdx/middleware_registry.rb +106 -0
  76. data/lib/cmdx/middlewares/correlate.rb +266 -0
  77. data/lib/cmdx/middlewares/timeout.rb +232 -0
  78. data/lib/cmdx/parameter.rb +228 -1
  79. data/lib/cmdx/parameter_inspector.rb +61 -0
  80. data/lib/cmdx/parameter_registry.rb +125 -0
  81. data/lib/cmdx/parameter_serializer.rb +83 -0
  82. data/lib/cmdx/parameter_validator.rb +62 -0
  83. data/lib/cmdx/parameter_value.rb +109 -1
  84. data/lib/cmdx/parameters_inspector.rb +59 -0
  85. data/lib/cmdx/parameters_serializer.rb +102 -0
  86. data/lib/cmdx/railtie.rb +123 -3
  87. data/lib/cmdx/result.rb +367 -25
  88. data/lib/cmdx/result_ansi.rb +105 -9
  89. data/lib/cmdx/result_inspector.rb +76 -0
  90. data/lib/cmdx/result_logger.rb +90 -3
  91. data/lib/cmdx/result_serializer.rb +137 -0
  92. data/lib/cmdx/rspec/result_matchers.rb +917 -0
  93. data/lib/cmdx/rspec/task_matchers.rb +570 -0
  94. data/lib/cmdx/task.rb +405 -37
  95. data/lib/cmdx/task_serializer.rb +74 -2
  96. data/lib/cmdx/utils/ansi_color.rb +95 -0
  97. data/lib/cmdx/utils/log_timestamp.rb +48 -0
  98. data/lib/cmdx/utils/monotonic_runtime.rb +71 -4
  99. data/lib/cmdx/utils/name_affix.rb +78 -0
  100. data/lib/cmdx/validators/custom.rb +82 -0
  101. data/lib/cmdx/validators/exclusion.rb +94 -0
  102. data/lib/cmdx/validators/format.rb +102 -8
  103. data/lib/cmdx/validators/inclusion.rb +104 -0
  104. data/lib/cmdx/validators/length.rb +128 -0
  105. data/lib/cmdx/validators/numeric.rb +128 -0
  106. data/lib/cmdx/validators/presence.rb +93 -7
  107. data/lib/cmdx/version.rb +7 -1
  108. data/lib/cmdx/workflow.rb +394 -0
  109. data/lib/cmdx.rb +25 -64
  110. data/lib/generators/cmdx/install_generator.rb +37 -1
  111. data/lib/generators/cmdx/task_generator.rb +69 -1
  112. data/lib/generators/cmdx/templates/install.rb +8 -12
  113. data/lib/generators/cmdx/workflow_generator.rb +109 -0
  114. metadata +54 -15
  115. data/docs/basics/run.md +0 -34
  116. data/docs/batch.md +0 -53
  117. data/docs/example.md +0 -82
  118. data/docs/hooks.md +0 -62
  119. data/lib/cmdx/batch.rb +0 -43
  120. data/lib/cmdx/parameters.rb +0 -35
  121. data/lib/cmdx/run.rb +0 -39
  122. data/lib/cmdx/run_inspector.rb +0 -26
  123. data/lib/cmdx/run_serializer.rb +0 -20
  124. data/lib/cmdx/task_hook.rb +0 -18
  125. data/lib/generators/cmdx/batch_generator.rb +0 -30
  126. /data/lib/generators/cmdx/templates/{batch.rb.tt → workflow.rb.tt} +0 -0
@@ -2,10 +2,41 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Complex type.
6
+ #
7
+ # The Complex coercion converts parameter values to Complex number objects
8
+ # using Ruby's built-in Complex() method, with proper error handling
9
+ # for values that cannot be converted to complex numbers.
10
+ #
11
+ # @example Basic complex coercion
12
+ # class MathTask < CMDx::Task
13
+ # required :complex_number, type: :complex
14
+ # optional :coefficient, type: :complex, default: Complex(1, 0)
15
+ # end
16
+ #
17
+ # @example Coercion behavior
18
+ # Coercions::Complex.call("1+2i") # => (1+2i)
19
+ # Coercions::Complex.call("3-4i") # => (3-4i)
20
+ # Coercions::Complex.call(5) # => (5+0i)
21
+ # Coercions::Complex.call("invalid") # => raises CoercionError
22
+ #
23
+ # @see ParameterValue Parameter value coercion
24
+ # @see Parameter Parameter type definitions
5
25
  module Complex
6
26
 
7
27
  module_function
8
28
 
29
+ # Coerce a value to Complex.
30
+ #
31
+ # @param value [Object] value to coerce to complex number
32
+ # @param _options [Hash] coercion options (unused)
33
+ # @return [Complex] coerced complex number value
34
+ # @raise [CoercionError] if coercion fails
35
+ #
36
+ # @example
37
+ # Coercions::Complex.call("1+2i") # => (1+2i)
38
+ # Coercions::Complex.call(42) # => (42+0i)
39
+ # Coercions::Complex.call("3.5-2i") # => (3.5-2i)
9
40
  def call(value, _options = {})
10
41
  Complex(value)
11
42
  rescue ArgumentError, TypeError
@@ -2,12 +2,51 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Date type.
6
+ #
7
+ # The Date coercion converts parameter values to Date objects
8
+ # with support for date parsing, custom format strings, and
9
+ # automatic handling of date-like objects.
10
+ #
11
+ # @example Basic date coercion
12
+ # class ProcessOrderTask < CMDx::Task
13
+ # required :order_date, type: :date
14
+ # optional :delivery_date, type: :date, format: "%Y-%m-%d"
15
+ # end
16
+ #
17
+ # @example Coercion behavior
18
+ # Coercions::Date.call("2023-12-25") # => Date object
19
+ # Coercions::Date.call("25/12/2023", format: "%d/%m/%Y") # Custom format
20
+ # Coercions::Date.call(Time.now) # => Date (from Time)
21
+ # Coercions::Date.call("invalid") # => raises CoercionError
22
+ #
23
+ # @see ParameterValue Parameter value coercion
24
+ # @see Parameter Parameter type definitions
5
25
  module Date
6
26
 
27
+ # Date-compatible class names that are passed through unchanged
28
+ # @return [Array<String>] class names that represent date-like objects
7
29
  ANALOG_TYPES = %w[Date DateTime Time].freeze
8
30
 
9
31
  module_function
10
32
 
33
+ # Coerce a value to Date.
34
+ #
35
+ # Handles multiple input formats:
36
+ # - Date, DateTime, Time objects (returned as Date)
37
+ # - String with custom format (parsed using strptime)
38
+ # - String with standard format (parsed using Date.parse)
39
+ #
40
+ # @param value [Object] value to coerce to date
41
+ # @param options [Hash] coercion options
42
+ # @option options [String] :format custom date format string
43
+ # @return [Date] coerced date value
44
+ # @raise [CoercionError] if coercion fails
45
+ #
46
+ # @example
47
+ # Coercions::Date.call("2023-12-25") # => Date
48
+ # Coercions::Date.call("25/12/2023", format: "%d/%m/%Y") # => Date with custom format
49
+ # Coercions::Date.call(Time.now) # => Date from Time
11
50
  def call(value, options = {})
12
51
  return value if ANALOG_TYPES.include?(value.class.name)
13
52
  return ::Date.strptime(value, options[:format]) if options[:format]
@@ -2,12 +2,51 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to DateTime type.
6
+ #
7
+ # The DateTime coercion converts parameter values to DateTime objects
8
+ # with support for datetime parsing, custom format strings, and
9
+ # automatic handling of date/time-like objects.
10
+ #
11
+ # @example Basic datetime coercion
12
+ # class ProcessOrderTask < CMDx::Task
13
+ # required :order_datetime, type: :date_time
14
+ # optional :delivery_datetime, type: :date_time, format: "%Y-%m-%d %H:%M:%S"
15
+ # end
16
+ #
17
+ # @example Coercion behavior
18
+ # Coercions::DateTime.call("2023-12-25T14:30:00") # => DateTime object
19
+ # Coercions::DateTime.call("25/12/2023 2:30 PM", format: "%d/%m/%Y %l:%M %p") # Custom format
20
+ # Coercions::DateTime.call(Time.now) # => DateTime (from Time)
21
+ # Coercions::DateTime.call("invalid") # => raises CoercionError
22
+ #
23
+ # @see ParameterValue Parameter value coercion
24
+ # @see Parameter Parameter type definitions
5
25
  module DateTime
6
26
 
27
+ # DateTime-compatible class names that are passed through unchanged
28
+ # @return [Array<String>] class names that represent datetime-like objects
7
29
  ANALOG_TYPES = %w[Date DateTime Time].freeze
8
30
 
9
31
  module_function
10
32
 
33
+ # Coerce a value to DateTime.
34
+ #
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 DateTime.parse)
39
+ #
40
+ # @param value [Object] value to coerce to datetime
41
+ # @param options [Hash] coercion options
42
+ # @option options [String] :format custom datetime format string
43
+ # @return [DateTime] coerced datetime value
44
+ # @raise [CoercionError] if coercion fails
45
+ #
46
+ # @example
47
+ # Coercions::DateTime.call("2023-12-25T14:30:00") # => DateTime
48
+ # Coercions::DateTime.call("25/12/2023 14:30", format: "%d/%m/%Y %H:%M") # => DateTime with custom format
49
+ # Coercions::DateTime.call(Time.now) # => DateTime from Time
11
50
  def call(value, options = {})
12
51
  return value if ANALOG_TYPES.include?(value.class.name)
13
52
  return ::DateTime.strptime(value, options[:format]) if options[:format]
@@ -2,10 +2,41 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Float type.
6
+ #
7
+ # The Float coercion converts parameter values to Float objects
8
+ # using Ruby's built-in Float() method, with proper error handling
9
+ # for values that cannot be converted to floating-point numbers.
10
+ #
11
+ # @example Basic float coercion
12
+ # class ProcessOrderTask < CMDx::Task
13
+ # required :price, type: :float
14
+ # optional :discount_rate, type: :float, default: 0.0
15
+ # end
16
+ #
17
+ # @example Coercion behavior
18
+ # Coercions::Float.call("123.45") # => 123.45
19
+ # Coercions::Float.call("1.5e2") # => 150.0 (scientific notation)
20
+ # Coercions::Float.call(42) # => 42.0
21
+ # Coercions::Float.call("invalid") # => raises CoercionError
22
+ #
23
+ # @see ParameterValue Parameter value coercion
24
+ # @see Parameter Parameter type definitions
5
25
  module Float
6
26
 
7
27
  module_function
8
28
 
29
+ # Coerce a value to Float.
30
+ #
31
+ # @param value [Object] value to coerce to float
32
+ # @param _options [Hash] coercion options (unused)
33
+ # @return [Float] coerced float value
34
+ # @raise [CoercionError] if coercion fails
35
+ #
36
+ # @example
37
+ # Coercions::Float.call("123.45") # => 123.45
38
+ # Coercions::Float.call(42) # => 42.0
39
+ # Coercions::Float.call("1e3") # => 1000.0
9
40
  def call(value, _options = {})
10
41
  Float(value)
11
42
  rescue ArgumentError, TypeError
@@ -2,10 +2,47 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Hash type.
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
5
25
  module Hash
6
26
 
7
27
  extend self
8
28
 
29
+ # Coerce a value to Hash.
30
+ #
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])
36
+ #
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
41
+ #
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}
9
46
  def call(value, _options = {})
10
47
  case value.class.name
11
48
  when "Hash", "ActionController::Parameters"
@@ -23,6 +60,11 @@ module CMDx
23
60
 
24
61
  private
25
62
 
63
+ # Raise a standardized coercion error.
64
+ #
65
+ # @return [void]
66
+ # @raise [CoercionError] always raises coercion error
67
+ # @api private
26
68
  def raise_coercion_error!
27
69
  raise CoercionError, I18n.t(
28
70
  "cmdx.coercions.into_a",
@@ -2,10 +2,42 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Integer type.
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
5
26
  module Integer
6
27
 
7
28
  module_function
8
29
 
30
+ # Coerce a value to Integer.
31
+ #
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
36
+ #
37
+ # @example
38
+ # Coercions::Integer.call("123") # => 123
39
+ # Coercions::Integer.call(45.9) # => 45
40
+ # Coercions::Integer.call("0xFF") # => 255
9
41
  def call(value, _options = {})
10
42
  Integer(value)
11
43
  rescue ArgumentError, TypeError
@@ -2,10 +2,41 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Rational type.
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
5
25
  module Rational
6
26
 
7
27
  module_function
8
28
 
29
+ # Coerce a value to Rational.
30
+ #
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
35
+ #
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)
9
40
  def call(value, _options = {})
10
41
  Rational(value)
11
42
  rescue ArgumentError, TypeError
@@ -2,10 +2,41 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to String type.
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
5
26
  module String
6
27
 
7
28
  module_function
8
29
 
30
+ # Coerce a value to String.
31
+ #
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
36
+ #
37
+ # @example
38
+ # Coercions::String.call(123) # => "123"
39
+ # Coercions::String.call(:test) # => "test"
9
40
  def call(value, _options = {})
10
41
  String(value)
11
42
  end
@@ -2,12 +2,51 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Coerces values to Time type.
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
5
25
  module Time
6
26
 
27
+ # Time-compatible class names that are passed through unchanged
28
+ # @return [Array<String>] class names that represent time-like objects
7
29
  ANALOG_TYPES = %w[Date DateTime Time].freeze
8
30
 
9
31
  module_function
10
32
 
33
+ # Coerce a value to Time.
34
+ #
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)
39
+ #
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
45
+ #
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
11
50
  def call(value, options = {})
12
51
  return value if ANALOG_TYPES.include?(value.class.name)
13
52
  return ::Time.strptime(value, options[:format]) if options[:format]
@@ -2,10 +2,41 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
+ # Virtual coercion that returns values unchanged.
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)
5
28
  module Virtual
6
29
 
7
30
  module_function
8
31
 
32
+ # Return the value unchanged (no coercion).
33
+ #
34
+ # @param value [Object] value to pass through unchanged
35
+ # @param _options [Hash] coercion options (unused)
36
+ # @return [Object] the original value without modification
37
+ #
38
+ # @example
39
+ # Coercions::Virtual.call(anything) # => anything
9
40
  def call(value, _options = {})
10
41
  value
11
42
  end