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.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- data/docs/basics/chain.md +190 -160
- data/docs/basics/context.md +242 -154
- data/docs/basics/setup.md +302 -32
- data/docs/callbacks.md +390 -94
- data/docs/configuration.md +181 -65
- data/docs/deprecation.md +245 -0
- data/docs/getting_started.md +161 -39
- data/docs/internationalization.md +590 -70
- data/docs/interruptions/exceptions.md +135 -118
- data/docs/interruptions/faults.md +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- data/docs/outcomes/result.md +140 -112
- data/docs/outcomes/states.md +134 -99
- data/docs/outcomes/statuses.md +204 -146
- data/docs/parameters/coercions.md +232 -281
- data/docs/parameters/defaults.md +224 -169
- data/docs/parameters/definitions.md +289 -141
- data/docs/parameters/namespacing.md +250 -161
- data/docs/parameters/validations.md +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
#
|
4
|
+
# Result inspection and formatting utilities for readable result representation.
|
5
5
|
#
|
6
|
-
# This module
|
7
|
-
#
|
8
|
-
#
|
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
|
19
|
+
# Formats a result hash into a human-readable string representation.
|
19
20
|
#
|
20
|
-
#
|
21
|
-
# key
|
22
|
-
#
|
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
|
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
|
42
|
+
# @return [String] a formatted string representation of the result with key information
|
27
43
|
#
|
28
|
-
# @
|
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
|
-
#
|
47
|
+
# #=> "MyTask: type=Task index=0 id=abc123 state=executed status=success outcome=good"
|
43
48
|
#
|
44
|
-
# @example
|
45
|
-
# result =
|
49
|
+
# @example Format a result with failure reference
|
50
|
+
# result = MyTask.call
|
46
51
|
# ResultInspector.call(result)
|
47
|
-
#
|
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)
|
data/lib/cmdx/result_logger.rb
CHANGED
@@ -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
|
7
|
-
# severity levels based on the result status. It automatically
|
8
|
-
#
|
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
|
21
|
+
# Logs a task execution result with the appropriate severity level.
|
20
22
|
#
|
21
|
-
#
|
22
|
-
# the severity level
|
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
|
-
#
|
31
|
-
#
|
32
|
-
# #
|
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
|
-
#
|
36
|
-
#
|
37
|
-
# #
|
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
|
-
#
|
5
|
-
#
|
6
|
-
#
|
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
|
-
#
|
10
|
-
#
|
11
|
-
#
|
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
|
-
#
|
22
|
-
#
|
23
|
-
#
|
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
|
28
|
-
#
|
29
|
-
#
|
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
|
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
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# #=> {
|
38
|
-
# #
|
39
|
-
# #
|
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
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# #=> {
|
45
|
-
# #
|
46
|
-
# #
|
47
|
-
# #
|
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!(
|