cmdx 1.1.0 → 1.1.1

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +13 -12
  4. data/.cursor/prompts/yardoc.md +11 -6
  5. data/CHANGELOG.md +13 -2
  6. data/README.md +1 -0
  7. data/docs/ai_prompts.md +269 -195
  8. data/docs/basics/call.md +124 -58
  9. data/docs/basics/chain.md +190 -160
  10. data/docs/basics/context.md +242 -154
  11. data/docs/basics/setup.md +302 -32
  12. data/docs/callbacks.md +390 -94
  13. data/docs/configuration.md +181 -65
  14. data/docs/deprecation.md +245 -0
  15. data/docs/getting_started.md +161 -39
  16. data/docs/internationalization.md +590 -70
  17. data/docs/interruptions/exceptions.md +135 -118
  18. data/docs/interruptions/faults.md +150 -125
  19. data/docs/interruptions/halt.md +134 -80
  20. data/docs/logging.md +181 -118
  21. data/docs/middlewares.md +150 -377
  22. data/docs/outcomes/result.md +140 -112
  23. data/docs/outcomes/states.md +134 -99
  24. data/docs/outcomes/statuses.md +204 -146
  25. data/docs/parameters/coercions.md +232 -281
  26. data/docs/parameters/defaults.md +224 -169
  27. data/docs/parameters/definitions.md +289 -141
  28. data/docs/parameters/namespacing.md +250 -161
  29. data/docs/parameters/validations.md +260 -133
  30. data/docs/testing.md +191 -197
  31. data/docs/workflows.md +143 -98
  32. data/lib/cmdx/callback.rb +23 -19
  33. data/lib/cmdx/callback_registry.rb +1 -3
  34. data/lib/cmdx/chain_inspector.rb +23 -23
  35. data/lib/cmdx/chain_serializer.rb +38 -19
  36. data/lib/cmdx/coercion.rb +20 -12
  37. data/lib/cmdx/coercion_registry.rb +51 -32
  38. data/lib/cmdx/configuration.rb +84 -31
  39. data/lib/cmdx/context.rb +32 -21
  40. data/lib/cmdx/core_ext/hash.rb +13 -13
  41. data/lib/cmdx/core_ext/module.rb +1 -1
  42. data/lib/cmdx/core_ext/object.rb +12 -12
  43. data/lib/cmdx/correlator.rb +60 -39
  44. data/lib/cmdx/errors.rb +105 -131
  45. data/lib/cmdx/fault.rb +66 -45
  46. data/lib/cmdx/immutator.rb +20 -21
  47. data/lib/cmdx/lazy_struct.rb +78 -70
  48. data/lib/cmdx/log_formatters/json.rb +1 -1
  49. data/lib/cmdx/log_formatters/key_value.rb +1 -1
  50. data/lib/cmdx/log_formatters/line.rb +1 -1
  51. data/lib/cmdx/log_formatters/logstash.rb +1 -1
  52. data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
  53. data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
  54. data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
  55. data/lib/cmdx/log_formatters/raw.rb +2 -2
  56. data/lib/cmdx/logger.rb +19 -14
  57. data/lib/cmdx/logger_ansi.rb +33 -17
  58. data/lib/cmdx/logger_serializer.rb +85 -24
  59. data/lib/cmdx/middleware.rb +39 -21
  60. data/lib/cmdx/middleware_registry.rb +4 -3
  61. data/lib/cmdx/parameter.rb +151 -89
  62. data/lib/cmdx/parameter_inspector.rb +34 -21
  63. data/lib/cmdx/parameter_registry.rb +36 -30
  64. data/lib/cmdx/parameter_serializer.rb +21 -14
  65. data/lib/cmdx/result.rb +136 -135
  66. data/lib/cmdx/result_ansi.rb +31 -17
  67. data/lib/cmdx/result_inspector.rb +32 -27
  68. data/lib/cmdx/result_logger.rb +23 -14
  69. data/lib/cmdx/result_serializer.rb +65 -27
  70. data/lib/cmdx/task.rb +234 -113
  71. data/lib/cmdx/task_deprecator.rb +22 -25
  72. data/lib/cmdx/task_processor.rb +89 -88
  73. data/lib/cmdx/task_serializer.rb +27 -14
  74. data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
  75. data/lib/cmdx/validator.rb +25 -16
  76. data/lib/cmdx/validator_registry.rb +53 -31
  77. data/lib/cmdx/validators/exclusion.rb +1 -1
  78. data/lib/cmdx/validators/format.rb +2 -2
  79. data/lib/cmdx/validators/inclusion.rb +2 -2
  80. data/lib/cmdx/validators/length.rb +2 -2
  81. data/lib/cmdx/validators/numeric.rb +3 -3
  82. data/lib/cmdx/validators/presence.rb +2 -2
  83. data/lib/cmdx/version.rb +1 -1
  84. data/lib/cmdx/workflow.rb +54 -33
  85. data/lib/generators/cmdx/task_generator.rb +6 -6
  86. data/lib/generators/cmdx/workflow_generator.rb +6 -6
  87. metadata +3 -1
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Provides formatted inspection functionality for task execution results.
4
+ # Result inspection and formatting utilities for readable result representation.
5
5
  #
6
- # This module formats result hash data into a human-readable string representation
7
- # with ordered key-value pairs. It handles special formatting for specific keys
8
- # like failure references and applies consistent ordering to result attributes.
6
+ # This module provides functionality to format result metadata into human-readable
7
+ # strings for debugging, logging, and introspection purposes. It processes result
8
+ # hashes and displays essential result information in a structured, ordered format
9
+ # that emphasizes the most important attributes first.
9
10
  module ResultInspector
10
11
 
11
12
  ORDERED_KEYS = %i[
@@ -15,36 +16,40 @@ module CMDx
15
16
 
16
17
  module_function
17
18
 
18
- # Formats a result hash into a human-readable inspection string.
19
+ # Formats a result hash into a human-readable string representation.
19
20
  #
20
- # Creates a formatted string representation of a result hash with ordered
21
- # key-value pairs. Special keys like :class, :caused_failure, and :threw_failure
22
- # receive custom formatting for better readability and debugging.
21
+ # This method converts result metadata into a structured string format that
22
+ # displays key result information in a predefined order. It handles special
23
+ # formatting for class names, failure references, and standard key-value pairs.
24
+ # The method filters the result hash to only include keys defined in ORDERED_KEYS
25
+ # and applies appropriate formatting based on the key type.
23
26
  #
24
- # @param result [Hash] the result hash to format and inspect
27
+ # @param result [Hash] the result hash to format
28
+ # @option result [String] :class the class name of the task or workflow
29
+ # @option result [String] :type the type identifier (e.g., "Task", "Workflow")
30
+ # @option result [Integer] :index the position index in the execution chain
31
+ # @option result [String] :id the unique identifier of the result
32
+ # @option result [String] :state the execution state (e.g., "executed", "skipped")
33
+ # @option result [String] :status the execution status (e.g., "success", "failure")
34
+ # @option result [String] :outcome the overall outcome (e.g., "good", "bad")
35
+ # @option result [Hash] :metadata additional metadata associated with the result
36
+ # @option result [Array] :tags the tags associated with the result
37
+ # @option result [Integer] :pid the process ID if applicable
38
+ # @option result [Float] :runtime the execution runtime in seconds
39
+ # @option result [Hash] :caused_failure reference to a failure this result caused
40
+ # @option result [Hash] :threw_failure reference to a failure this result threw
25
41
  #
26
- # @return [String] formatted string with space-separated key-value pairs
42
+ # @return [String] a formatted string representation of the result with key information
27
43
  #
28
- # @raise [NoMethodError] if result doesn't respond to key? or []
29
- #
30
- # @example Formatting a basic result
31
- # result = { class: "MyTask", state: "complete", status: "success" }
32
- # ResultInspector.call(result)
33
- # # => "MyTask: state=complete status=success"
34
- #
35
- # @example Formatting result with failure information
36
- # result = {
37
- # class: "ProcessTask",
38
- # state: "interrupted",
39
- # caused_failure: { index: 2, class: "ValidationError", id: "val_123" }
40
- # }
44
+ # @example Format a successful task result
45
+ # result = MyTask.call
41
46
  # ResultInspector.call(result)
42
- # # => "ProcessTask: state=interrupted caused_failure=<[2] ValidationError: val_123>"
47
+ # #=> "MyTask: type=Task index=0 id=abc123 state=executed status=success outcome=good"
43
48
  #
44
- # @example Formatting empty or minimal result
45
- # result = { id: "task_456" }
49
+ # @example Format a result with failure reference
50
+ # result = MyTask.call
46
51
  # ResultInspector.call(result)
47
- # # => "id=task_456"
52
+ # #=> "MyTask: index=1 state=executed status=failure caused_failure=<[2] ValidationError: def456>"
48
53
  def call(result)
49
54
  ORDERED_KEYS.filter_map do |key|
50
55
  next unless result.key?(key)
@@ -3,9 +3,11 @@
3
3
  module CMDx
4
4
  # Logger utilities for task execution results.
5
5
  #
6
- # This module provides functionality to log task execution results with appropriate
7
- # severity levels based on the result status. It automatically maps result statuses
8
- # to corresponding log levels and delegates to the task's configured logger.
6
+ # This module provides functionality to log task execution results with
7
+ # appropriate severity levels based on the result status. It automatically
8
+ # determines the correct log level (info, warn, error) based on whether
9
+ # the task succeeded, was skipped, or failed, and delegates to the task's
10
+ # configured logger instance.
9
11
  module ResultLogger
10
12
 
11
13
  STATUS_TO_SEVERITY = {
@@ -16,25 +18,32 @@ module CMDx
16
18
 
17
19
  module_function
18
20
 
19
- # Logs the task execution result with appropriate severity level.
21
+ # Logs a task execution result with the appropriate severity level.
20
22
  #
21
- # This method retrieves the logger from the task and logs the result using
22
- # the severity level mapped from the result's status. If no logger is configured
23
- # for the task, the method returns early without logging.
23
+ # Retrieves the logger from the task instance and logs the result object
24
+ # using the severity level determined by the result's status. If no logger
25
+ # is configured for the task, the method returns early without logging.
26
+ # The logger level is temporarily set to match the severity to ensure
27
+ # the message is captured regardless of current log level configuration.
24
28
  #
25
- # @param result [Result] the task execution result to log
29
+ # @param result [CMDx::Result] the task execution result to log
26
30
  #
27
31
  # @return [void]
28
32
  #
29
33
  # @example Log a successful task result
30
- # result = task.process
31
- # CMDx::ResultLogger.call(result)
32
- # # => logs at info level: "Task completed successfully"
34
+ # task = ProcessDataTask.call(data: "input")
35
+ # ResultLogger.call(task.result)
36
+ # # Logs at :info level: "Result: ProcessDataTask completed successfully"
33
37
  #
34
38
  # @example Log a failed task result
35
- # result = failing_task.process
36
- # CMDx::ResultLogger.call(result)
37
- # # => logs at error level: "Task failed with error"
39
+ # task = ValidateDataTask.call(data: "invalid")
40
+ # ResultLogger.call(task.result)
41
+ # # Logs at :error level: "Result: ValidateDataTask failed with error"
42
+ #
43
+ # @example Log a skipped task result
44
+ # task = ConditionalTask.call(condition: false)
45
+ # ResultLogger.call(task.result)
46
+ # # Logs at :warn level: "Result: ConditionalTask was skipped"
38
47
  def call(result)
39
48
  logger = result.task.send(:logger)
40
49
  return if logger.nil?
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Provides serialization functionality for CMDx::Result objects,
5
- # converting them into structured hash representations suitable for
6
- # logging, storage, or transmission.
4
+ # Result serialization module for converting result objects to hash format.
5
+ #
6
+ # This module provides functionality to serialize result objects into a
7
+ # standardized hash representation that includes essential metadata about
8
+ # the result such as task information, execution state, status, outcome,
9
+ # metadata, and runtime. For failed results, it intelligently strips
10
+ # redundant failure information to avoid duplication in serialized output.
7
11
  module ResultSerializer
8
12
 
9
- # A proc that removes failure-related metadata from the hash representation
10
- # when the result hasn't actually failed in the specified way.
11
- # This prevents duplicate failure information from appearing in logs.
13
+ # Proc for stripping failure information from serialized results.
14
+ # Removes caused_failure and threw_failure keys when the result doesn't
15
+ # have the corresponding failure state, avoiding redundant information.
12
16
  STRIP_FAILURE = proc do |h, r, k|
13
17
  unless r.send(:"#{k}?")
14
18
  # Strip caused/threw failures since its the same info as the log line
@@ -18,33 +22,67 @@ module CMDx
18
22
 
19
23
  module_function
20
24
 
21
- # Converts a Result object into a structured hash representation.
22
- # Combines task serialization data with result-specific information
23
- # including execution state, status, outcome, metadata, and runtime.
25
+ # Serializes a result object into a hash representation.
26
+ #
27
+ # Converts a result instance into a standardized hash format containing
28
+ # task metadata and execution information. For failed results, applies
29
+ # intelligent failure stripping to remove redundant caused_failure and
30
+ # threw_failure information that would duplicate log output.
24
31
  #
25
32
  # @param result [CMDx::Result] the result object to serialize
26
33
  #
27
- # @return [Hash] a structured hash containing task information and result details
28
- # including :state, :status, :outcome, :metadata, :runtime, and optionally
29
- # :caused_failure and :threw_failure if the result failed
34
+ # @return [Hash] a hash containing the result's metadata and execution information
35
+ # @option return [Integer] :index the result's position index in the execution chain
36
+ # @option return [String] :chain_id the unique identifier of the result's execution chain
37
+ # @option return [String] :type the task type, either "Task" or "Workflow"
38
+ # @option return [String] :class the full class name of the task
39
+ # @option return [String] :id the unique identifier of the task instance
40
+ # @option return [Array] :tags the tags associated with the task from cmd settings
41
+ # @option return [Symbol] :state the execution state (:executing, :complete, :interrupted)
42
+ # @option return [Symbol] :status the execution status (:success, :failed, :skipped)
43
+ # @option return [Symbol] :outcome the execution outcome (:good, :bad)
44
+ # @option return [Hash] :metadata additional metadata collected during execution
45
+ # @option return [Float] :runtime the execution runtime in seconds
46
+ # @option return [Hash] :caused_failure failure information if result caused a failure (stripped for non-failed results)
47
+ # @option return [Hash] :threw_failure failure information if result threw a failure (stripped for non-failed results)
30
48
  #
31
- # @raise [NoMethodError] if result doesn't respond to expected methods
32
- # @raise [TypeError] if result.task is invalid for TaskSerializer
49
+ # @raise [NoMethodError] if the result doesn't respond to required methods
33
50
  #
34
- # @example Serializing a successful result
35
- # result = task.call
36
- # CMDx::ResultSerializer.call(result)
37
- # #=> { index: 0, chain_id: "abc123", type: "Task", class: "MyTask",
38
- # # id: "def456", tags: [], state: "complete", status: "success",
39
- # # outcome: "good", metadata: {}, runtime: 0.05 }
51
+ # @example Serialize a successful result
52
+ # task = SuccessfulTask.new(data: "test")
53
+ # ResultSerializer.call(result)
54
+ # #=> {
55
+ # # index: 0,
56
+ # # chain_id: "abc123",
57
+ # # type: "Task",
58
+ # # class: "SuccessfulTask",
59
+ # # id: "def456",
60
+ # # tags: [],
61
+ # # state: :complete,
62
+ # # status: :success,
63
+ # # outcome: :good,
64
+ # # metadata: {},
65
+ # # runtime: 0.045
66
+ # # }
40
67
  #
41
- # @example Serializing a failed result
42
- # result = task.call
43
- # CMDx::ResultSerializer.call(result)
44
- # #=> { index: 0, chain_id: "abc123", type: "Task", class: "MyTask",
45
- # # id: "def456", tags: [], state: "interrupted", status: "failed",
46
- # # outcome: "bad", metadata: { error: "Something went wrong" },
47
- # # runtime: 0.02, caused_failure: {...}, threw_failure: {...} }
68
+ # @example Serialize a failed result with failure stripping
69
+ # task = FailingTask.call
70
+ # ResultSerializer.call(task.result)
71
+ # #=> {
72
+ # # index: 1,
73
+ # # chain_id: "xyz789",
74
+ # # type: "Task",
75
+ # # class: "FailingTask",
76
+ # # id: "ghi012",
77
+ # # tags: [],
78
+ # # state: :interrupted,
79
+ # # status: :failed,
80
+ # # outcome: :bad,
81
+ # # metadata: { reason: "Database connection failed" },
82
+ # # runtime: 0.012,
83
+ # # caused_failure: { message: "Task failed", ... },
84
+ # # threw_failure: { message: "Validation error", ... },
85
+ # # }
48
86
  def call(result)
49
87
  TaskSerializer.call(result.task).tap do |hash|
50
88
  hash.merge!(