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
@@ -2,43 +2,45 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to Date objects.
5
+ # Converts various input types to Date format
6
6
  #
7
- # This coercion handles conversion of various types to Date objects, with support
8
- # for custom date formats and automatic detection of date-like objects.
9
- class Date < Coercion
7
+ # Handles conversion from strings, Date objects, DateTime objects, Time objects,
8
+ # and other date-like values to Date objects using Ruby's built-in parsing
9
+ # capabilities and optional custom format parsing.
10
+ module Date
10
11
 
12
+ extend self
13
+
14
+ # Types that are already date-like and don't need conversion
11
15
  ANALOG_TYPES = %w[Date DateTime Time].freeze
12
16
 
13
- # Converts the given value to a Date object.
14
- #
15
- # @param value [Object] the value to convert to a Date
16
- # @param options [Hash] optional configuration
17
- # @option options [String] :strptime custom date format for parsing
18
- #
19
- # @return [Date] the converted Date object
17
+ # Converts a value to a Date object
20
18
  #
21
- # @raise [CoercionError] if the value cannot be converted to a Date
19
+ # @param value [Object] The value to convert to a Date
20
+ # @param options [Hash] Optional configuration parameters
21
+ # @option options [String] :strptime Custom date format string for parsing
22
22
  #
23
- # @example Converting a string with default parsing
24
- # Coercions::Date.call('2023-12-25') #=> #<Date: 2023-12-25>
23
+ # @return [Date] The converted Date object
25
24
  #
26
- # @example Converting with custom format
27
- # Coercions::Date.call('25/12/2023', strptime: '%d/%m/%Y') #=> #<Date: 2023-12-25>
25
+ # @raise [CoercionError] If the value cannot be converted to a Date
28
26
  #
29
- # @example Converting existing date-like objects
30
- # Coercions::Date.call(DateTime.now) #=> #<Date: 2023-12-25>
27
+ # @example Convert string to Date using default parsing
28
+ # Date.call("2023-12-25") # => #<Date: 2023-12-25>
29
+ # Date.call("Dec 25, 2023") # => #<Date: 2023-12-25>
30
+ # @example Convert string using custom format
31
+ # Date.call("25/12/2023", strptime: "%d/%m/%Y") # => #<Date: 2023-12-25>
32
+ # Date.call("12-25-2023", strptime: "%m-%d-%Y") # => #<Date: 2023-12-25>
33
+ # @example Return existing Date objects unchanged
34
+ # Date.call(Date.new(2023, 12, 25)) # => #<Date: 2023-12-25>
35
+ # Date.call(DateTime.new(2023, 12, 25)) # => #<Date: 2023-12-25>
31
36
  def call(value, options = {})
32
37
  return value if ANALOG_TYPES.include?(value.class.name)
33
38
  return ::Date.strptime(value, options[:strptime]) if options[:strptime]
34
39
 
35
40
  ::Date.parse(value)
36
41
  rescue TypeError, ::Date::Error
37
- raise CoercionError, I18n.t(
38
- "cmdx.coercions.into_a",
39
- type: "date",
40
- default: "could not coerce into a date"
41
- )
42
+ type = Locale.t("cmdx.types.date")
43
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
42
44
  end
43
45
 
44
46
  end
@@ -2,45 +2,44 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to DateTime objects.
5
+ # Converts various input types to DateTime format
6
6
  #
7
- # This coercion handles conversion of various types to DateTime objects,
8
- # with support for custom date/time formats and automatic detection of
9
- # analog types (Date, DateTime, Time).
10
- class DateTime < Coercion
7
+ # Handles conversion from date strings, Date objects, Time objects, and other
8
+ # values that can be converted to DateTime using Ruby's DateTime.parse method
9
+ # or custom strptime formats.
10
+ module DateTime
11
+
12
+ extend self
11
13
 
12
14
  ANALOG_TYPES = %w[Date DateTime Time].freeze
13
15
 
14
- # Converts the given value to a DateTime object.
15
- #
16
- # @param value [Object] the value to convert to a DateTime
17
- # @param options [Hash] optional configuration
18
- # @option options [String] :strptime custom format string for parsing
19
- #
20
- # @return [DateTime] the converted DateTime object
16
+ # Converts a value to a DateTime
21
17
  #
22
- # @raise [CoercionError] if the value cannot be converted to a DateTime
18
+ # @param value [Object] The value to convert to DateTime
19
+ # @param options [Hash] Optional configuration parameters
20
+ # @option options [String] :strptime Custom date format string for parsing
23
21
  #
24
- # @example Converting a date string
25
- # Coercions::DateTime.call('2023-12-25') #=> #<DateTime: 2023-12-25T00:00:00+00:00>
22
+ # @return [DateTime] The converted DateTime value
26
23
  #
27
- # @example Converting with a custom format
28
- # Coercions::DateTime.call('25/12/2023', strptime: '%d/%m/%Y') #=> #<DateTime: 2023-12-25T00:00:00+00:00>
24
+ # @raise [CoercionError] If the value cannot be converted to DateTime
29
25
  #
30
- # @example Passing through existing DateTime objects
31
- # dt = DateTime.now
32
- # Coercions::DateTime.call(dt) #=> dt (unchanged)
26
+ # @example Convert date strings to DateTime
27
+ # DateTime.call("2023-12-25") # => #<DateTime: 2023-12-25T00:00:00+00:00>
28
+ # DateTime.call("Dec 25, 2023") # => #<DateTime: 2023-12-25T00:00:00+00:00>
29
+ # @example Convert with custom strptime format
30
+ # DateTime.call("25/12/2023", strptime: "%d/%m/%Y")
31
+ # # => #<DateTime: 2023-12-25T00:00:00+00:00>
32
+ # @example Convert existing date objects
33
+ # DateTime.call(Date.new(2023, 12, 25)) # => #<DateTime: 2023-12-25T00:00:00+00:00>
34
+ # DateTime.call(Time.new(2023, 12, 25)) # => #<DateTime: 2023-12-25T00:00:00+00:00>
33
35
  def call(value, options = {})
34
36
  return value if ANALOG_TYPES.include?(value.class.name)
35
37
  return ::DateTime.strptime(value, options[:strptime]) if options[:strptime]
36
38
 
37
39
  ::DateTime.parse(value)
38
40
  rescue TypeError, ::Date::Error
39
- raise CoercionError, I18n.t(
40
- "cmdx.coercions.into_a",
41
- type: "datetime",
42
- default: "could not coerce into a datetime"
43
- )
41
+ type = Locale.t("cmdx.types.date_time")
42
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
44
43
  end
45
44
 
46
45
  end
@@ -2,36 +2,39 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to floats.
5
+ # Converts various input types to Float format
6
6
  #
7
- # This coercion handles conversion of various types to float values using
8
- # Ruby's built-in Float() method.
9
- class Float < Coercion
7
+ # Handles conversion from numeric strings, integers, and other numeric types
8
+ # that can be converted to floats using Ruby's Float() method.
9
+ module Float
10
10
 
11
- # Converts the given value to a float.
12
- #
13
- # @param value [Object] the value to convert to a float
14
- # @param _options [Hash] optional configuration (currently unused)
11
+ extend self
12
+
13
+ # Converts a value to a Float
15
14
  #
16
- # @return [Float] the converted float value
15
+ # @param value [Object] The value to convert to a float
16
+ # @param options [Hash] Optional configuration parameters (currently unused)
17
+ # @option options [Object] :unused Currently no options are used
17
18
  #
18
- # @raise [CoercionError] if the value cannot be converted to a float
19
+ # @return [Float] The converted float value
19
20
  #
20
- # @example Converting numeric strings
21
- # Coercions::Float.call("3.14") #=> 3.14
22
- # Coercions::Float.call("42") #=> 42.0
21
+ # @raise [CoercionError] If the value cannot be converted to a float
23
22
  #
24
- # @example Converting other numeric types
25
- # Coercions::Float.call(42) #=> 42.0
26
- # Coercions::Float.call(3.14) #=> 3.14
27
- def call(value, _options = {})
23
+ # @example Convert numeric strings to float
24
+ # Float.call("123") # => 123.0
25
+ # Float.call("123.456") # => 123.456
26
+ # Float.call("-42.5") # => -42.5
27
+ # Float.call("1.23e4") # => 12300.0
28
+ # @example Convert numeric types to float
29
+ # Float.call(42) # => 42.0
30
+ # Float.call(BigDecimal("123.456")) # => 123.456
31
+ # Float.call(Rational(3, 4)) # => 0.75
32
+ # Float.call(Complex(5.0, 0)) # => 5.0
33
+ def call(value, options = {})
28
34
  Float(value)
29
35
  rescue ArgumentError, RangeError, TypeError
30
- raise CoercionError, I18n.t(
31
- "cmdx.coercions.into_a",
32
- type: "float",
33
- default: "could not coerce into a float"
34
- )
36
+ type = Locale.t("cmdx.types.float")
37
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
35
38
  end
36
39
 
37
40
  end
@@ -2,41 +2,40 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to hashes.
5
+ # Coerces various input types into Hash objects
6
6
  #
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
7
+ # Supports conversion from:
8
+ # - Hash objects (returned as-is)
9
+ # - Array objects (converted using Hash[*array])
10
+ # - JSON strings starting with "{" (parsed into Hash)
11
+ # - Other types raise CoercionError
12
+ module Hash
11
13
 
12
- # Converts the given value to a hash.
13
- #
14
- # @param value [Object] the value to convert to a hash
15
- # @param _options [Hash] optional configuration (currently unused)
16
- #
17
- # @return [Hash] the converted hash value
14
+ extend self
15
+
16
+ # Coerces a value into a Hash
18
17
  #
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
18
+ # @param value [Object] The value to coerce
19
+ # @param options [Hash] Additional options (currently unused)
20
+ # @option options [Symbol] :strict Whether to enforce strict conversion
23
21
  #
24
- # @example Converting a JSON string
25
- # Coercions::Hash.call('{"a": 1, "b": 2}') #=> {"a" => 1, "b" => 2}
22
+ # @return [Hash] The coerced hash value
26
23
  #
27
- # @example Converting an array to hash
28
- # Coercions::Hash.call(["a", 1, "b", 2]) #=> {"a" => 1, "b" => 2}
24
+ # @raise [CoercionError] When the value cannot be coerced to a Hash
29
25
  #
30
- # @example Passing through existing hashes
31
- # Coercions::Hash.call({"key" => "value"}) #=> {"key" => "value"}
32
- def call(value, _options = {})
33
- case value.class.name
34
- when "Hash", "ActionController::Parameters"
26
+ # @example Coerce from existing Hash
27
+ # Hash.call({a: 1, b: 2}) # => {a: 1, b: 2}
28
+ # @example Coerce from Array
29
+ # Hash.call([:a, 1, :b, 2]) # => {a: 1, b: 2}
30
+ # @example Coerce from JSON string
31
+ # Hash.call('{"key": "value"}') # => {"key" => "value"}
32
+ def call(value, options = {})
33
+ if value.is_a?(::Hash)
35
34
  value
36
- when "Array"
35
+ elsif value.is_a?(::Array)
37
36
  ::Hash[*value]
38
- when "String"
39
- value.start_with?("{") ? JSON.parse(value) : raise_coercion_error!
37
+ elsif value.is_a?(::String) && value.start_with?("{")
38
+ JSON.parse(value)
40
39
  else
41
40
  raise_coercion_error!
42
41
  end
@@ -46,12 +45,12 @@ module CMDx
46
45
 
47
46
  private
48
47
 
48
+ # Raises a CoercionError with localized message
49
+ #
50
+ # @raise [CoercionError] Always raised with localized error message
49
51
  def raise_coercion_error!
50
- raise CoercionError, I18n.t(
51
- "cmdx.coercions.into_a",
52
- type: "hash",
53
- default: "could not coerce into a hash"
54
- )
52
+ type = Locale.t("cmdx.types.hash")
53
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
55
54
  end
56
55
 
57
56
  end
@@ -2,37 +2,43 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to integers.
5
+ # Converts various input types to Integer format
6
6
  #
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
7
+ # Handles conversion from strings, numbers, and other values to integers
8
+ # using Ruby's Integer() method. Raises CoercionError for values that
9
+ # cannot be converted to integers.
10
+ module Integer
10
11
 
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)
12
+ extend self
13
+
14
+ # Converts a value to an Integer
15
15
  #
16
- # @return [Integer] the converted integer value
16
+ # @param value [Object] The value to convert to an integer
17
+ # @param options [Hash] Optional configuration parameters (currently unused)
18
+ # @option options [Object] :unused Currently no options are used
17
19
  #
18
- # @raise [CoercionError] if the value cannot be converted to an integer
20
+ # @return [Integer] The converted integer value
19
21
  #
20
- # @example Converting numeric strings
21
- # Coercions::Integer.call("123") #=> 123
22
- # Coercions::Integer.call("-456") #=> -456
22
+ # @raise [CoercionError] If the value cannot be converted to an integer
23
23
  #
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
28
- def call(value, _options = {})
24
+ # @example Convert numeric strings to integers
25
+ # Integer.call("42") # => 42
26
+ # Integer.call("-123") # => -123
27
+ # Integer.call("0") # => 0
28
+ # @example Convert numeric types to integers
29
+ # Integer.call(42.0) # => 42
30
+ # Integer.call(3.14) # => 3
31
+ # Integer.call(0.0) # => 0
32
+ # @example Handle edge cases
33
+ # Integer.call("") # => 0
34
+ # Integer.call(nil) # => 0
35
+ # Integer.call(false) # => 0
36
+ # Integer.call(true) # => 1
37
+ def call(value, options = {})
29
38
  Integer(value)
30
- rescue ArgumentError, FloatDomainError, RangeError, TypeError # rubocop:disable Lint/ShadowedException
31
- raise CoercionError, I18n.t(
32
- "cmdx.coercions.into_an",
33
- type: "integer",
34
- default: "could not coerce into an integer"
35
- )
39
+ rescue ArgumentError, FloatDomainError, RangeError, TypeError
40
+ type = Locale.t("cmdx.types.integer")
41
+ raise CoercionError, Locale.t("cmdx.coercions.into_an", type:)
36
42
  end
37
43
 
38
44
  end
@@ -2,37 +2,42 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to rational numbers.
5
+ # Converts various input types to Rational format
6
6
  #
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
7
+ # Handles conversion from strings, numbers, and other values to rational
8
+ # numbers using Ruby's Rational() method. Raises CoercionError for values
9
+ # that cannot be converted to rational numbers.
10
+ module Rational
10
11
 
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
12
+ extend self
13
+
14
+ # Converts a value to a Rational
17
15
  #
18
- # @raise [CoercionError] if the value cannot be converted to a rational number
16
+ # @param value [Object] The value to convert to a rational number
17
+ # @param options [Hash] Optional configuration parameters (currently unused)
18
+ # @option options [Object] :unused Currently no options are used
19
19
  #
20
- # @example Converting a string fraction
21
- # Coercions::Rational.call('1/2') #=> (1/2)
20
+ # @return [Rational] The converted rational number
22
21
  #
23
- # @example Converting an integer
24
- # Coercions::Rational.call(5) #=> (5/1)
22
+ # @raise [CoercionError] If the value cannot be converted to a rational number
25
23
  #
26
- # @example Converting a float
27
- # Coercions::Rational.call(0.25) #=> (1/4)
28
- def call(value, _options = {})
24
+ # @example Convert numeric strings to rational numbers
25
+ # Rational.call("3/4") # => (3/4)
26
+ # Rational.call("2.5") # => (5/2)
27
+ # Rational.call("0") # => (0/1)
28
+ # @example Convert numeric types to rational numbers
29
+ # Rational.call(3.14) # => (157/50)
30
+ # Rational.call(2) # => (2/1)
31
+ # Rational.call(0.5) # => (1/2)
32
+ # @example Handle edge cases
33
+ # Rational.call("") # => (0/1)
34
+ # Rational.call(nil) # => (0/1)
35
+ # Rational.call(0) # => (0/1)
36
+ def call(value, options = {})
29
37
  Rational(value)
30
- rescue ArgumentError, FloatDomainError, RangeError, TypeError, ZeroDivisionError # rubocop:disable Lint/ShadowedException
31
- raise CoercionError, I18n.t(
32
- "cmdx.coercions.into_a",
33
- type: "rational",
34
- default: "could not coerce into a rational"
35
- )
38
+ rescue ArgumentError, FloatDomainError, RangeError, TypeError, ZeroDivisionError
39
+ type = Locale.t("cmdx.types.rational")
40
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
36
41
  end
37
42
 
38
43
  end
@@ -2,34 +2,31 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to strings.
5
+ # Coerces values to String type using Ruby's built-in String() method.
6
6
  #
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
7
+ # This coercion handles various input types by converting them to their
8
+ # string representation. It's a simple wrapper around Ruby's String()
9
+ # method for consistency with the CMDx coercion interface.
10
+ module String
11
11
 
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
12
+ extend self
13
+
14
+ # Coerces a value to String type.
18
15
  #
19
- # @raise [TypeError] if the value cannot be converted to a string
16
+ # @param value [Object] The value to coerce to a string
17
+ # @param options [Hash] Optional configuration parameters (unused in this coercion)
20
18
  #
21
- # @example Converting numbers
22
- # Coercions::String.call(123) #=> "123"
23
- # Coercions::String.call(45.67) #=> "45.67"
19
+ # @return [String] The coerced string value
24
20
  #
25
- # @example Converting symbols and nil
26
- # Coercions::String.call(:symbol) #=> "symbol"
27
- # Coercions::String.call(nil) #=> ""
21
+ # @raise [TypeError] If the value cannot be converted to a string
28
22
  #
29
- # @example Converting boolean values
30
- # Coercions::String.call(true) #=> "true"
31
- # Coercions::String.call(false) #=> "false"
32
- def call(value, _options = {})
23
+ # @example Basic string coercion
24
+ # String.call("hello") # => "hello"
25
+ # String.call(42) # => "42"
26
+ # String.call([1, 2, 3]) # => "[1, 2, 3]"
27
+ # String.call(nil) # => ""
28
+ # String.call(true) # => "true"
29
+ def call(value, options = {})
33
30
  String(value)
34
31
  end
35
32
 
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module Coercions
5
+ # Coerces values to Symbol type using Ruby's to_sym method.
6
+ #
7
+ # This coercion handles various input types by converting them to symbols.
8
+ # It provides error handling for values that cannot be converted to symbols
9
+ # and raises appropriate CMDx coercion errors with localized messages.
10
+ module Symbol
11
+
12
+ extend self
13
+
14
+ # Coerces a value to Symbol type.
15
+ #
16
+ # @param value [Object] The value to coerce to a symbol
17
+ # @param options [Hash] Optional configuration parameters (unused in this coercion)
18
+ #
19
+ # @return [Symbol] The coerced symbol value
20
+ #
21
+ # @raise [CoercionError] If the value cannot be converted to a symbol
22
+ #
23
+ # @example Basic symbol coercion
24
+ # Symbol.call("hello") # => :hello
25
+ # Symbol.call("user_id") # => :user_id
26
+ # Symbol.call("") # => :""
27
+ # Symbol.call(:existing) # => :existing
28
+ def call(value, options = {})
29
+ value.to_sym
30
+ rescue NoMethodError
31
+ type = Locale.t("cmdx.types.symbol")
32
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -2,34 +2,38 @@
2
2
 
3
3
  module CMDx
4
4
  module Coercions
5
- # Coercion class for converting values to Time objects.
5
+ # Converts various input types to Time format
6
6
  #
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
7
+ # Handles conversion from strings, dates, and other time-like objects to Time
8
+ # using Ruby's built-in time parsing methods. Supports custom strptime formats
9
+ # and raises CoercionError for values that cannot be converted to Time.
10
+ module Time
11
+
12
+ extend self
10
13
 
11
14
  ANALOG_TYPES = %w[DateTime Time].freeze
12
15
 
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
16
+ # Converts a value to a Time object
20
17
  #
21
- # @raise [CoercionError] if the value cannot be converted to a Time object
18
+ # @param value [Object] The value to convert to a Time object
19
+ # @param options [Hash] Optional configuration parameters
20
+ # @option options [String] :strptime Custom strptime format string for parsing
22
21
  #
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
22
+ # @return [Time] The converted Time object
25
23
  #
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
24
+ # @raise [CoercionError] If the value cannot be converted to a Time object
29
25
  #
30
- # @example Analog types pass through unchanged
31
- # time = Time.now
32
- # Coercions::Time.call(time) #=> time (unchanged)
26
+ # @example Convert time-like objects
27
+ # Time.call(Time.now) # => Time object (unchanged)
28
+ # Time.call(DateTime.now) # => Time object (converted)
29
+ # Time.call(Date.today) # => Time object (converted)
30
+ # @example Convert strings with default parsing
31
+ # Time.call("2023-12-25 10:30:00") # => Time object
32
+ # Time.call("2023-12-25") # => Time object
33
+ # Time.call("10:30:00") # => Time object
34
+ # @example Convert strings with custom format
35
+ # Time.call("25/12/2023", strptime: "%d/%m/%Y") # => Time object
36
+ # Time.call("12-25-2023", strptime: "%m-%d-%Y") # => Time object
33
37
  def call(value, options = {})
34
38
  return value if ANALOG_TYPES.include?(value.class.name)
35
39
  return value.to_time if value.respond_to?(:to_time)
@@ -37,11 +41,8 @@ module CMDx
37
41
 
38
42
  ::Time.parse(value)
39
43
  rescue ArgumentError, TypeError
40
- raise CoercionError, I18n.t(
41
- "cmdx.coercions.into_a",
42
- type: "time",
43
- default: "could not coerce into a time"
44
- )
44
+ type = Locale.t("cmdx.types.time")
45
+ raise CoercionError, Locale.t("cmdx.coercions.into_a", type:)
45
46
  end
46
47
 
47
48
  end