cmdx 1.0.1 → 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 +21 -0
- data/.cursor/prompts/yardoc.md +13 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +29 -3
- data/README.md +2 -1
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +126 -60
- 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 +382 -119
- data/docs/configuration.md +211 -49
- 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 +152 -127
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +183 -120
- data/docs/middlewares.md +165 -392
- 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 +251 -289
- 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 +247 -159
- data/docs/testing.md +196 -203
- data/docs/workflows.md +146 -101
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/callback.rb +39 -55
- data/lib/cmdx/callback_registry.rb +80 -73
- data/lib/cmdx/chain.rb +65 -122
- data/lib/cmdx/chain_inspector.rb +23 -116
- data/lib/cmdx/chain_serializer.rb +34 -146
- data/lib/cmdx/coercion.rb +57 -0
- data/lib/cmdx/coercion_registry.rb +113 -0
- data/lib/cmdx/coercions/array.rb +18 -36
- data/lib/cmdx/coercions/big_decimal.rb +21 -33
- data/lib/cmdx/coercions/boolean.rb +21 -40
- data/lib/cmdx/coercions/complex.rb +18 -31
- data/lib/cmdx/coercions/date.rb +20 -39
- data/lib/cmdx/coercions/date_time.rb +22 -39
- data/lib/cmdx/coercions/float.rb +19 -32
- data/lib/cmdx/coercions/hash.rb +22 -41
- data/lib/cmdx/coercions/integer.rb +20 -33
- data/lib/cmdx/coercions/rational.rb +20 -32
- data/lib/cmdx/coercions/string.rb +23 -31
- data/lib/cmdx/coercions/time.rb +24 -40
- data/lib/cmdx/coercions/virtual.rb +14 -31
- data/lib/cmdx/configuration.rb +101 -162
- data/lib/cmdx/context.rb +34 -166
- data/lib/cmdx/core_ext/hash.rb +42 -67
- data/lib/cmdx/core_ext/module.rb +35 -79
- data/lib/cmdx/core_ext/object.rb +63 -98
- data/lib/cmdx/correlator.rb +59 -154
- data/lib/cmdx/error.rb +37 -202
- data/lib/cmdx/errors.rb +153 -216
- data/lib/cmdx/fault.rb +68 -150
- data/lib/cmdx/faults.rb +26 -137
- data/lib/cmdx/immutator.rb +22 -110
- data/lib/cmdx/lazy_struct.rb +110 -186
- data/lib/cmdx/log_formatters/json.rb +14 -40
- data/lib/cmdx/log_formatters/key_value.rb +14 -40
- data/lib/cmdx/log_formatters/line.rb +14 -48
- data/lib/cmdx/log_formatters/logstash.rb +14 -57
- data/lib/cmdx/log_formatters/pretty_json.rb +14 -50
- data/lib/cmdx/log_formatters/pretty_key_value.rb +13 -46
- data/lib/cmdx/log_formatters/pretty_line.rb +16 -54
- data/lib/cmdx/log_formatters/raw.rb +19 -49
- data/lib/cmdx/logger.rb +22 -79
- data/lib/cmdx/logger_ansi.rb +31 -72
- data/lib/cmdx/logger_serializer.rb +74 -103
- data/lib/cmdx/middleware.rb +56 -60
- data/lib/cmdx/middleware_registry.rb +82 -77
- data/lib/cmdx/middlewares/correlate.rb +41 -226
- data/lib/cmdx/middlewares/timeout.rb +46 -185
- data/lib/cmdx/parameter.rb +167 -183
- data/lib/cmdx/parameter_evaluator.rb +231 -0
- data/lib/cmdx/parameter_inspector.rb +37 -55
- data/lib/cmdx/parameter_registry.rb +65 -84
- data/lib/cmdx/parameter_serializer.rb +32 -76
- data/lib/cmdx/railtie.rb +24 -107
- data/lib/cmdx/result.rb +254 -259
- data/lib/cmdx/result_ansi.rb +28 -80
- data/lib/cmdx/result_inspector.rb +34 -70
- data/lib/cmdx/result_logger.rb +23 -77
- data/lib/cmdx/result_serializer.rb +59 -125
- data/lib/cmdx/rspec/matchers.rb +28 -0
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +42 -0
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +94 -0
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +57 -0
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +87 -0
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +51 -0
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +58 -0
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +59 -0
- data/lib/cmdx/rspec/result_matchers/have_context.rb +86 -0
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +54 -0
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +52 -0
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +114 -0
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +66 -0
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +64 -0
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +78 -0
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +76 -0
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +62 -0
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +85 -0
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +68 -0
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +92 -0
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +46 -0
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +181 -0
- data/lib/cmdx/task.rb +336 -427
- data/lib/cmdx/task_deprecator.rb +52 -0
- data/lib/cmdx/task_processor.rb +246 -0
- data/lib/cmdx/task_serializer.rb +34 -69
- data/lib/cmdx/utils/ansi_color.rb +13 -89
- data/lib/cmdx/utils/log_timestamp.rb +13 -42
- data/lib/cmdx/utils/monotonic_runtime.rb +11 -63
- data/lib/cmdx/utils/name_affix.rb +21 -71
- data/lib/cmdx/validator.rb +57 -0
- data/lib/cmdx/validator_registry.rb +108 -0
- data/lib/cmdx/validators/exclusion.rb +55 -94
- data/lib/cmdx/validators/format.rb +31 -85
- data/lib/cmdx/validators/inclusion.rb +65 -110
- data/lib/cmdx/validators/length.rb +117 -133
- data/lib/cmdx/validators/numeric.rb +123 -130
- data/lib/cmdx/validators/presence.rb +38 -79
- data/lib/cmdx/version.rb +1 -7
- data/lib/cmdx/workflow.rb +58 -330
- data/lib/cmdx.rb +1 -1
- data/lib/generators/cmdx/install_generator.rb +14 -31
- data/lib/generators/cmdx/task_generator.rb +39 -55
- data/lib/generators/cmdx/templates/install.rb +24 -6
- data/lib/generators/cmdx/workflow_generator.rb +41 -66
- data/lib/locales/ar.yml +0 -1
- data/lib/locales/cs.yml +0 -1
- data/lib/locales/da.yml +0 -1
- data/lib/locales/de.yml +0 -1
- data/lib/locales/el.yml +0 -1
- data/lib/locales/en.yml +0 -1
- data/lib/locales/es.yml +0 -1
- data/lib/locales/fi.yml +0 -1
- data/lib/locales/fr.yml +0 -1
- data/lib/locales/he.yml +0 -1
- data/lib/locales/hi.yml +0 -1
- data/lib/locales/it.yml +0 -1
- data/lib/locales/ja.yml +0 -1
- data/lib/locales/ko.yml +0 -1
- data/lib/locales/nl.yml +0 -1
- data/lib/locales/no.yml +0 -1
- data/lib/locales/pl.yml +0 -1
- data/lib/locales/pt.yml +0 -1
- data/lib/locales/ru.yml +0 -1
- data/lib/locales/sv.yml +0 -1
- data/lib/locales/th.yml +0 -1
- data/lib/locales/tr.yml +0 -1
- data/lib/locales/vi.yml +0 -1
- data/lib/locales/zh.yml +0 -1
- metadata +36 -8
- data/lib/cmdx/parameter_validator.rb +0 -81
- data/lib/cmdx/parameter_value.rb +0 -244
- data/lib/cmdx/parameters_inspector.rb +0 -72
- data/lib/cmdx/parameters_serializer.rb +0 -115
- data/lib/cmdx/rspec/result_matchers.rb +0 -917
- data/lib/cmdx/rspec/task_matchers.rb +0 -570
- data/lib/cmdx/validators/custom.rb +0 -102
data/lib/cmdx/configuration.rb
CHANGED
@@ -2,119 +2,90 @@
|
|
2
2
|
|
3
3
|
module CMDx
|
4
4
|
|
5
|
-
|
6
|
-
# Provides global configuration management for CMDx framework settings.
|
7
|
-
# The configuration system allows customization of default behaviors for tasks,
|
8
|
-
# workflows, logging, and error handling across the entire application.
|
5
|
+
# Global configuration class for CMDx framework settings.
|
9
6
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
7
|
+
# Manages logging, middleware, callbacks, coercions, validators, and halt conditions
|
8
|
+
# for the entire CMDx framework. The Configuration class provides centralized control
|
9
|
+
# over framework behavior including task execution flow, error handling, and component
|
10
|
+
# registration. All settings configured here become defaults for tasks and workflows
|
11
|
+
# unless explicitly overridden at the task or workflow level.
|
13
12
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# - **logger**: Logger instance for task execution logging
|
17
|
-
# - **task_halt**: Result statuses that cause `call!` to raise faults
|
18
|
-
# - **workflow_halt**: Result statuses that halt workflow execution
|
19
|
-
# - **middlewares**: Global middleware registry applied to all tasks
|
20
|
-
# - **callbacks**: Global callback registry applied to all tasks
|
21
|
-
#
|
22
|
-
# ## Configuration Hierarchy
|
23
|
-
#
|
24
|
-
# CMDx follows a configuration hierarchy where settings can be overridden:
|
25
|
-
# 1. **Global Configuration**: Framework-wide defaults (this module)
|
26
|
-
# 2. **Task Settings**: Class-level overrides via `task_settings!`
|
27
|
-
# 3. **Runtime Parameters**: Instance-specific overrides during execution
|
28
|
-
#
|
29
|
-
# @example Basic configuration setup
|
30
|
-
# CMDx.configure do |config|
|
31
|
-
# config.logger = Logger.new($stdout)
|
32
|
-
# config.task_halt = ["failed"] # Only halt on failures
|
33
|
-
# config.middlewares.use CMDx::Middlewares::Timeout, 30
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# @example Rails initializer configuration
|
37
|
-
# # config/initializers/cmdx.rb
|
38
|
-
# CMDx.configure do |config|
|
39
|
-
# config.logger = Logger.new($stdout)
|
40
|
-
# config.task_halt = CMDx::Result::FAILED
|
41
|
-
# config.workflow_halt = [CMDx::Result::FAILED, CMDx::Result::SKIPPED]
|
42
|
-
#
|
43
|
-
# # Add global middlewares
|
44
|
-
# config.middlewares.use CMDx::Middlewares::Timeout, 30
|
45
|
-
# config.middlewares.use AuthenticationMiddleware if Rails.env.production?
|
46
|
-
#
|
47
|
-
# # Add global callbacks
|
48
|
-
# config.callbacks.register :before_execution, :log_task_start
|
49
|
-
# config.callbacks.register :on_success, NotificationCallback.new([:slack])
|
50
|
-
# config.callbacks.register :on_failure, :alert_admin, if: :production?
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# @example Custom logger configuration
|
54
|
-
# CMDx.configure do |config|
|
55
|
-
# config.logger = Logger.new(
|
56
|
-
# Rails.root.join('log', 'cmdx.log'),
|
57
|
-
# formatter: CMDx::LogFormatters::Json.new
|
58
|
-
# )
|
59
|
-
# end
|
60
|
-
#
|
61
|
-
# @example Environment-specific configuration
|
62
|
-
# CMDx.configure do |config|
|
63
|
-
# case Rails.env
|
64
|
-
# when 'development'
|
65
|
-
# config.logger = Logger.new($stdout, formatter: CMDx::LogFormatters::PrettyLine.new)
|
66
|
-
# when 'test'
|
67
|
-
# config.logger = Logger.new('/dev/null') # Silent logging
|
68
|
-
# when 'production'
|
69
|
-
# config.logger = Logger.new($stdout, formatter: CMDx::LogFormatters::Json.new)
|
70
|
-
# end
|
71
|
-
# end
|
72
|
-
#
|
73
|
-
# @see Task Task-level configuration overrides
|
74
|
-
# @see Workflow Workflow-level configuration overrides
|
75
|
-
# @see LogFormatters Available logging formatters
|
76
|
-
# @see Result Result statuses for halt configuration
|
77
|
-
# @since 1.0.0
|
78
|
-
|
79
|
-
##
|
80
|
-
# Configuration class that manages CMDx framework settings.
|
81
|
-
# Provides explicit attribute accessors for all configuration options.
|
82
|
-
#
|
83
|
-
# @since 1.0.0
|
13
|
+
# The configuration system supports both global and per-task customization, allowing
|
14
|
+
# fine-grained control over framework behavior while maintaining sensible defaults.
|
84
15
|
class Configuration
|
85
16
|
|
86
|
-
# Default configuration values
|
87
17
|
DEFAULT_HALT = "failed"
|
88
18
|
|
89
|
-
#
|
90
|
-
attr_accessor :logger
|
19
|
+
# @return [Logger] Logger instance for task execution logging
|
20
|
+
attr_accessor :logger
|
21
|
+
|
22
|
+
# @return [MiddlewareRegistry] Global middleware registry applied to all tasks
|
23
|
+
attr_accessor :middlewares
|
24
|
+
|
25
|
+
# @return [CallbackRegistry] Global callback registry applied to all tasks
|
26
|
+
attr_accessor :callbacks
|
91
27
|
|
92
|
-
|
93
|
-
|
28
|
+
# @return [CoercionRegistry] Global coercion registry for custom parameter types
|
29
|
+
attr_accessor :coercions
|
30
|
+
|
31
|
+
# @return [ValidatorRegistry] Global validator registry for custom parameter validation
|
32
|
+
attr_accessor :validators
|
33
|
+
|
34
|
+
# @return [String, Array<String>] Result statuses that cause `call!` to raise faults
|
35
|
+
attr_accessor :task_halt
|
36
|
+
|
37
|
+
# @return [String, Array<String>] Result statuses that halt workflow execution
|
38
|
+
attr_accessor :workflow_halt
|
39
|
+
|
40
|
+
# Creates a new configuration instance with default settings.
|
41
|
+
#
|
42
|
+
# Initializes all configuration attributes with sensible defaults including
|
43
|
+
# a stdout logger with line formatting, empty registries for extensibility
|
44
|
+
# components, and default halt conditions for both tasks and workflows.
|
94
45
|
#
|
95
|
-
# @
|
96
|
-
#
|
46
|
+
# @return [Configuration] a new configuration instance with default settings
|
47
|
+
#
|
48
|
+
# @example Create a new configuration
|
49
|
+
# config = Configuration.new
|
50
|
+
# config.logger.class #=> Logger
|
51
|
+
# config.task_halt #=> "failed"
|
97
52
|
def initialize
|
98
|
-
@logger
|
99
|
-
@middlewares
|
100
|
-
@callbacks
|
101
|
-
@
|
53
|
+
@logger = ::Logger.new($stdout, formatter: CMDx::LogFormatters::Line.new)
|
54
|
+
@middlewares = MiddlewareRegistry.new
|
55
|
+
@callbacks = CallbackRegistry.new
|
56
|
+
@coercions = CoercionRegistry.new
|
57
|
+
@validators = ValidatorRegistry.new
|
58
|
+
@task_halt = DEFAULT_HALT
|
102
59
|
@workflow_halt = DEFAULT_HALT
|
103
60
|
end
|
104
61
|
|
105
|
-
|
106
|
-
#
|
107
|
-
#
|
62
|
+
# Converts the configuration to a hash representation.
|
63
|
+
#
|
64
|
+
# Creates a hash containing all configuration attributes for serialization,
|
65
|
+
# inspection, or transfer between processes. The hash includes all registries
|
66
|
+
# and settings in their current state.
|
67
|
+
#
|
68
|
+
# @return [Hash] hash representation of the configuration
|
69
|
+
# @option return [Logger] :logger the configured logger instance
|
70
|
+
# @option return [MiddlewareRegistry] :middlewares the middleware registry
|
71
|
+
# @option return [CallbackRegistry] :callbacks the callback registry
|
72
|
+
# @option return [CoercionRegistry] :coercions the coercion registry
|
73
|
+
# @option return [ValidatorRegistry] :validators the validator registry
|
74
|
+
# @option return [String, Array<String>] :task_halt the task halt configuration
|
75
|
+
# @option return [String, Array<String>] :workflow_halt the workflow halt configuration
|
108
76
|
#
|
109
|
-
# @
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
77
|
+
# @example Convert configuration to hash
|
78
|
+
# config = Configuration.new
|
79
|
+
# hash = config.to_h
|
80
|
+
# hash[:logger].class #=> Logger
|
81
|
+
# hash[:task_halt] #=> "failed"
|
113
82
|
def to_h
|
114
83
|
{
|
115
84
|
logger: @logger,
|
116
85
|
middlewares: @middlewares,
|
117
86
|
callbacks: @callbacks,
|
87
|
+
coercions: @coercions,
|
88
|
+
validators: @validators,
|
118
89
|
task_halt: @task_halt,
|
119
90
|
workflow_halt: @workflow_halt
|
120
91
|
}
|
@@ -124,71 +95,48 @@ module CMDx
|
|
124
95
|
|
125
96
|
module_function
|
126
97
|
|
127
|
-
##
|
128
98
|
# Returns the current global configuration instance.
|
129
|
-
# Creates a new configuration with default values if none exists.
|
130
99
|
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
100
|
+
# Provides access to the singleton configuration instance used by the entire
|
101
|
+
# CMDx framework. Creates a new configuration with default settings if none
|
102
|
+
# exists. This method is thread-safe and ensures only one configuration
|
103
|
+
# instance exists per process.
|
134
104
|
#
|
135
|
-
# @return [Configuration] the current configuration
|
105
|
+
# @return [Configuration] the current global configuration instance
|
136
106
|
#
|
137
|
-
# @example
|
138
|
-
# CMDx.configuration.logger #=> <Logger instance>
|
139
|
-
# CMDx.configuration.task_halt #=> "failed"
|
140
|
-
#
|
141
|
-
# @example Checking configuration state
|
107
|
+
# @example Access global configuration
|
142
108
|
# config = CMDx.configuration
|
143
|
-
# config.logger.
|
109
|
+
# config.logger.level = Logger::DEBUG
|
110
|
+
# config.task_halt = ["failed", "skipped"]
|
144
111
|
def configuration
|
145
112
|
return @configuration if @configuration
|
146
113
|
|
147
114
|
@configuration ||= Configuration.new
|
148
115
|
end
|
149
116
|
|
150
|
-
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
117
|
+
# Configures the global CMDx settings using a block.
|
118
|
+
#
|
119
|
+
# Yields the current configuration instance to the provided block for
|
120
|
+
# modification. This is the recommended way to configure CMDx as it
|
121
|
+
# provides a clean DSL-like interface for setting up the framework.
|
154
122
|
#
|
155
|
-
#
|
156
|
-
#
|
123
|
+
# @param block [Proc] configuration block that receives the configuration instance
|
124
|
+
#
|
125
|
+
# @return [Configuration] the configured configuration instance
|
157
126
|
#
|
158
|
-
# @yieldparam config [Configuration] the configuration object to modify
|
159
|
-
# @return [Configuration] the updated configuration object
|
160
127
|
# @raise [ArgumentError] if no block is provided
|
161
128
|
#
|
162
|
-
# @example
|
129
|
+
# @example Configure CMDx settings
|
163
130
|
# CMDx.configure do |config|
|
131
|
+
# config.logger.level = Logger::INFO
|
164
132
|
# config.task_halt = ["failed", "skipped"]
|
133
|
+
# config.middlewares.register(CMDx::Middlewares::Timeout.new(seconds: 30))
|
165
134
|
# end
|
166
135
|
#
|
167
|
-
# @example
|
168
|
-
# CMDx.configure do |config|
|
169
|
-
# config.logger = Rails.logger if defined?(Rails)
|
170
|
-
#
|
171
|
-
# config.task_halt = if Rails.env.production?
|
172
|
-
# "failed" # Only halt on failures in production
|
173
|
-
# else
|
174
|
-
# ["failed", "skipped"] # Halt on both in development
|
175
|
-
# end
|
176
|
-
#
|
177
|
-
|
178
|
-
# end
|
179
|
-
#
|
180
|
-
# @example Formatter configuration
|
136
|
+
# @example Configure with custom logger
|
181
137
|
# CMDx.configure do |config|
|
182
|
-
# config.logger =
|
183
|
-
#
|
184
|
-
# when 'json'
|
185
|
-
# CMDx::LogFormatters::Json.new
|
186
|
-
# when 'pretty'
|
187
|
-
# CMDx::LogFormatters::PrettyLine.new
|
188
|
-
# else
|
189
|
-
# CMDx::LogFormatters::Line.new
|
190
|
-
# end
|
191
|
-
# end
|
138
|
+
# config.logger = Rails.logger
|
139
|
+
# config.logger.formatter = CMDx::LogFormatters::JSON.new
|
192
140
|
# end
|
193
141
|
def configure
|
194
142
|
raise ArgumentError, "block required" unless block_given?
|
@@ -198,34 +146,25 @@ module CMDx
|
|
198
146
|
config
|
199
147
|
end
|
200
148
|
|
201
|
-
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
149
|
+
# Resets the global configuration to default settings.
|
150
|
+
#
|
151
|
+
# Creates a new configuration instance with default settings, discarding
|
152
|
+
# any existing configuration. This is useful for testing scenarios or
|
153
|
+
# when you need to start with a clean configuration state.
|
205
154
|
#
|
206
|
-
# @return [Configuration]
|
155
|
+
# @return [Configuration] a new configuration instance with default settings
|
207
156
|
#
|
208
|
-
# @example
|
209
|
-
#
|
210
|
-
# CMDx.
|
211
|
-
# CMDx.configuration.task_halt #=> ["failed"]
|
157
|
+
# @example Reset to defaults
|
158
|
+
# CMDx.configure { |c| c.task_halt = ["failed", "skipped"] }
|
159
|
+
# CMDx.configuration.task_halt #=> ["failed", "skipped"]
|
212
160
|
#
|
213
|
-
# # Reset to defaults
|
214
161
|
# CMDx.reset_configuration!
|
215
|
-
# CMDx.configuration.task_halt
|
162
|
+
# CMDx.configuration.task_halt #=> "failed"
|
216
163
|
#
|
217
|
-
# @example
|
218
|
-
#
|
219
|
-
#
|
220
|
-
# CMDx.reset_configuration! # Start with clean defaults
|
164
|
+
# @example Use in test setup
|
165
|
+
# RSpec.configure do |config|
|
166
|
+
# config.before(:each) { CMDx.reset_configuration! }
|
221
167
|
# end
|
222
|
-
#
|
223
|
-
# @example Conditional reset
|
224
|
-
# # Reset configuration in development for experimentation
|
225
|
-
# CMDx.reset_configuration! if Rails.env.development?
|
226
|
-
#
|
227
|
-
# @note This method is primarily useful for testing or when you need
|
228
|
-
# to return to a known default state.
|
229
168
|
def reset_configuration!
|
230
169
|
@configuration = Configuration.new
|
231
170
|
end
|
data/lib/cmdx/context.rb
CHANGED
@@ -1,181 +1,49 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module CMDx
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# the task execution lifecycle.
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# ## Usage Patterns
|
16
|
-
#
|
17
|
-
# Context is typically used in three main scenarios:
|
18
|
-
# 1. **Parameter Input**: Passing initial data to tasks
|
19
|
-
# 2. **Data Storage**: Storing intermediate results during task execution
|
20
|
-
# 3. **Task Communication**: Sharing data between multiple tasks
|
21
|
-
#
|
22
|
-
# @example Basic parameter input
|
23
|
-
# class ProcessOrderTask < CMDx::Task
|
24
|
-
# required :order_id, type: :integer
|
25
|
-
# optional :notify_customer, type: :boolean, default: true
|
26
|
-
#
|
27
|
-
# def call
|
28
|
-
# context.order = Order.find(order_id)
|
29
|
-
# context.processed_at = Time.now
|
30
|
-
#
|
31
|
-
# if notify_customer
|
32
|
-
# context.notification_sent = send_notification
|
33
|
-
# end
|
34
|
-
# end
|
35
|
-
# end
|
36
|
-
#
|
37
|
-
# result = ProcessOrderTask.call(order_id: 123, notify_customer: false)
|
38
|
-
# result.context.order #=> <Order id: 123>
|
39
|
-
# result.context.processed_at #=> 2023-01-01 12:00:00 UTC
|
40
|
-
# result.context.notification_sent #=> nil
|
41
|
-
#
|
42
|
-
# @example Dynamic attribute assignment
|
43
|
-
# class DataProcessingTask < CMDx::Task
|
44
|
-
# required :input_data, type: :hash
|
45
|
-
#
|
46
|
-
# def call
|
47
|
-
# # Method-style assignment
|
48
|
-
# context.processed_data = transform(input_data)
|
49
|
-
# context.validation_errors = validate(context.processed_data)
|
50
|
-
#
|
51
|
-
# # Hash-style assignment
|
52
|
-
# context[:metadata] = { processed_at: Time.now }
|
53
|
-
# context["summary"] = generate_summary
|
54
|
-
#
|
55
|
-
# # Workflow assignment
|
56
|
-
# context.merge!(
|
57
|
-
# status: "complete",
|
58
|
-
# record_count: context.processed_data.size
|
59
|
-
# )
|
60
|
-
# end
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# @example Inter-task communication
|
64
|
-
# class OrderProcessingWorkflow < CMDx::Workflow
|
65
|
-
# def call
|
66
|
-
# # First task sets up context
|
67
|
-
# ValidateOrderTask.call(context)
|
68
|
-
#
|
69
|
-
# # Subsequent tasks use and modify context
|
70
|
-
# ProcessPaymentTask.call(context)
|
71
|
-
# UpdateInventoryTask.call(context)
|
72
|
-
# SendConfirmationTask.call(context)
|
73
|
-
# end
|
74
|
-
# end
|
75
|
-
#
|
76
|
-
# # Initial context with order data
|
77
|
-
# result = OrderProcessingWorkflow.call(
|
78
|
-
# order_id: 123,
|
79
|
-
# payment_method: "credit_card",
|
80
|
-
# customer_email: "customer@example.com"
|
81
|
-
# )
|
82
|
-
#
|
83
|
-
# # Context accumulates data from all tasks
|
84
|
-
# result.context.order #=> <Order> (from ValidateOrderTask)
|
85
|
-
# result.context.payment_result #=> <Payment> (from ProcessPaymentTask)
|
86
|
-
# result.context.inventory_updated #=> true (from UpdateInventoryTask)
|
87
|
-
# result.context.confirmation_sent #=> true (from SendConfirmationTask)
|
88
|
-
#
|
89
|
-
# @example Context passing between tasks
|
90
|
-
# class ProcessOrderTask < CMDx::Task
|
91
|
-
# required :order_id, type: :integer
|
92
|
-
#
|
93
|
-
# def call
|
94
|
-
# context.order = Order.find(order_id)
|
95
|
-
#
|
96
|
-
# # Pass context to subtasks
|
97
|
-
# payment_result = ProcessPaymentTask.call(context)
|
98
|
-
# email_result = SendEmailTask.call(context)
|
99
|
-
#
|
100
|
-
# # Results maintain context continuity
|
101
|
-
# context.payment_processed = payment_result.success?
|
102
|
-
# context.email_sent = email_result.success?
|
103
|
-
# end
|
104
|
-
# end
|
105
|
-
#
|
106
|
-
# # After execution, context contains accumulated data
|
107
|
-
# result = ProcessOrderTask.call(order_id: 123)
|
108
|
-
# result.context.order #=> <Order>
|
109
|
-
# result.context.payment_processed #=> true
|
110
|
-
# result.context.email_sent #=> true
|
111
|
-
#
|
112
|
-
# @example Context with nested data structures
|
113
|
-
# class AnalyticsTask < CMDx::Task
|
114
|
-
# required :user_id, type: :integer
|
115
|
-
#
|
116
|
-
# def call
|
117
|
-
# context.user = User.find(user_id)
|
118
|
-
# context.analytics = {
|
119
|
-
# page_views: calculate_page_views,
|
120
|
-
# session_duration: calculate_session_duration,
|
121
|
-
# conversion_rate: calculate_conversion_rate
|
122
|
-
# }
|
123
|
-
#
|
124
|
-
# # Access nested data
|
125
|
-
# context.dig(:analytics, :page_views) #=> 150
|
126
|
-
#
|
127
|
-
# # Add more nested data
|
128
|
-
# context.analytics[:last_login] = context.user.last_login
|
129
|
-
# end
|
130
|
-
# end
|
131
|
-
#
|
132
|
-
# @see LazyStruct Base class providing dynamic attribute functionality
|
133
|
-
# @see Task Task base class that uses Context for parameter storage
|
134
|
-
# @see Chain Chain execution context that Context belongs to
|
135
|
-
# @see Parameter Parameter definitions that populate Context
|
136
|
-
# @since 1.0.0
|
4
|
+
# Execution context container for task parameter storage and access.
|
5
|
+
#
|
6
|
+
# Context provides normalized parameter storage for task execution, inheriting
|
7
|
+
# from LazyStruct to provide flexible attribute access patterns. It serves as
|
8
|
+
# the primary interface for storing and retrieving execution parameters, allowing
|
9
|
+
# both hash-style and method-style attribute access with automatic key normalization.
|
10
|
+
# Context instances are used throughout task execution to maintain parameter state
|
11
|
+
# and provide consistent data access across the task lifecycle.
|
137
12
|
class Context < LazyStruct
|
138
13
|
|
139
|
-
|
140
|
-
# Builds a Context instance from the given input, with intelligent handling
|
141
|
-
# of existing Context objects to avoid unnecessary object creation.
|
14
|
+
# Creates or returns a Context instance from the provided input.
|
142
15
|
#
|
143
|
-
# This factory method
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
16
|
+
# This factory method normalizes various input types into a proper Context instance,
|
17
|
+
# ensuring consistent context handling throughout the framework. If the input is
|
18
|
+
# already a Context instance and not frozen, it returns the input unchanged to
|
19
|
+
# avoid unnecessary object creation. Otherwise, it creates a new Context instance
|
20
|
+
# with the provided data.
|
147
21
|
#
|
148
|
-
# @param context [Hash, Context,
|
149
|
-
# @
|
22
|
+
# @param context [Hash, Context, Object] input data to convert to Context
|
23
|
+
# @option context [Object] any any attribute keys and values for context initialization
|
150
24
|
#
|
151
|
-
# @
|
152
|
-
# context = Context.build(name: "John", age: 30)
|
153
|
-
# context.name #=> "John"
|
154
|
-
# context.age #=> 30
|
25
|
+
# @return [Context] a Context instance containing the provided data
|
155
26
|
#
|
156
|
-
# @example
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
27
|
+
# @example Create context from hash
|
28
|
+
# context = Context.build(user_id: 123, action: "process")
|
29
|
+
# context.user_id #=> 123
|
30
|
+
# context.action #=> "process"
|
160
31
|
#
|
161
|
-
# @example
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
# original.object_id == new_context.object_id #=> false
|
32
|
+
# @example Return existing unfrozen context
|
33
|
+
# existing = Context.new(status: "active")
|
34
|
+
# result = Context.build(existing)
|
35
|
+
# result.equal?(existing) #=> true
|
166
36
|
#
|
167
|
-
# @example
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
37
|
+
# @example Create new context from frozen context
|
38
|
+
# frozen_context = Context.new(data: "test").freeze
|
39
|
+
# new_context = Context.build(frozen_context)
|
40
|
+
# new_context.equal?(frozen_context) #=> false
|
41
|
+
# new_context.data #=> "test"
|
172
42
|
#
|
173
|
-
# @example
|
174
|
-
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
# # context = Context.build(order_id: 123, priority: "high")
|
178
|
-
# # ProcessOrderTask.new(context).call
|
43
|
+
# @example Create context from empty input
|
44
|
+
# context = Context.build
|
45
|
+
# context.class #=> CMDx::Context
|
46
|
+
# context.to_h #=> {}
|
179
47
|
def self.build(context = {})
|
180
48
|
return context if context.is_a?(self) && !context.frozen?
|
181
49
|
|