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
data/lib/cmdx/chain.rb CHANGED
@@ -1,79 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Thread-local chain that tracks task execution results within a correlation context.
4
+ # Manages execution chains for task results with thread-local storage support.
5
5
  #
6
- # A Chain represents a sequence of task executions that are logically related,
7
- # typically within the same request or operation flow. It provides thread-local
8
- # storage to ensure that tasks executing in the same thread share the same chain
9
- # while maintaining isolation across different threads.
10
- #
11
- # @example Basic usage with automatic chain creation
12
- # # Chain is automatically created when first task runs
13
- # result1 = MyTask.call(data: "first")
14
- # result2 = MyTask.call(data: "second")
15
- #
16
- # result1.chain.id == result2.chain.id #=> true
17
- # result1.index #=> 0
18
- # result2.index #=> 1
19
- #
20
- # @example Using custom chain ID
21
- # chain = CMDx::Chain.new(id: "custom-correlation-123")
22
- # CMDx::Chain.current = chain
23
- #
24
- # result = MyTask.call(data: "test")
25
- # result.chain.id #=> "custom-correlation-123"
26
- #
27
- # @example Thread isolation
28
- # # Each thread gets its own chain
29
- # Thread.new do
30
- # result = MyTask.call(data: "thread1")
31
- # result.chain.id #=> unique ID for this thread
32
- # end
33
- #
34
- # Thread.new do
35
- # result = MyTask.call(data: "thread2")
36
- # result.chain.id #=> different unique ID
37
- # end
38
- #
39
- # @example Temporary chain context
40
- # CMDx::Chain.use(id: "temp-correlation") do
41
- # result = MyTask.call(data: "test")
42
- # result.chain.id #=> "temp-correlation"
43
- # end
44
- # # Original chain is restored after block
45
- #
46
- # @see CMDx::Correlator
47
- # @since 1.0.0
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.
48
11
  class Chain
49
12
 
50
- # Thread-local storage key for the current chain
51
13
  THREAD_KEY = :cmdx_correlation_chain
52
14
 
53
- __cmdx_attr_delegator :index, :first, :last, :size,
54
- to: :results
55
- __cmdx_attr_delegator :state, :status, :outcome, :runtime,
56
- to: :first
15
+ cmdx_attr_delegator :index, :first, :last, :size,
16
+ to: :results
17
+ cmdx_attr_delegator :state, :status, :outcome, :runtime,
18
+ to: :first
57
19
 
58
- # @!attribute [r] id
59
- # @return [String] the unique identifier for this chain
60
- # @!attribute [r] results
61
- # @return [Array<CMDx::Result>] the collection of task results in this chain
62
- attr_reader :id, :results
20
+ # @return [String] the unique identifier for this chain
21
+ attr_reader :id
63
22
 
64
- # Creates a new chain instance.
23
+ # @return [Array<CMDx::Result>] the collection of task results in this chain
24
+ attr_reader :results
25
+
26
+ # Creates a new execution chain with optional attributes.
27
+ #
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
65
30
  #
66
- # @param attributes [Hash] configuration options for the chain
67
- # @option attributes [String] :id custom identifier for the chain.
68
- # If not provided, uses the current correlator ID or generates a new UUID.
31
+ # @return [Chain] the newly created chain instance
69
32
  #
70
- # @example Create chain with default ID
33
+ # @example Create a chain with default ID
71
34
  # chain = CMDx::Chain.new
72
- # chain.id #=> "018c2b95-b764-7615-a924-cc5b910ed1e5"
35
+ # chain.id #=> "generated-uuid"
73
36
  #
74
- # @example Create chain with custom ID
75
- # chain = CMDx::Chain.new(id: "user-session-123")
76
- # chain.id #=> "user-session-123"
37
+ # @example Create a chain with custom ID
38
+ # chain = CMDx::Chain.new(id: "custom-123")
39
+ # chain.id #=> "custom-123"
77
40
  def initialize(attributes = {})
78
41
  @id = attributes[:id] || CMDx::Correlator.id || CMDx::Correlator.generate
79
42
  @results = []
@@ -81,53 +44,55 @@ module CMDx
81
44
 
82
45
  class << self
83
46
 
84
- # Returns the current thread-local chain.
47
+ # Gets the current execution chain from thread-local storage.
85
48
  #
86
- # @return [CMDx::Chain, nil] the chain for the current thread, or nil if none exists
49
+ # @return [Chain, nil] the current chain or nil if none is set
87
50
  #
88
- # @example
89
- # CMDx::Chain.current #=> nil (no chain set)
90
- #
91
- # MyTask.call(data: "test")
92
- # CMDx::Chain.current #=> #<CMDx::Chain:0x... @id="018c2b95...">
51
+ # @example Access current chain
52
+ # chain = CMDx::Chain.current
53
+ # chain.id if chain #=> "current-chain-id"
93
54
  def current
94
55
  Thread.current[THREAD_KEY]
95
56
  end
96
57
 
97
- # Sets the current thread-local chain.
58
+ # Sets the current execution chain in thread-local storage.
59
+ #
60
+ # @param chain [Chain, nil] the chain to set as current
98
61
  #
99
- # @param chain [CMDx::Chain, nil] the chain to set for the current thread
100
- # @return [CMDx::Chain, nil] the chain that was set
62
+ # @return [Chain, nil] the chain that was set
101
63
  #
102
- # @example
103
- # chain = CMDx::Chain.new(id: "custom-id")
104
- # CMDx::Chain.current = chain
105
- # CMDx::Chain.current.id #=> "custom-id"
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
106
68
  def current=(chain)
107
69
  Thread.current[THREAD_KEY] = chain
108
70
  end
109
71
 
110
- # Clears the current thread-local chain.
72
+ # Clears the current execution chain from thread-local storage.
111
73
  #
112
- # @return [nil]
74
+ # @return [nil] always returns nil
113
75
  #
114
- # @example
115
- # CMDx::Chain.current #=> #<CMDx::Chain:0x...>
76
+ # @example Clear current chain
116
77
  # CMDx::Chain.clear
117
- # CMDx::Chain.current #=> nil
78
+ # CMDx::Chain.current #=> nil
118
79
  def clear
119
80
  Thread.current[THREAD_KEY] = nil
120
81
  end
121
82
 
122
- # Adds a result to the current chain, creating a new chain if none exists.
83
+ # Builds or extends the current execution chain with a new result.
123
84
  #
124
- # This method is typically called internally by the task execution framework
125
- # and should not be used directly in application code.
85
+ # @param result [CMDx::Result] the result to add to the chain
126
86
  #
127
- # @param result [CMDx::Result] the task result to add to the chain
128
- # @return [CMDx::Chain] the chain containing the result
87
+ # @return [Chain] the current chain with the result added
129
88
  #
130
- # @api private
89
+ # @raise [TypeError] if result is not a Result instance
90
+ #
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
131
96
  def build(result)
132
97
  raise TypeError, "must be a Result" unless result.is_a?(Result)
133
98
 
@@ -138,50 +103,28 @@ module CMDx
138
103
 
139
104
  end
140
105
 
141
- # Converts the chain to a hash representation.
142
- #
143
- # Serializes the chain and all its results into a structured hash
144
- # suitable for logging, debugging, and data interchange.
106
+ # Converts the chain to a hash representation using the serializer.
145
107
  #
146
- # @return [Hash] Structured hash representation of the chain
108
+ # @return [Hash] serialized hash representation of the chain
147
109
  #
148
- # @example
149
- # chain.to_h
150
- # # => {
151
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
152
- # # state: "complete",
153
- # # status: "success",
154
- # # outcome: "success",
155
- # # runtime: 0.5,
156
- # # results: [
157
- # # { class: "ProcessOrderTask", state: "complete", status: "success", ... },
158
- # # { class: "SendEmailTask", state: "complete", status: "success", ... }
159
- # # ]
160
- # # }
110
+ # @example Convert to hash
111
+ # chain.to_h #=> { id: "abc123", results: [...], state: "complete" }
161
112
  def to_h
162
113
  ChainSerializer.call(self)
163
114
  end
164
115
  alias to_a to_h
165
116
 
166
- # Converts the chain to a string representation for inspection.
167
- #
168
- # Creates a comprehensive, human-readable summary of the chain including
169
- # all task results with formatted headers and footers.
117
+ # Converts the chain to a formatted string representation.
170
118
  #
171
- # @return [String] Formatted chain summary with task details
119
+ # @return [String] formatted string representation of the chain
172
120
  #
173
- # @example
174
- # chain.to_s
175
- # # => "
176
- # # chain: 018c2b95-b764-7615-a924-cc5b910ed1e5
177
- # # ================================================
178
- # #
179
- # # ProcessOrderTask: index=0 state=complete status=success ...
180
- # # SendEmailTask: index=1 state=complete status=success ...
181
- # #
182
- # # ================================================
183
- # # state: complete | status: success | outcome: success | runtime: 0.5
184
- # # "
121
+ # @example Convert to string
122
+ # puts chain.to_s
123
+ # # chain: abc123
124
+ # # ===================
125
+ # # {...}
126
+ # # ===================
127
+ # # state: complete | status: success | outcome: success | runtime: 0.001
185
128
  def to_s
186
129
  ChainInspector.call(self)
187
130
  end
@@ -1,137 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Chain inspection utility for generating comprehensive chain summaries.
4
+ # Provides formatted inspection and display functionality for execution chains.
5
5
  #
6
- # The ChainInspector module provides functionality to convert Chain instances
7
- # into detailed, human-readable string representations. It creates formatted
8
- # summaries that include chain metadata, all task results, and summary statistics
9
- # with visual separators for easy debugging and monitoring.
10
- #
11
- # @example Basic chain inspection
12
- # result = ProcessOrderTask.call(order_id: 123)
13
- # chain = result.chain
14
- #
15
- # ChainInspector.call(chain)
16
- # # => "
17
- # # chain: 018c2b95-b764-7615-a924-cc5b910ed1e5
18
- # # ================================================
19
- # #
20
- # # {
21
- # # class: "ProcessOrderTask",
22
- # # type: "Task",
23
- # # index: 0,
24
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
25
- # # tags: [],
26
- # # state: "complete",
27
- # # status: "success",
28
- # # outcome: "success",
29
- # # metadata: {},
30
- # # runtime: 0.5
31
- # # }
32
- # #
33
- # # ================================================
34
- # # state: complete | status: success | outcome: success | runtime: 0.5
35
- # # "
36
- #
37
- # @example Chain with multiple tasks
38
- # class ComplexTask < CMDx::Task
39
- # def call
40
- # SubTask1.call(context)
41
- # SubTask2.call(context)
42
- # end
43
- # end
44
- #
45
- # result = ComplexTask.call
46
- # ChainInspector.call(result.chain)
47
- # # => Shows formatted output with all three task results and summary
48
- #
49
- # @example Failed chain inspection
50
- # # When a chain contains failed tasks, the summary reflects the failure state
51
- # ChainInspector.call(failed_chain)
52
- # # => Shows all task results with failure information and failed summary
53
- #
54
- # @see CMDx::Chain Chain execution context and result tracking
55
- # @see CMDx::Result Individual result inspection via to_h
6
+ # This module formats chain execution information into a human-readable string
7
+ # representation, including the chain ID, individual task results, and summary
8
+ # information about the chain's final state.
56
9
  module ChainInspector
57
10
 
58
- # Keys to display in the chain summary footer.
59
- #
60
- # These keys represent the most important chain-level information
61
- # that should be displayed in the summary footer for quick reference.
62
11
  FOOTER_KEYS = %i[
63
12
  state status outcome runtime
64
13
  ].freeze
65
14
 
66
15
  module_function
67
16
 
68
- # Converts a Chain instance to a comprehensive string representation.
69
- #
70
- # Creates a formatted summary that includes:
71
- # - Chain header with unique ID
72
- # - Visual separator line
73
- # - Pretty-printed hash representation of each result
74
- # - Visual separator line
75
- # - Summary footer with key chain statistics
17
+ # Formats a chain into a human-readable inspection string.
76
18
  #
77
- # @param chain [CMDx::Chain] The chain instance to inspect
78
- # @return [String] Formatted chain summary with task details and statistics
19
+ # Creates a formatted display showing the chain ID, individual task results,
20
+ # and summary footer with execution state information. The output includes
21
+ # visual separators and structured formatting for easy reading.
79
22
  #
80
- # @example Single task chain
81
- # chain = SimpleTask.call.chain
82
- # ChainInspector.call(chain)
83
- # # => "
84
- # # chain: 018c2b95-b764-7615-a924-cc5b910ed1e5
85
- # # ================================================
86
- # #
87
- # # {
88
- # # class: "SimpleTask",
89
- # # type: "Task",
90
- # # index: 0,
91
- # # state: "complete",
92
- # # status: "success",
93
- # # outcome: "success",
94
- # # runtime: 0.1
95
- # # }
96
- # #
97
- # # ================================================
98
- # # state: complete | status: success | outcome: success | runtime: 0.1
99
- # # "
23
+ # @param chain [CMDx::Chain] the chain object to inspect
100
24
  #
101
- # @example Multi-task chain
102
- # class ParentTask < CMDx::Task
103
- # def call
104
- # ChildTask1.call(context)
105
- # ChildTask2.call(context)
106
- # end
107
- # end
25
+ # @return [String] formatted multi-line string representation of the chain
108
26
  #
109
- # chain = ParentTask.call.chain
110
- # ChainInspector.call(chain)
111
- # # => "
112
- # # chain: 018c2b95-b764-7615-a924-cc5b910ed1e5
113
- # # ================================================
114
- # #
115
- # # { class: "ParentTask", index: 0, state: "complete", status: "success", ... }
116
- # # { class: "ChildTask1", index: 1, state: "complete", status: "success", ... }
117
- # # { class: "ChildTask2", index: 2, state: "complete", status: "success", ... }
118
- # #
119
- # # ================================================
120
- # # state: complete | status: success | outcome: success | runtime: 0.5
121
- # # "
27
+ # @raise [NoMethodError] if chain doesn't respond to required methods (id, results, state, status, outcome, runtime)
122
28
  #
123
- # @example Failed chain inspection
124
- # failed_chain = FailingTask.call.chain
125
- # ChainInspector.call(failed_chain)
126
- # # => "
127
- # # chain: 018c2b95-b764-7615-a924-cc5b910ed1e5
128
- # # ================================================
29
+ # @example Inspect a simple chain
30
+ # chain = CMDx::Chain.new(id: "abc123")
31
+ # result = CMDx::Result.new(task)
32
+ # chain.results << result
33
+ # puts CMDx::ChainInspector.call(chain)
34
+ # # Output:
35
+ # # chain: abc123
36
+ # # ===================
129
37
  # #
130
- # # { class: "FailingTask", state: "interrupted", status: "failed", metadata: { reason: "Error" }, ... }
38
+ # # {:state=>"complete", :status=>"success", ...}
131
39
  # #
132
- # # ================================================
133
- # # state: interrupted | status: failed | outcome: failed | runtime: 0.1
134
- # # "
40
+ # # ===================
41
+ # # state: complete | status: success | outcome: success | runtime: 0.001
135
42
  def call(chain)
136
43
  header = "\nchain: #{chain.id}"
137
44
  footer = FOOTER_KEYS.map { |key| "#{key}: #{chain.send(key)}" }.join(" | ")
@@ -1,164 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Chain serialization utility for converting Chain objects to hash representations.
5
- #
6
- # The ChainSerializer module provides functionality to serialize Chain instances
7
- # into structured hash representations suitable for inspection, logging,
8
- # debugging, and data interchange. It creates comprehensive data structures
9
- # that include chain metadata and all associated task results.
10
- #
11
- # @example Basic chain serialization
12
- # result = ProcessOrderTask.call(order_id: 123)
13
- # chain = result.chain
14
- #
15
- # ChainSerializer.call(chain)
16
- # # => {
17
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
18
- # # state: "complete",
19
- # # status: "success",
20
- # # outcome: "success",
21
- # # runtime: 0.5,
22
- # # results: [
23
- # # {
24
- # # class: "ProcessOrderTask",
25
- # # type: "Task",
26
- # # index: 0,
27
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
28
- # # chain_id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
29
- # # tags: [],
30
- # # state: "complete",
31
- # # status: "success",
32
- # # outcome: "success",
33
- # # metadata: {},
34
- # # runtime: 0.5
35
- # # }
36
- # # ]
37
- # # }
38
- #
39
- # @example Chain with multiple tasks
40
- # class ComplexTask < CMDx::Task
41
- # def call
42
- # SubTask1.call(context)
43
- # SubTask2.call(context)
44
- # end
45
- # end
46
- #
47
- # result = ComplexTask.call
48
- # chain = result.chain
49
- #
50
- # ChainSerializer.call(chain)
51
- # # => {
52
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
53
- # # state: "complete",
54
- # # status: "success",
55
- # # outcome: "success",
56
- # # runtime: 1.2,
57
- # # results: [
58
- # # { class: "ComplexTask", index: 0, state: "complete", status: "success", ... },
59
- # # { class: "SubTask1", index: 1, state: "complete", status: "success", ... },
60
- # # { class: "SubTask2", index: 2, state: "complete", status: "success", ... }
61
- # # ]
62
- # # }
63
- #
64
- # @example Failed chain serialization
65
- # failed_result = FailingTask.call
66
- # failed_chain = failed_result.chain
67
- #
68
- # ChainSerializer.call(failed_chain)
69
- # # => {
70
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
71
- # # state: "interrupted",
72
- # # status: "failed",
73
- # # outcome: "failed",
74
- # # runtime: 0.1,
75
- # # results: [
76
- # # {
77
- # # class: "FailingTask",
78
- # # state: "interrupted",
79
- # # status: "failed",
80
- # # outcome: "failed",
81
- # # metadata: { reason: "Something went wrong" },
82
- # # runtime: 0.1,
83
- # # ...
84
- # # }
85
- # # ]
86
- # # }
87
- #
88
- # @see CMDx::Chain Chain execution context and result tracking
89
- # @see CMDx::ResultSerializer Individual result serialization
90
- # @see CMDx::ChainInspector Human-readable chain formatting
4
+ # Serializes Chain objects into hash representations for external consumption.
5
+ # Provides a consistent interface for converting chain execution data into
6
+ # structured format suitable for logging, API responses, or persistence.
91
7
  module ChainSerializer
92
8
 
93
9
  module_function
94
10
 
95
- # Converts a Chain object to a hash representation.
11
+ # Converts a chain object into a hash representation containing execution metadata.
12
+ # Extracts key chain attributes and serializes all contained results for complete
13
+ # execution state capture.
96
14
  #
97
- # Serializes a Chain instance into a structured hash containing chain metadata
98
- # and all associated task results. The chain-level data is derived from the
99
- # first result in the collection, while all individual results are included
100
- # in their full serialized form.
15
+ # @param chain [Chain] the chain instance to serialize
101
16
  #
102
- # @param chain [CMDx::Chain] The chain object to serialize
103
- # @return [Hash] Structured hash representation of the chain and all results
17
+ # @return [Hash] hash containing chain metadata and serialized results
104
18
  #
105
- # @example Simple chain serialization
106
- # chain = SimpleTask.call.chain
107
- # ChainSerializer.call(chain)
108
- # # => {
109
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
110
- # # state: "complete",
111
- # # status: "success",
112
- # # outcome: "success",
113
- # # runtime: 0.1,
114
- # # results: [
115
- # # {
116
- # # class: "SimpleTask",
117
- # # type: "Task",
118
- # # index: 0,
119
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
120
- # # chain_id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
121
- # # tags: [],
122
- # # state: "complete",
123
- # # status: "success",
124
- # # outcome: "success",
125
- # # metadata: {},
126
- # # runtime: 0.1
127
- # # }
128
- # # ]
129
- # # }
130
- #
131
- # @example Multi-task chain serialization
132
- # class ParentTask < CMDx::Task
133
- # def call
134
- # ChildTask.call(context)
135
- # end
136
- # end
19
+ # @raise [NoMethodError] if chain doesn't respond to required methods
137
20
  #
138
- # chain = ParentTask.call.chain
21
+ # @example Serializing a workflow chain
22
+ # chain = UserWorkflow.call(user_id: 123)
139
23
  # ChainSerializer.call(chain)
140
24
  # # => {
141
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
142
- # # state: "complete", # From first result (ParentTask)
143
- # # status: "success", # From first result (ParentTask)
144
- # # outcome: "success", # From first result (ParentTask)
145
- # # runtime: 0.5, # From first result (ParentTask)
146
- # # results: [
147
- # # { class: "ParentTask", index: 0, ... },
148
- # # { class: "ChildTask", index: 1, ... }
149
- # # ]
150
- # # }
151
- #
152
- # @example Empty chain serialization
153
- # empty_chain = Chain.new
154
- # ChainSerializer.call(empty_chain)
155
- # # => {
156
- # # id: "018c2b95-b764-7615-a924-cc5b910ed1e5",
157
- # # state: nil,
158
- # # status: nil,
159
- # # outcome: nil,
160
- # # runtime: nil,
161
- # # results: []
25
+ # # id: "abc123",
26
+ # # state: :complete,
27
+ # # status: :success,
28
+ # # outcome: :good,
29
+ # # runtime: 0.045,
30
+ # # results: [...]
162
31
  # # }
163
32
  def call(chain)
164
33
  {
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ # Base class for implementing type coercion functionality in parameter processing.
5
+ #
6
+ # Coercions are used to convert parameter values from one type to another,
7
+ # supporting both built-in types and custom coercion logic. All coercion
8
+ # implementations must inherit from this class and implement the abstract call method.
9
+ class Coercion
10
+
11
+ # Executes a coercion by creating a new instance and calling it.
12
+ #
13
+ # @param value [Object] the value to be coerced
14
+ # @param options [Hash] additional options for the coercion
15
+ #
16
+ # @return [Object] the coerced value
17
+ #
18
+ # @raise [UndefinedCallError] when the coercion subclass doesn't implement call
19
+ #
20
+ # @example Execute a coercion on a value
21
+ # IntegerCoercion.call("42")
22
+ # # => 42
23
+ def self.call(value, options = {})
24
+ new.call(value, options)
25
+ end
26
+
27
+ # Abstract method that must be implemented by coercion subclasses.
28
+ #
29
+ # This method contains the actual coercion logic to convert the input
30
+ # value to the desired type. Subclasses must override this method to
31
+ # provide their specific coercion implementation.
32
+ #
33
+ # @param _value [Object] the value to be coerced
34
+ # @param _options [Hash] additional options for the coercion
35
+ #
36
+ # @return [Object] the coerced value
37
+ #
38
+ # @raise [UndefinedCallError] always raised in the base class
39
+ #
40
+ # @example Implement in a subclass
41
+ # def call(value, options = {})
42
+ # Integer(value)
43
+ # end
44
+ def call(_value, _options = {})
45
+ raise UndefinedCallError, "call method not defined in #{self.class.name}"
46
+ end
47
+
48
+ end
49
+ end