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.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +4 -1
- data/.cursor/prompts/llms.md +20 -0
- data/.cursor/prompts/rspec.md +4 -1
- data/.cursor/prompts/yardoc.md +3 -2
- data/.cursor/rules/cursor-instructions.mdc +56 -1
- data/.irbrc +6 -0
- data/.rubocop.yml +29 -18
- data/.ruby-version +1 -1
- data/CHANGELOG.md +6 -128
- data/LLM.md +3317 -0
- data/README.md +68 -44
- data/docs/attributes/coercions.md +162 -0
- data/docs/attributes/defaults.md +90 -0
- data/docs/attributes/definitions.md +281 -0
- data/docs/attributes/naming.md +78 -0
- data/docs/attributes/validations.md +309 -0
- data/docs/basics/chain.md +56 -249
- data/docs/basics/context.md +56 -289
- data/docs/basics/execution.md +114 -0
- data/docs/basics/setup.md +37 -334
- data/docs/callbacks.md +89 -467
- data/docs/deprecation.md +91 -174
- data/docs/getting_started.md +212 -202
- data/docs/internationalization.md +11 -647
- data/docs/interruptions/exceptions.md +23 -198
- data/docs/interruptions/faults.md +71 -151
- data/docs/interruptions/halt.md +109 -186
- data/docs/logging.md +44 -256
- data/docs/middlewares.md +113 -426
- data/docs/outcomes/result.md +81 -228
- data/docs/outcomes/states.md +33 -221
- data/docs/outcomes/statuses.md +21 -311
- data/docs/tips_and_tricks.md +120 -70
- data/docs/workflows.md +99 -283
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/attribute.rb +229 -0
- data/lib/cmdx/attribute_registry.rb +94 -0
- data/lib/cmdx/attribute_value.rb +193 -0
- data/lib/cmdx/callback_registry.rb +69 -77
- data/lib/cmdx/chain.rb +56 -73
- data/lib/cmdx/coercion_registry.rb +52 -68
- data/lib/cmdx/coercions/array.rb +19 -18
- data/lib/cmdx/coercions/big_decimal.rb +20 -24
- data/lib/cmdx/coercions/boolean.rb +26 -25
- data/lib/cmdx/coercions/complex.rb +21 -22
- data/lib/cmdx/coercions/date.rb +25 -23
- data/lib/cmdx/coercions/date_time.rb +24 -25
- data/lib/cmdx/coercions/float.rb +25 -22
- data/lib/cmdx/coercions/hash.rb +31 -32
- data/lib/cmdx/coercions/integer.rb +30 -24
- data/lib/cmdx/coercions/rational.rb +29 -24
- data/lib/cmdx/coercions/string.rb +19 -22
- data/lib/cmdx/coercions/symbol.rb +37 -0
- data/lib/cmdx/coercions/time.rb +26 -25
- data/lib/cmdx/configuration.rb +49 -108
- data/lib/cmdx/context.rb +222 -44
- data/lib/cmdx/deprecator.rb +61 -0
- data/lib/cmdx/errors.rb +42 -252
- data/lib/cmdx/exceptions.rb +39 -0
- data/lib/cmdx/faults.rb +78 -39
- data/lib/cmdx/freezer.rb +51 -0
- data/lib/cmdx/identifier.rb +30 -0
- data/lib/cmdx/locale.rb +52 -0
- data/lib/cmdx/log_formatters/json.rb +21 -22
- data/lib/cmdx/log_formatters/key_value.rb +20 -22
- data/lib/cmdx/log_formatters/line.rb +15 -22
- data/lib/cmdx/log_formatters/logstash.rb +22 -23
- data/lib/cmdx/log_formatters/raw.rb +16 -22
- data/lib/cmdx/middleware_registry.rb +70 -74
- data/lib/cmdx/middlewares/correlate.rb +90 -54
- data/lib/cmdx/middlewares/runtime.rb +58 -0
- data/lib/cmdx/middlewares/timeout.rb +48 -68
- data/lib/cmdx/railtie.rb +12 -45
- data/lib/cmdx/result.rb +229 -314
- data/lib/cmdx/task.rb +194 -366
- data/lib/cmdx/utils/call.rb +49 -0
- data/lib/cmdx/utils/condition.rb +71 -0
- data/lib/cmdx/utils/format.rb +61 -0
- data/lib/cmdx/validator_registry.rb +63 -72
- data/lib/cmdx/validators/exclusion.rb +38 -67
- data/lib/cmdx/validators/format.rb +48 -49
- data/lib/cmdx/validators/inclusion.rb +43 -74
- data/lib/cmdx/validators/length.rb +91 -154
- data/lib/cmdx/validators/numeric.rb +87 -162
- data/lib/cmdx/validators/presence.rb +37 -50
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/worker.rb +178 -0
- data/lib/cmdx/workflow.rb +85 -81
- data/lib/cmdx.rb +19 -13
- data/lib/generators/cmdx/install_generator.rb +14 -13
- data/lib/generators/cmdx/task_generator.rb +25 -50
- data/lib/generators/cmdx/templates/install.rb +11 -46
- data/lib/generators/cmdx/templates/task.rb.tt +3 -2
- data/lib/locales/en.yml +18 -4
- data/src/cmdx-logo.png +0 -0
- metadata +32 -116
- data/docs/ai_prompts.md +0 -393
- data/docs/basics/call.md +0 -317
- data/docs/configuration.md +0 -344
- data/docs/parameters/coercions.md +0 -396
- data/docs/parameters/defaults.md +0 -335
- data/docs/parameters/definitions.md +0 -446
- data/docs/parameters/namespacing.md +0 -378
- data/docs/parameters/validations.md +0 -405
- data/docs/testing.md +0 -553
- data/lib/cmdx/callback.rb +0 -53
- data/lib/cmdx/chain_inspector.rb +0 -56
- data/lib/cmdx/chain_serializer.rb +0 -63
- data/lib/cmdx/coercion.rb +0 -57
- data/lib/cmdx/coercions/virtual.rb +0 -29
- data/lib/cmdx/core_ext/hash.rb +0 -83
- data/lib/cmdx/core_ext/module.rb +0 -98
- data/lib/cmdx/core_ext/object.rb +0 -125
- data/lib/cmdx/correlator.rb +0 -122
- data/lib/cmdx/error.rb +0 -60
- data/lib/cmdx/fault.rb +0 -140
- data/lib/cmdx/immutator.rb +0 -52
- data/lib/cmdx/lazy_struct.rb +0 -246
- data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
- data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
- data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
- data/lib/cmdx/logger.rb +0 -49
- data/lib/cmdx/logger_ansi.rb +0 -68
- data/lib/cmdx/logger_serializer.rb +0 -116
- data/lib/cmdx/middleware.rb +0 -70
- data/lib/cmdx/parameter.rb +0 -312
- data/lib/cmdx/parameter_evaluator.rb +0 -231
- data/lib/cmdx/parameter_inspector.rb +0 -66
- data/lib/cmdx/parameter_registry.rb +0 -106
- data/lib/cmdx/parameter_serializer.rb +0 -59
- data/lib/cmdx/result_ansi.rb +0 -71
- data/lib/cmdx/result_inspector.rb +0 -71
- data/lib/cmdx/result_logger.rb +0 -59
- data/lib/cmdx/result_serializer.rb +0 -104
- data/lib/cmdx/rspec/matchers.rb +0 -28
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
- data/lib/cmdx/task_deprecator.rb +0 -52
- data/lib/cmdx/task_processor.rb +0 -246
- data/lib/cmdx/task_serializer.rb +0 -57
- data/lib/cmdx/utils/ansi_color.rb +0 -73
- data/lib/cmdx/utils/log_timestamp.rb +0 -36
- data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
- data/lib/cmdx/utils/name_affix.rb +0 -52
- data/lib/cmdx/validator.rb +0 -57
- data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
- data/lib/generators/cmdx/workflow_generator.rb +0 -84
- data/lib/locales/ar.yml +0 -35
- data/lib/locales/cs.yml +0 -35
- data/lib/locales/da.yml +0 -35
- data/lib/locales/de.yml +0 -35
- data/lib/locales/el.yml +0 -35
- data/lib/locales/es.yml +0 -35
- data/lib/locales/fi.yml +0 -35
- data/lib/locales/fr.yml +0 -35
- data/lib/locales/he.yml +0 -35
- data/lib/locales/hi.yml +0 -35
- data/lib/locales/it.yml +0 -35
- data/lib/locales/ja.yml +0 -35
- data/lib/locales/ko.yml +0 -35
- data/lib/locales/nl.yml +0 -35
- data/lib/locales/no.yml +0 -35
- data/lib/locales/pl.yml +0 -35
- data/lib/locales/pt.yml +0 -35
- data/lib/locales/ru.yml +0 -35
- data/lib/locales/sv.yml +0 -35
- data/lib/locales/th.yml +0 -35
- data/lib/locales/tr.yml +0 -35
- data/lib/locales/vi.yml +0 -35
- data/lib/locales/zh.yml +0 -35
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Serialization module for converting chain objects to hash representation.
|
5
|
-
#
|
6
|
-
# ChainSerializer provides functionality to serialize chain objects into a
|
7
|
-
# standardized hash format that includes essential metadata about the chain
|
8
|
-
# execution including unique identification, execution state, status, outcome,
|
9
|
-
# runtime, and all contained task results. The serialized format is commonly
|
10
|
-
# used for debugging, logging, introspection, and data exchange throughout
|
11
|
-
# the task execution pipeline.
|
12
|
-
module ChainSerializer
|
13
|
-
|
14
|
-
module_function
|
15
|
-
|
16
|
-
# Serializes a chain object into a hash representation.
|
17
|
-
#
|
18
|
-
# Converts a chain instance into a standardized hash format containing
|
19
|
-
# key metadata about the chain's execution context and all contained results.
|
20
|
-
# The serialization includes information delegated from the first result in
|
21
|
-
# the chain (state, status, outcome, runtime) along with the chain's unique
|
22
|
-
# identifier and complete collection of task results converted to hashes.
|
23
|
-
#
|
24
|
-
# @param chain [CMDx::Chain] the chain object to serialize
|
25
|
-
#
|
26
|
-
# @return [Hash] a hash containing the chain's metadata and execution information
|
27
|
-
# @option return [String] :id the unique identifier of the chain
|
28
|
-
# @option return [String] :state the execution state delegated from first result
|
29
|
-
# @option return [String] :status the execution status delegated from first result
|
30
|
-
# @option return [String] :outcome the execution outcome delegated from first result
|
31
|
-
# @option return [Float] :runtime the execution runtime in seconds delegated from first result
|
32
|
-
# @option return [Array<Hash>] :results array of serialized result hashes from all tasks in the chain
|
33
|
-
#
|
34
|
-
# @raise [NoMethodError] if the chain doesn't respond to required methods (id, state, status, outcome, runtime, results)
|
35
|
-
#
|
36
|
-
# @example Serialize a workflow chain with multiple tasks
|
37
|
-
# workflow = DataProcessingWorkflow.call(input: "data")
|
38
|
-
# ChainSerializer.call(workflow.chain)
|
39
|
-
# #=> {
|
40
|
-
# # id: "def456",
|
41
|
-
# # state: "complete",
|
42
|
-
# # status: "success",
|
43
|
-
# # outcome: "success",
|
44
|
-
# # runtime: 0.123,
|
45
|
-
# # results: [
|
46
|
-
# # { index: 0, class: "ValidateDataTask", status: "success", ... },
|
47
|
-
# # { index: 1, class: "ProcessDataTask", status: "success", ... },
|
48
|
-
# # { index: 2, class: "SaveDataTask", status: "success", ... }
|
49
|
-
# # ]
|
50
|
-
# # }
|
51
|
-
def call(chain)
|
52
|
-
{
|
53
|
-
id: chain.id,
|
54
|
-
state: chain.state,
|
55
|
-
status: chain.status,
|
56
|
-
outcome: chain.outcome,
|
57
|
-
runtime: chain.runtime,
|
58
|
-
results: chain.results.map(&:to_h)
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
end
|
data/lib/cmdx/coercion.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Base class for implementing parameter coercion functionality in task processing.
|
5
|
-
#
|
6
|
-
# Coercions are used to convert parameter values from one type to another during
|
7
|
-
# task execution, enabling automatic type conversion and normalization. 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
|
-
# @raise [CoercionError] when coercion fails in subclass implementations
|
20
|
-
#
|
21
|
-
# @example Execute a coercion on a value
|
22
|
-
# StringCoercion.call(123) #=> "123"
|
23
|
-
#
|
24
|
-
# @example Execute with options
|
25
|
-
# CustomCoercion.call("value", strict: true) #=> processed_value
|
26
|
-
def self.call(value, options = {})
|
27
|
-
new.call(value, options)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Abstract method that must be implemented by coercion subclasses.
|
31
|
-
#
|
32
|
-
# This method contains the actual coercion logic to convert the input
|
33
|
-
# value to the desired type. Subclasses must override this method
|
34
|
-
# to provide their specific coercion implementation.
|
35
|
-
#
|
36
|
-
# @param value [Object] the value to be coerced (unused in base class)
|
37
|
-
# @param options [Hash] additional options for the coercion (unused in base class)
|
38
|
-
#
|
39
|
-
# @return [Object] the coerced value
|
40
|
-
#
|
41
|
-
# @raise [UndefinedCallError] always raised in the base class
|
42
|
-
# @raise [CoercionError] when coercion fails in subclass implementations
|
43
|
-
#
|
44
|
-
# @example Implement in a subclass
|
45
|
-
# class StringCoercion < CMDx::Coercion
|
46
|
-
# def call(value, _options = {})
|
47
|
-
# String(value)
|
48
|
-
# rescue ArgumentError, TypeError
|
49
|
-
# raise CoercionError, "could not coerce into a string"
|
50
|
-
# end
|
51
|
-
# end
|
52
|
-
def call(value, options = {}) # rubocop:disable Lint/UnusedMethodArgument
|
53
|
-
raise UndefinedCallError, "call method not defined in #{self.class.name}"
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module Coercions
|
5
|
-
# Coercion class for virtual values that performs no conversion.
|
6
|
-
#
|
7
|
-
# This coercion acts as a pass-through, returning the input value unchanged.
|
8
|
-
# It's useful when you want to maintain the original value type and format
|
9
|
-
# without any transformation.
|
10
|
-
class Virtual < Coercion
|
11
|
-
|
12
|
-
# Returns the given value unchanged.
|
13
|
-
#
|
14
|
-
# @param value [Object] the value to return as-is
|
15
|
-
# @param _options [Hash] optional configuration (currently unused)
|
16
|
-
#
|
17
|
-
# @return [Object] the original value without any conversion
|
18
|
-
#
|
19
|
-
# @example Returning values unchanged
|
20
|
-
# Coercions::Virtual.call("hello") #=> "hello"
|
21
|
-
# Coercions::Virtual.call(123) #=> 123
|
22
|
-
# Coercions::Virtual.call(nil) #=> nil
|
23
|
-
def call(value, _options = {})
|
24
|
-
value
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/cmdx/core_ext/hash.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module CoreExt
|
5
|
-
# Extensions for Ruby's Hash class that provide flexible key access and querying.
|
6
|
-
# These extensions are automatically included in all hashes when CMDx is loaded, providing
|
7
|
-
# seamless symbol/string key interoperability and enhanced key existence checking.
|
8
|
-
module HashExtensions
|
9
|
-
|
10
|
-
# Fetches a value from the hash with flexible key matching.
|
11
|
-
# Tries the exact key first, then attempts symbol/string conversion if not found.
|
12
|
-
#
|
13
|
-
# @param key [Symbol, String, Object] the key to fetch from the hash
|
14
|
-
#
|
15
|
-
# @return [Object, nil] the value associated with the key, or nil if not found
|
16
|
-
#
|
17
|
-
# @example Fetch with symbol key
|
18
|
-
# hash = { name: "John", "age" => 30 }
|
19
|
-
# hash.cmdx_fetch(:name) #=> "John"
|
20
|
-
# hash.cmdx_fetch(:age) #=> 30
|
21
|
-
#
|
22
|
-
# @example Fetch with string key
|
23
|
-
# hash = { name: "John", "age" => 30 }
|
24
|
-
# hash.cmdx_fetch("name") #=> "John"
|
25
|
-
# hash.cmdx_fetch("age") #=> 30
|
26
|
-
def cmdx_fetch(key)
|
27
|
-
case key
|
28
|
-
when Symbol then fetch(key) { self[key.to_s] }
|
29
|
-
when String then fetch(key) { self[key.to_sym] }
|
30
|
-
else self[key]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Checks if a key exists in the hash with flexible key matching.
|
35
|
-
# Tries the exact key first, then attempts symbol/string conversion.
|
36
|
-
#
|
37
|
-
# @param key [Symbol, String, Object] the key to check for existence
|
38
|
-
#
|
39
|
-
# @return [Boolean] true if the key exists (in any form), false otherwise
|
40
|
-
#
|
41
|
-
# @example Check key existence
|
42
|
-
# hash = { name: "John", "age" => 30 }
|
43
|
-
# hash.cmdx_key?(:name) #=> true
|
44
|
-
# hash.cmdx_key?("name") #=> true
|
45
|
-
# hash.cmdx_key?(:age) #=> true
|
46
|
-
# hash.cmdx_key?("age") #=> true
|
47
|
-
# hash.cmdx_key?(:missing) #=> false
|
48
|
-
def cmdx_key?(key)
|
49
|
-
key?(key) || key?(
|
50
|
-
case key
|
51
|
-
when Symbol then key.to_s
|
52
|
-
when String then key.to_sym
|
53
|
-
end
|
54
|
-
)
|
55
|
-
rescue NoMethodError
|
56
|
-
false
|
57
|
-
end
|
58
|
-
|
59
|
-
# Checks if the hash responds to a method or contains a key.
|
60
|
-
# Combines method existence checking with flexible key existence checking.
|
61
|
-
#
|
62
|
-
# @param key [Symbol, String] the method name or key to check
|
63
|
-
# @param include_private [Boolean] whether to include private methods in the check
|
64
|
-
#
|
65
|
-
# @return [Boolean] true if the hash responds to the method or contains the key
|
66
|
-
#
|
67
|
-
# @example Check method or key response
|
68
|
-
# hash = { name: "John", "age" => 30 }
|
69
|
-
# hash.cmdx_respond_to?(:keys) #=> true (method exists)
|
70
|
-
# hash.cmdx_respond_to?(:name) #=> true (key exists)
|
71
|
-
# hash.cmdx_respond_to?("age") #=> true (key exists)
|
72
|
-
# hash.cmdx_respond_to?(:missing) #=> false
|
73
|
-
def cmdx_respond_to?(key, include_private = false)
|
74
|
-
respond_to?(key.to_sym, include_private) || cmdx_key?(key)
|
75
|
-
rescue NoMethodError
|
76
|
-
cmdx_key?(key)
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
Hash.include(CMDx::CoreExt::HashExtensions)
|
data/lib/cmdx/core_ext/module.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module CoreExt
|
5
|
-
# Extensions for Ruby's Module class that provide attribute delegation and settings functionality.
|
6
|
-
# These extensions are automatically included in all modules when CMDx is loaded.
|
7
|
-
module ModuleExtensions
|
8
|
-
|
9
|
-
# Creates delegated methods that forward calls to another object or class.
|
10
|
-
# Supports method name prefixing, privacy levels, and optional method existence checking.
|
11
|
-
#
|
12
|
-
# @param methods [Array<Symbol>] the method names to delegate
|
13
|
-
# @param options [Hash] delegation options
|
14
|
-
# @option options [Symbol] :to the target object or :class to delegate to
|
15
|
-
# @option options [Boolean] :allow_missing (false) whether to allow delegation to non-existent methods
|
16
|
-
# @option options [Boolean] :protected (false) whether to make the delegated method protected
|
17
|
-
# @option options [Boolean] :private (false) whether to make the delegated method private
|
18
|
-
# @option options [String, Symbol] :prefix optional prefix for the delegated method name
|
19
|
-
# @option options [String, Symbol] :suffix optional suffix for the delegated method name
|
20
|
-
#
|
21
|
-
# @return [void]
|
22
|
-
# @raise [NoMethodError] when delegating to a non-existent method and :allow_missing is false
|
23
|
-
#
|
24
|
-
# @example Delegate methods to an instance variable
|
25
|
-
# class Task
|
26
|
-
# def initialize
|
27
|
-
# @logger = Logger.new
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# cmdx_attr_delegator :info, :warn, :error, to: :@logger
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# @example Delegate with prefix and privacy
|
34
|
-
# class Workflow
|
35
|
-
# cmdx_attr_delegator :perform, to: :task, prefix: 'execute_', private: true
|
36
|
-
# end
|
37
|
-
def cmdx_attr_delegator(*methods, **options)
|
38
|
-
methods.each do |method|
|
39
|
-
method_name = Utils::NameAffix.call(method, options.fetch(:to), options)
|
40
|
-
|
41
|
-
define_method(method_name) do |*args, **kwargs, &block|
|
42
|
-
object = (options[:to] == :class ? self.class : send(options[:to]))
|
43
|
-
|
44
|
-
unless options[:allow_missing] || object.respond_to?(method, true)
|
45
|
-
raise NoMethodError,
|
46
|
-
"undefined method `#{method}' for #{options[:to]}"
|
47
|
-
end
|
48
|
-
|
49
|
-
object.send(method, *args, **kwargs, &block)
|
50
|
-
end
|
51
|
-
|
52
|
-
case options
|
53
|
-
in { protected: true } then send(:protected, method_name)
|
54
|
-
in { private: true } then send(:private, method_name)
|
55
|
-
else # Leave public
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Creates a singleton method for accessing inheritable settings with caching and default values.
|
61
|
-
# Settings are inherited from superclass and can have default values via blocks or static values.
|
62
|
-
#
|
63
|
-
# @param method [Symbol] the name of the setting method to create
|
64
|
-
# @param options [Hash] setting options
|
65
|
-
# @option options [Object, Proc] :default the default value or a proc that returns the default value
|
66
|
-
#
|
67
|
-
# @return [void]
|
68
|
-
#
|
69
|
-
# @example Define a setting with a default value
|
70
|
-
# class BaseTask
|
71
|
-
# cmdx_attr_setting :timeout, default: 30
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# BaseTask.timeout #=> 30
|
75
|
-
#
|
76
|
-
# @example Define a setting with a dynamic default
|
77
|
-
# class Task
|
78
|
-
# cmdx_attr_setting :retry_count, default: -> { ENV['RETRY_COUNT']&.to_i || 3 }
|
79
|
-
# end
|
80
|
-
def cmdx_attr_setting(method, **options)
|
81
|
-
define_singleton_method(method) do
|
82
|
-
@cmd_facets ||= {}
|
83
|
-
return @cmd_facets[method] if @cmd_facets.key?(method)
|
84
|
-
|
85
|
-
value = superclass.cmdx_try(method)
|
86
|
-
return @cmd_facets[method] = value.dup unless value.nil?
|
87
|
-
|
88
|
-
default = options[:default]
|
89
|
-
value = default.cmdx_call
|
90
|
-
@cmd_facets[method] = default.is_a?(Proc) ? value : value.dup
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
Module.include(CMDx::CoreExt::ModuleExtensions)
|
data/lib/cmdx/core_ext/object.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
module CoreExt
|
5
|
-
# Extensions for Ruby's Object class that provide flexible method calling and evaluation utilities.
|
6
|
-
# These extensions are automatically included in all objects when CMDx is loaded, providing
|
7
|
-
# safe method invocation, conditional evaluation, and dynamic yielding capabilities.
|
8
|
-
module ObjectExtensions
|
9
|
-
|
10
|
-
alias cmdx_respond_to? respond_to?
|
11
|
-
|
12
|
-
# Safely tries to call a method, evaluate a proc, or access a hash key.
|
13
|
-
# Provides flexible invocation that handles different types of callables gracefully.
|
14
|
-
#
|
15
|
-
# @param key [Symbol, String, Proc, Object] the method name, proc, or hash key to try
|
16
|
-
# @param args [Array] arguments to pass to the method or proc
|
17
|
-
#
|
18
|
-
# @return [Object, nil] the result of the method call, proc evaluation, or hash access; nil if not found
|
19
|
-
#
|
20
|
-
# @example Try calling a method
|
21
|
-
# "hello".cmdx_try(:upcase) #=> "HELLO"
|
22
|
-
# "hello".cmdx_try(:missing) #=> nil
|
23
|
-
#
|
24
|
-
# @example Try evaluating a proc
|
25
|
-
# obj.cmdx_try(-> { self.class.name }) #=> "String"
|
26
|
-
#
|
27
|
-
# @example Try accessing a hash key
|
28
|
-
# {name: "John"}.cmdx_try(:name) #=> "John"
|
29
|
-
def cmdx_try(key, *args, **kwargs, &)
|
30
|
-
if key.is_a?(Proc)
|
31
|
-
return instance_eval(&key) unless is_a?(Module) || key.inspect.include?("(lambda)")
|
32
|
-
|
33
|
-
if key.arity.positive? && args.empty?
|
34
|
-
key.call(self, *args, **kwargs, &)
|
35
|
-
else
|
36
|
-
key.call(*args, **kwargs, &)
|
37
|
-
end
|
38
|
-
elsif respond_to?(key, true)
|
39
|
-
send(key, *args, **kwargs, &)
|
40
|
-
elsif is_a?(Hash)
|
41
|
-
cmdx_fetch(key)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Evaluates conditional options using :if and :unless logic.
|
46
|
-
# Supports both method names and procs for conditional evaluation.
|
47
|
-
#
|
48
|
-
# @param options [Hash] evaluation options
|
49
|
-
# @option options [Symbol, Proc] :if condition that must be truthy
|
50
|
-
# @option options [Symbol, Proc] :unless condition that must be falsy
|
51
|
-
# @option options [Object] :default (true) default value when no conditions are specified
|
52
|
-
#
|
53
|
-
# @return [Boolean] true if conditions are met, false otherwise
|
54
|
-
#
|
55
|
-
# @example Evaluate with if condition
|
56
|
-
# user.cmdx_eval(if: :active?) #=> true if user.active? is truthy
|
57
|
-
#
|
58
|
-
# @example Evaluate with unless condition
|
59
|
-
# user.cmdx_eval(unless: :banned?) #=> true if user.banned? is falsy
|
60
|
-
#
|
61
|
-
# @example Evaluate with both conditions
|
62
|
-
# user.cmdx_eval(if: :active?, unless: :banned?) #=> true if active and not banned
|
63
|
-
def cmdx_eval(options = {})
|
64
|
-
if options[:if] && options[:unless]
|
65
|
-
cmdx_try(options[:if]) && !cmdx_try(options[:unless])
|
66
|
-
elsif options[:if]
|
67
|
-
cmdx_try(options[:if])
|
68
|
-
elsif options[:unless]
|
69
|
-
!cmdx_try(options[:unless])
|
70
|
-
else
|
71
|
-
options.fetch(:default, true)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Yields or returns a value based on its type, with smart method calling.
|
76
|
-
# Handles symbols/strings as method names, procs/hashes via cmdx_try, and returns other values as-is.
|
77
|
-
#
|
78
|
-
# @param key [Symbol, String, Proc, Hash, Object] the value to yield or method to call
|
79
|
-
# @param args [Array] arguments to pass to method calls
|
80
|
-
#
|
81
|
-
# @return [Object] the result of method call, proc evaluation, or the value itself
|
82
|
-
#
|
83
|
-
# @example Yield a method call
|
84
|
-
# "hello".cmdx_yield(:upcase) #=> "HELLO"
|
85
|
-
#
|
86
|
-
# @example Yield a static value
|
87
|
-
# obj.cmdx_yield("static") #=> "static"
|
88
|
-
#
|
89
|
-
# @example Yield a proc
|
90
|
-
# obj.cmdx_yield(-> { Time.now }) #=> 2023-01-01 12:00:00 UTC
|
91
|
-
def cmdx_yield(key, ...)
|
92
|
-
if key.is_a?(Symbol) || key.is_a?(String)
|
93
|
-
return key unless respond_to?(key, true)
|
94
|
-
|
95
|
-
send(key, ...)
|
96
|
-
elsif is_a?(Hash) || key.is_a?(Proc)
|
97
|
-
cmdx_try(key, ...)
|
98
|
-
else
|
99
|
-
key
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Invokes the object if it responds to :call, otherwise returns the object itself.
|
104
|
-
# Useful for handling both callable and non-callable objects uniformly.
|
105
|
-
#
|
106
|
-
# @param args [Array] arguments to pass to the call method
|
107
|
-
#
|
108
|
-
# @return [Object] the result of calling the object, or the object itself if not callable
|
109
|
-
#
|
110
|
-
# @example Invoke a proc
|
111
|
-
# proc { "hello" }.cmdx_call #=> "hello"
|
112
|
-
#
|
113
|
-
# @example Invoke a non-callable object
|
114
|
-
# "hello".cmdx_call #=> "hello"
|
115
|
-
def cmdx_call(...)
|
116
|
-
return self unless respond_to?(:call)
|
117
|
-
|
118
|
-
call(...)
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
Object.include(CMDx::CoreExt::ObjectExtensions)
|
data/lib/cmdx/correlator.rb
DELETED
@@ -1,122 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
# Thread-safe correlation ID management for distributed tracing and request tracking.
|
5
|
-
#
|
6
|
-
# Correlator provides functionality to generate, store, and manage correlation IDs
|
7
|
-
# across thread boundaries for request tracing, logging correlation, and distributed
|
8
|
-
# system monitoring. Correlation IDs are stored in thread-local storage to ensure
|
9
|
-
# thread safety and isolation between concurrent operations.
|
10
|
-
module Correlator
|
11
|
-
|
12
|
-
THREAD_KEY = :cmdx_correlation_id
|
13
|
-
|
14
|
-
module_function
|
15
|
-
|
16
|
-
# Generates a new correlation ID using the best available UUID algorithm.
|
17
|
-
#
|
18
|
-
# Attempts to use UUID v7 (time-ordered) if available in Ruby 3.3+, otherwise
|
19
|
-
# falls back to standard UUID v4. UUID v7 provides better database indexing
|
20
|
-
# performance and natural time-based ordering for correlation tracking.
|
21
|
-
#
|
22
|
-
# @return [String] a new UUID correlation ID
|
23
|
-
#
|
24
|
-
# @example Generate a correlation ID
|
25
|
-
# Correlator.generate #=> "01234567-89ab-7def-0123-456789abcdef"
|
26
|
-
#
|
27
|
-
# @example Using the generated ID for logging
|
28
|
-
# correlation_id = Correlator.generate
|
29
|
-
# logger.info "Request started", correlation_id: correlation_id
|
30
|
-
def generate
|
31
|
-
return SecureRandom.uuid_v7 if SecureRandom.respond_to?(:uuid_v7)
|
32
|
-
|
33
|
-
SecureRandom.uuid
|
34
|
-
end
|
35
|
-
|
36
|
-
# Retrieves the current correlation ID for the active thread.
|
37
|
-
#
|
38
|
-
# Returns the correlation ID that has been set for the current thread's
|
39
|
-
# execution context. Returns nil if no correlation ID has been established
|
40
|
-
# for the current thread.
|
41
|
-
#
|
42
|
-
# @return [String, nil] the current thread's correlation ID, or nil if not set
|
43
|
-
#
|
44
|
-
# @example Get current correlation ID
|
45
|
-
# Correlator.id #=> "01234567-89ab-7def-0123-456789abcdef"
|
46
|
-
def id
|
47
|
-
Thread.current[THREAD_KEY]
|
48
|
-
end
|
49
|
-
|
50
|
-
# Sets the correlation ID for the current thread.
|
51
|
-
#
|
52
|
-
# Establishes a correlation ID in thread-local storage that will be
|
53
|
-
# accessible to all operations within the current thread's execution
|
54
|
-
# context. This ID will persist until explicitly changed or cleared.
|
55
|
-
#
|
56
|
-
# @param value [String, Symbol] the correlation ID to set for this thread
|
57
|
-
#
|
58
|
-
# @return [String, Symbol] the assigned correlation ID value
|
59
|
-
#
|
60
|
-
# @example Set a custom correlation ID
|
61
|
-
# Correlator.id = "custom-trace-123"
|
62
|
-
#
|
63
|
-
# @example Set a generated correlation ID
|
64
|
-
# Correlator.id = Correlator.generate
|
65
|
-
def id=(value)
|
66
|
-
Thread.current[THREAD_KEY] = value
|
67
|
-
end
|
68
|
-
|
69
|
-
# Clears the correlation ID for the current thread.
|
70
|
-
#
|
71
|
-
# Removes the correlation ID from thread-local storage, effectively
|
72
|
-
# resetting the correlation context for the current thread. Useful
|
73
|
-
# for cleanup between request processing or test scenarios.
|
74
|
-
#
|
75
|
-
# @return [nil] always returns nil after clearing
|
76
|
-
#
|
77
|
-
# @example Clear correlation ID
|
78
|
-
# Correlator.clear
|
79
|
-
# Correlator.id #=> nil
|
80
|
-
def clear
|
81
|
-
Thread.current[THREAD_KEY] = nil
|
82
|
-
end
|
83
|
-
|
84
|
-
# Temporarily sets a correlation ID for the duration of a block execution.
|
85
|
-
#
|
86
|
-
# Establishes a correlation ID context for the provided block, automatically
|
87
|
-
# restoring the previous correlation ID when the block completes. This ensures
|
88
|
-
# proper correlation ID isolation for nested operations or temporary contexts.
|
89
|
-
#
|
90
|
-
# @param value [String, Symbol] the temporary correlation ID to use during block execution
|
91
|
-
#
|
92
|
-
# @return [Object] the return value of the executed block
|
93
|
-
#
|
94
|
-
# @raise [TypeError] if the provided value is not a String or Symbol
|
95
|
-
#
|
96
|
-
# @example Use temporary correlation ID
|
97
|
-
# Correlator.use("temp-id-123") do
|
98
|
-
# logger.info "Processing with temporary ID"
|
99
|
-
# perform_operation
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# @example Nested correlation contexts
|
103
|
-
# Correlator.id = "parent-id"
|
104
|
-
# Correlator.use("child-id") do
|
105
|
-
# puts Correlator.id #=> "child-id"
|
106
|
-
# end
|
107
|
-
# puts Correlator.id #=> "parent-id"
|
108
|
-
def use(value)
|
109
|
-
unless value.is_a?(String) || value.is_a?(Symbol)
|
110
|
-
raise TypeError,
|
111
|
-
"must be a String or Symbol"
|
112
|
-
end
|
113
|
-
|
114
|
-
previous_id = id
|
115
|
-
self.id = value
|
116
|
-
yield
|
117
|
-
ensure
|
118
|
-
self.id = previous_id
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
end
|
data/lib/cmdx/error.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CMDx
|
4
|
-
|
5
|
-
# Base exception class for all CMDx-related errors.
|
6
|
-
#
|
7
|
-
# This serves as the root exception class for all errors raised by the CMDx
|
8
|
-
# framework. It inherits from StandardError and provides a common base for
|
9
|
-
# handling CMDx-specific exceptions.
|
10
|
-
Error = Class.new(StandardError)
|
11
|
-
|
12
|
-
# Raised when parameter coercion fails during task execution.
|
13
|
-
#
|
14
|
-
# This error occurs when a parameter value cannot be converted to the expected
|
15
|
-
# type using the registered coercion handlers. It indicates that the provided
|
16
|
-
# value is incompatible with the parameter's defined type.
|
17
|
-
CoercionError = Class.new(Error)
|
18
|
-
|
19
|
-
# Raised when a deprecated task is used.
|
20
|
-
#
|
21
|
-
# This error occurs when a deprecated task is called. It indicates that the
|
22
|
-
# task is no longer supported and should be replaced with a newer alternative.
|
23
|
-
DeprecationError = Class.new(Error)
|
24
|
-
|
25
|
-
# Raised when an abstract method is called without being implemented.
|
26
|
-
#
|
27
|
-
# This error occurs when a subclass fails to implement required abstract methods
|
28
|
-
# such as call methods in validators, callbacks, or middleware. It indicates
|
29
|
-
# incomplete implementation of required functionality.
|
30
|
-
UndefinedCallError = Class.new(Error)
|
31
|
-
|
32
|
-
# Raised when attempting to use an unregistered callback.
|
33
|
-
#
|
34
|
-
# This error occurs when trying to reference a callback that hasn't been
|
35
|
-
# registered in the callback registry. It indicates that the callback name
|
36
|
-
# is not recognized or was misspelled.
|
37
|
-
UnknownCallbackError = Class.new(Error)
|
38
|
-
|
39
|
-
# Raised when attempting to use an unregistered coercion type.
|
40
|
-
#
|
41
|
-
# This error occurs when trying to use a parameter type that doesn't have
|
42
|
-
# a corresponding coercion handler registered. It indicates that the specified
|
43
|
-
# type is not supported by the coercion system.
|
44
|
-
UnknownCoercionError = Class.new(Error)
|
45
|
-
|
46
|
-
# Raised when attempting to use an unregistered validator.
|
47
|
-
#
|
48
|
-
# This error occurs when trying to reference a validator that hasn't been
|
49
|
-
# registered in the validator registry. It indicates that the validator name
|
50
|
-
# is not recognized or was misspelled.
|
51
|
-
UnknownValidatorError = Class.new(Error)
|
52
|
-
|
53
|
-
# Raised when parameter validation fails during task execution.
|
54
|
-
#
|
55
|
-
# This error occurs when a parameter value doesn't meet the validation criteria
|
56
|
-
# defined by the validator. It indicates that the provided value violates
|
57
|
-
# business rules or data integrity constraints.
|
58
|
-
ValidationError = Class.new(Error)
|
59
|
-
|
60
|
-
end
|