cmdx 1.16.0 → 1.18.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/CHANGELOG.md +23 -1
- data/README.md +3 -0
- data/lib/cmdx/attribute.rb +12 -0
- data/lib/cmdx/attribute_value.rb +22 -14
- data/lib/cmdx/chain.rb +20 -9
- data/lib/cmdx/coercions/array.rb +6 -3
- data/lib/cmdx/coercions/hash.rb +6 -2
- data/lib/cmdx/executor.rb +23 -0
- data/lib/cmdx/middlewares/correlate.rb +23 -12
- data/lib/cmdx/task.rb +45 -6
- data/lib/cmdx/version.rb +1 -1
- data/lib/locales/af.yml +3 -1
- data/lib/locales/ar.yml +3 -1
- data/lib/locales/az.yml +3 -1
- data/lib/locales/be.yml +3 -1
- data/lib/locales/bg.yml +3 -1
- data/lib/locales/bn.yml +3 -1
- data/lib/locales/bs.yml +3 -1
- data/lib/locales/ca.yml +3 -1
- data/lib/locales/cnr.yml +3 -1
- data/lib/locales/cs.yml +3 -1
- data/lib/locales/cy.yml +3 -1
- data/lib/locales/da.yml +3 -1
- data/lib/locales/de.yml +3 -1
- data/lib/locales/dz.yml +3 -1
- data/lib/locales/el.yml +3 -1
- data/lib/locales/en.yml +3 -1
- data/lib/locales/eo.yml +3 -1
- data/lib/locales/es.yml +3 -1
- data/lib/locales/et.yml +3 -1
- data/lib/locales/eu.yml +3 -1
- data/lib/locales/fa.yml +3 -1
- data/lib/locales/fi.yml +3 -1
- data/lib/locales/fr.yml +3 -1
- data/lib/locales/fy.yml +3 -1
- data/lib/locales/gd.yml +3 -1
- data/lib/locales/gl.yml +3 -1
- data/lib/locales/he.yml +3 -1
- data/lib/locales/hi.yml +3 -1
- data/lib/locales/hr.yml +3 -1
- data/lib/locales/hu.yml +3 -1
- data/lib/locales/hy.yml +3 -1
- data/lib/locales/id.yml +3 -1
- data/lib/locales/is.yml +3 -1
- data/lib/locales/it.yml +3 -1
- data/lib/locales/ja.yml +3 -1
- data/lib/locales/ka.yml +3 -1
- data/lib/locales/kk.yml +3 -1
- data/lib/locales/km.yml +3 -1
- data/lib/locales/kn.yml +3 -1
- data/lib/locales/ko.yml +3 -1
- data/lib/locales/lb.yml +3 -1
- data/lib/locales/lo.yml +3 -1
- data/lib/locales/lt.yml +3 -1
- data/lib/locales/lv.yml +3 -1
- data/lib/locales/mg.yml +3 -1
- data/lib/locales/mk.yml +3 -1
- data/lib/locales/ml.yml +3 -1
- data/lib/locales/mn.yml +3 -1
- data/lib/locales/mr-IN.yml +3 -1
- data/lib/locales/ms.yml +3 -1
- data/lib/locales/nb.yml +3 -1
- data/lib/locales/ne.yml +3 -1
- data/lib/locales/nl.yml +3 -1
- data/lib/locales/nn.yml +3 -1
- data/lib/locales/oc.yml +3 -1
- data/lib/locales/or.yml +3 -1
- data/lib/locales/pa.yml +3 -1
- data/lib/locales/pl.yml +3 -1
- data/lib/locales/pt.yml +3 -1
- data/lib/locales/rm.yml +3 -1
- data/lib/locales/ro.yml +3 -1
- data/lib/locales/ru.yml +3 -1
- data/lib/locales/sc.yml +3 -1
- data/lib/locales/sk.yml +3 -1
- data/lib/locales/sl.yml +3 -1
- data/lib/locales/sq.yml +3 -1
- data/lib/locales/sr.yml +3 -1
- data/lib/locales/st.yml +3 -1
- data/lib/locales/sv.yml +3 -1
- data/lib/locales/sw.yml +3 -1
- data/lib/locales/ta.yml +3 -1
- data/lib/locales/te.yml +3 -1
- data/lib/locales/th.yml +3 -1
- data/lib/locales/tl.yml +3 -1
- data/lib/locales/tr.yml +3 -1
- data/lib/locales/tt.yml +3 -1
- data/lib/locales/ug.yml +3 -1
- data/lib/locales/uk.yml +3 -1
- data/lib/locales/ur.yml +3 -1
- data/lib/locales/uz.yml +3 -1
- data/lib/locales/vi.yml +3 -1
- data/lib/locales/wo.yml +3 -1
- data/lib/locales/zh-CN.yml +3 -1
- data/lib/locales/zh-HK.yml +3 -1
- data/lib/locales/zh-TW.yml +3 -1
- data/lib/locales/zh-YUE.yml +3 -1
- data/mkdocs.yml +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 80c55fa1f758dc69cebff57fa5dd770b4bd7692f4a37768c320b6813d28cc9fb
|
|
4
|
+
data.tar.gz: babf14b98faa436de370d039cc2b6c796f2d0c43d9e408137ccdd1f666f4abe3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cbcb58370126bc18aec53218930b11a7c6a3194b4b1e1c6247ae2d6e693ef16f84cc4dbf90a7dbd816e900f421e625cac3ca227aca7ce4898fa711c1451230e0
|
|
7
|
+
data.tar.gz: de88ce41eacbf4f843803f84055d46dcfb7774aa5532396c820112a5ca3d80d68deb9dbc296f8b782d990122ed6ccc082bbc582f93d3714373c2705c55a936fe
|
data/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,29 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [UNRELEASED]
|
|
8
|
+
|
|
9
|
+
## [1.18.0] - 2025-03-09
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Use `Fiber.storage` instead of `Thread.current` for `Chain` and `Correlate` storage, with fallback to `Thread.current` for Ruby < 3.2, making them thread and fiber safe
|
|
13
|
+
- Clone shared logger in `Task#logger` when `log_level` or `log_formatter` is customized to prevent mutation of the shared instance
|
|
14
|
+
- Derive attribute values from source objects that respond to the attribute name (via `send`) as fallback when the source is not callable
|
|
15
|
+
|
|
16
|
+
## [1.17.0] - 2025-02-23
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Add `returns` macro for context output validation after task execution
|
|
20
|
+
- Add `remove_return`/`remove_returns` macro to remove declared returns (supports inheritance)
|
|
21
|
+
- Add array coercion for JSON `"null"` string as empty array
|
|
22
|
+
- Add hash coercion for JSON `"null"` string as empty hash
|
|
23
|
+
- Add attribute sourcing to support both string and symbol keys when sourcing/deriving from Hash
|
|
24
|
+
|
|
25
|
+
## Changed
|
|
26
|
+
- Do not fail coercion if nil on optional attributes
|
|
27
|
+
- Include the source method in the required attribute error message
|
|
28
|
+
|
|
29
|
+
## [1.16.0] - 2025-02-06
|
|
8
30
|
|
|
9
31
|
### Added
|
|
10
32
|
- Add `CMDx::Exception` alias for `CMDx::Error`
|
data/README.md
CHANGED
|
@@ -59,8 +59,11 @@ class AnalyzeMetrics < CMDx::Task
|
|
|
59
59
|
on_success :track_analysis_completion!
|
|
60
60
|
|
|
61
61
|
required :dataset_id, type: :integer, numeric: { min: 1 }
|
|
62
|
+
|
|
62
63
|
optional :analysis_type, default: "standard"
|
|
63
64
|
|
|
65
|
+
returns :result, :analyzed_at
|
|
66
|
+
|
|
64
67
|
def work
|
|
65
68
|
if dataset.nil?
|
|
66
69
|
fail!("Dataset not found", code: 404)
|
data/lib/cmdx/attribute.rb
CHANGED
|
@@ -184,6 +184,18 @@ module CMDx
|
|
|
184
184
|
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
+
# Checks if the attribute is optional.
|
|
188
|
+
#
|
|
189
|
+
# @return [Boolean] true if the attribute is optional, false otherwise
|
|
190
|
+
#
|
|
191
|
+
# @example
|
|
192
|
+
# attribute.optional? # => true
|
|
193
|
+
#
|
|
194
|
+
# @rbs () -> bool
|
|
195
|
+
def optional?
|
|
196
|
+
!required? || !!options[:optional]
|
|
197
|
+
end
|
|
198
|
+
|
|
187
199
|
# Checks if the attribute is required.
|
|
188
200
|
#
|
|
189
201
|
# @return [Boolean] true if the attribute is required, false otherwise
|
data/lib/cmdx/attribute_value.rb
CHANGED
|
@@ -18,7 +18,7 @@ module CMDx
|
|
|
18
18
|
# @rbs @attribute: Attribute
|
|
19
19
|
attr_reader :attribute
|
|
20
20
|
|
|
21
|
-
def_delegators :attribute, :task, :parent, :name, :options, :types, :source, :method_name, :required?
|
|
21
|
+
def_delegators :attribute, :task, :parent, :name, :options, :types, :source, :method_name, :required?, :optional?
|
|
22
22
|
def_delegators :task, :attributes, :errors
|
|
23
23
|
|
|
24
24
|
# Creates a new attribute value manager for the given attribute.
|
|
@@ -113,10 +113,11 @@ module CMDx
|
|
|
113
113
|
|
|
114
114
|
if required? && (parent.nil? || parent&.required?) && Utils::Condition.evaluate(task, options)
|
|
115
115
|
case sourced_value
|
|
116
|
-
when Context
|
|
116
|
+
when Context then sourced_value.key?(name)
|
|
117
|
+
when Hash then sourced_value.key?(name.to_s) || sourced_value.key?(name.to_sym)
|
|
117
118
|
when Proc then true # HACK: Cannot be determined so assume it will respond
|
|
118
119
|
else sourced_value.respond_to?(name, true)
|
|
119
|
-
end || errors.add(method_name, Locale.t("cmdx.attributes.required"))
|
|
120
|
+
end || errors.add(method_name, Locale.t("cmdx.attributes.required", method: source))
|
|
120
121
|
end
|
|
121
122
|
|
|
122
123
|
sourced_value
|
|
@@ -164,10 +165,16 @@ module CMDx
|
|
|
164
165
|
def derive_value(source_value)
|
|
165
166
|
derived_value =
|
|
166
167
|
case source_value
|
|
167
|
-
when Context
|
|
168
|
+
when Context then source_value[name]
|
|
169
|
+
when Hash then source_value[name.to_s] || source_value[name.to_sym]
|
|
168
170
|
when Symbol then source_value.send(name)
|
|
169
171
|
when Proc then task.instance_exec(name, &source_value)
|
|
170
|
-
else
|
|
172
|
+
else
|
|
173
|
+
if source_value.respond_to?(:call)
|
|
174
|
+
source_value.call(task, name)
|
|
175
|
+
elsif source_value.respond_to?(name, true)
|
|
176
|
+
source_value.send(name)
|
|
177
|
+
end
|
|
171
178
|
end
|
|
172
179
|
|
|
173
180
|
derived_value.nil? ? default_value : derived_value
|
|
@@ -222,16 +229,17 @@ module CMDx
|
|
|
222
229
|
rescue CoercionError => e
|
|
223
230
|
next if i != last_idx
|
|
224
231
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
+
unless optional? && transformed_value.nil?
|
|
233
|
+
message =
|
|
234
|
+
if last_idx.zero?
|
|
235
|
+
e.message
|
|
236
|
+
else
|
|
237
|
+
tl = types.map { |t| Locale.t("cmdx.types.#{t}") }.join(", ")
|
|
238
|
+
Locale.t("cmdx.coercions.into_any", types: tl)
|
|
239
|
+
end
|
|
232
240
|
|
|
233
|
-
|
|
234
|
-
|
|
241
|
+
errors.add(method_name, message)
|
|
242
|
+
end
|
|
235
243
|
end
|
|
236
244
|
end
|
|
237
245
|
|
data/lib/cmdx/chain.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CMDx
|
|
4
|
-
# Manages a collection of task execution results in a thread
|
|
4
|
+
# Manages a collection of task execution results in a thread and fiber safe manner.
|
|
5
5
|
# Chains provide a way to track related task executions and their outcomes
|
|
6
6
|
# within the same execution context.
|
|
7
7
|
class Chain
|
|
8
8
|
|
|
9
9
|
extend Forwardable
|
|
10
10
|
|
|
11
|
-
# @rbs
|
|
12
|
-
|
|
11
|
+
# @rbs CONCURRENCY_KEY: Symbol
|
|
12
|
+
CONCURRENCY_KEY = :cmdx_chain
|
|
13
13
|
|
|
14
14
|
# Returns the unique identifier for this chain.
|
|
15
15
|
#
|
|
@@ -47,7 +47,7 @@ module CMDx
|
|
|
47
47
|
|
|
48
48
|
class << self
|
|
49
49
|
|
|
50
|
-
# Retrieves the current chain for the current
|
|
50
|
+
# Retrieves the current chain for the current execution context.
|
|
51
51
|
#
|
|
52
52
|
# @return [Chain, nil] The current chain or nil if none exists
|
|
53
53
|
#
|
|
@@ -59,10 +59,10 @@ module CMDx
|
|
|
59
59
|
#
|
|
60
60
|
# @rbs () -> Chain?
|
|
61
61
|
def current
|
|
62
|
-
|
|
62
|
+
thread_or_fiber[CONCURRENCY_KEY]
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
# Sets the current chain for the current
|
|
65
|
+
# Sets the current chain for the current execution context.
|
|
66
66
|
#
|
|
67
67
|
# @param chain [Chain] The chain to set as current
|
|
68
68
|
#
|
|
@@ -73,10 +73,10 @@ module CMDx
|
|
|
73
73
|
#
|
|
74
74
|
# @rbs (Chain chain) -> Chain
|
|
75
75
|
def current=(chain)
|
|
76
|
-
|
|
76
|
+
thread_or_fiber[CONCURRENCY_KEY] = chain
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
# Clears the current chain for the current
|
|
79
|
+
# Clears the current chain for the current execution context.
|
|
80
80
|
#
|
|
81
81
|
# @return [nil] Always returns nil
|
|
82
82
|
#
|
|
@@ -85,7 +85,7 @@ module CMDx
|
|
|
85
85
|
#
|
|
86
86
|
# @rbs () -> nil
|
|
87
87
|
def clear
|
|
88
|
-
|
|
88
|
+
thread_or_fiber[CONCURRENCY_KEY] = nil
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
# Builds or extends the current chain by adding a result.
|
|
@@ -111,6 +111,17 @@ module CMDx
|
|
|
111
111
|
current
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
# Returns the thread or fiber storage for the current execution context.
|
|
117
|
+
#
|
|
118
|
+
# @return [Hash] The thread or fiber storage
|
|
119
|
+
#
|
|
120
|
+
# @rbs () -> Hash
|
|
121
|
+
def thread_or_fiber
|
|
122
|
+
Fiber.respond_to?(:storage) ? Fiber.storage : Thread.current
|
|
123
|
+
end
|
|
124
|
+
|
|
114
125
|
end
|
|
115
126
|
|
|
116
127
|
# Returns whether the chain is running in dry-run mode.
|
data/lib/cmdx/coercions/array.rb
CHANGED
|
@@ -5,7 +5,7 @@ module CMDx
|
|
|
5
5
|
# Converts various input types to Array format
|
|
6
6
|
#
|
|
7
7
|
# Handles conversion from strings that look like JSON arrays and other
|
|
8
|
-
# values that can be
|
|
8
|
+
# values that can be wrapped in an array using Ruby's Array() method.
|
|
9
9
|
module Array
|
|
10
10
|
|
|
11
11
|
extend self
|
|
@@ -29,8 +29,11 @@ module CMDx
|
|
|
29
29
|
#
|
|
30
30
|
# @rbs (untyped value, ?Hash[Symbol, untyped] options) -> Array[untyped]
|
|
31
31
|
def call(value, options = {})
|
|
32
|
-
if value.is_a?(::String) &&
|
|
33
|
-
|
|
32
|
+
if value.is_a?(::String) && (
|
|
33
|
+
value.start_with?("[") ||
|
|
34
|
+
value.strip == "null"
|
|
35
|
+
)
|
|
36
|
+
JSON.parse(value) || []
|
|
34
37
|
else
|
|
35
38
|
Array(value)
|
|
36
39
|
end
|
data/lib/cmdx/coercions/hash.rb
CHANGED
|
@@ -9,6 +9,7 @@ module CMDx
|
|
|
9
9
|
# - Hash objects (returned as-is)
|
|
10
10
|
# - Array objects (converted using Hash[*array])
|
|
11
11
|
# - JSON strings starting with "{" (parsed into Hash)
|
|
12
|
+
# - JSON strings that are "null" (parsed into empty Hash)
|
|
12
13
|
# - Other types raise CoercionError
|
|
13
14
|
module Hash
|
|
14
15
|
|
|
@@ -39,8 +40,11 @@ module CMDx
|
|
|
39
40
|
value
|
|
40
41
|
elsif value.is_a?(::Array)
|
|
41
42
|
::Hash[*value]
|
|
42
|
-
elsif value.is_a?(::String) &&
|
|
43
|
-
|
|
43
|
+
elsif value.is_a?(::String) && (
|
|
44
|
+
value.start_with?("{") ||
|
|
45
|
+
value.strip == "null"
|
|
46
|
+
)
|
|
47
|
+
JSON.parse(value) || {}
|
|
44
48
|
elsif value.respond_to?(:to_h)
|
|
45
49
|
value.to_h
|
|
46
50
|
else
|
data/lib/cmdx/executor.rb
CHANGED
|
@@ -66,6 +66,7 @@ module CMDx
|
|
|
66
66
|
task.class.settings[:middlewares].call!(task) do
|
|
67
67
|
pre_execution! unless @pre_execution
|
|
68
68
|
execution!
|
|
69
|
+
verify_returns!
|
|
69
70
|
rescue UndefinedMethodError => e
|
|
70
71
|
raise(e) # No need to clear the Chain since exception is not being re-raised
|
|
71
72
|
rescue Fault => e
|
|
@@ -97,6 +98,7 @@ module CMDx
|
|
|
97
98
|
task.class.settings[:middlewares].call!(task) do
|
|
98
99
|
pre_execution! unless @pre_execution
|
|
99
100
|
execution!
|
|
101
|
+
verify_returns!
|
|
100
102
|
rescue UndefinedMethodError => e
|
|
101
103
|
raise_exception(e)
|
|
102
104
|
rescue Fault => e
|
|
@@ -231,6 +233,27 @@ module CMDx
|
|
|
231
233
|
task.work
|
|
232
234
|
end
|
|
233
235
|
|
|
236
|
+
# Verifies that all declared returns are present in the context after execution.
|
|
237
|
+
#
|
|
238
|
+
# @rbs () -> void
|
|
239
|
+
def verify_returns!
|
|
240
|
+
return unless result.success?
|
|
241
|
+
|
|
242
|
+
returns = Array(task.class.settings[:returns])
|
|
243
|
+
missing = returns.reject { |name| task.context.key?(name) }
|
|
244
|
+
return if missing.empty?
|
|
245
|
+
|
|
246
|
+
missing.each { |name| task.errors.add(name, Locale.t("cmdx.returns.missing")) }
|
|
247
|
+
|
|
248
|
+
result.fail!(
|
|
249
|
+
Locale.t("cmdx.faults.invalid"),
|
|
250
|
+
errors: {
|
|
251
|
+
full_message: task.errors.to_s,
|
|
252
|
+
messages: task.errors.to_h
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
end
|
|
256
|
+
|
|
234
257
|
# Performs post-execution tasks including callback invocation.
|
|
235
258
|
#
|
|
236
259
|
# @rbs () -> void
|
|
@@ -4,18 +4,18 @@ module CMDx
|
|
|
4
4
|
module Middlewares
|
|
5
5
|
# Middleware for correlating task executions with unique identifiers.
|
|
6
6
|
#
|
|
7
|
-
# The Correlate middleware provides thread
|
|
8
|
-
# for tracking task execution flows across different operations.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
7
|
+
# The Correlate middleware provides thread and fiber safe correlation ID management
|
|
8
|
+
# for tracking task execution flows across different operations. It automatically
|
|
9
|
+
# generates correlation IDs when none are provided and stores them in task result
|
|
10
|
+
# metadata for traceability.
|
|
11
11
|
module Correlate
|
|
12
12
|
|
|
13
13
|
extend self
|
|
14
14
|
|
|
15
|
-
# @rbs
|
|
16
|
-
|
|
15
|
+
# @rbs CONCURRENCY_KEY: Symbol
|
|
16
|
+
CONCURRENCY_KEY = :cmdx_correlate
|
|
17
17
|
|
|
18
|
-
# Retrieves the current correlation ID from
|
|
18
|
+
# Retrieves the current correlation ID from local storage.
|
|
19
19
|
#
|
|
20
20
|
# @return [String, nil] The current correlation ID or nil if not set
|
|
21
21
|
#
|
|
@@ -24,10 +24,10 @@ module CMDx
|
|
|
24
24
|
#
|
|
25
25
|
# @rbs () -> String?
|
|
26
26
|
def id
|
|
27
|
-
|
|
27
|
+
thread_or_fiber[CONCURRENCY_KEY]
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# Sets the correlation ID in
|
|
30
|
+
# Sets the correlation ID in local storage.
|
|
31
31
|
#
|
|
32
32
|
# @param id [String] The correlation ID to set
|
|
33
33
|
# @return [String] The set correlation ID
|
|
@@ -37,10 +37,10 @@ module CMDx
|
|
|
37
37
|
#
|
|
38
38
|
# @rbs (String id) -> String
|
|
39
39
|
def id=(id)
|
|
40
|
-
|
|
40
|
+
thread_or_fiber[CONCURRENCY_KEY] = id
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
# Clears the current correlation ID from
|
|
43
|
+
# Clears the current correlation ID from local storage.
|
|
44
44
|
#
|
|
45
45
|
# @return [nil] Always returns nil
|
|
46
46
|
#
|
|
@@ -49,7 +49,7 @@ module CMDx
|
|
|
49
49
|
#
|
|
50
50
|
# @rbs () -> nil
|
|
51
51
|
def clear
|
|
52
|
-
|
|
52
|
+
thread_or_fiber[CONCURRENCY_KEY] = nil
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
# Temporarily uses a new correlation ID for the duration of a block.
|
|
@@ -122,6 +122,17 @@ module CMDx
|
|
|
122
122
|
use(correlation_id, &)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
# Returns the thread or fiber storage for the current execution context.
|
|
128
|
+
#
|
|
129
|
+
# @return [Hash] The thread or fiber storage
|
|
130
|
+
#
|
|
131
|
+
# @rbs () -> Hash
|
|
132
|
+
def thread_or_fiber
|
|
133
|
+
Fiber.respond_to?(:storage) ? Fiber.storage : Thread.current
|
|
134
|
+
end
|
|
135
|
+
|
|
125
136
|
end
|
|
126
137
|
end
|
|
127
138
|
end
|
data/lib/cmdx/task.rb
CHANGED
|
@@ -130,6 +130,7 @@ module CMDx
|
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
hash[:attributes] ||= AttributeRegistry.new
|
|
133
|
+
hash[:returns] ||= []
|
|
133
134
|
hash[:tags] ||= []
|
|
134
135
|
|
|
135
136
|
hash.merge!(options)
|
|
@@ -217,6 +218,33 @@ module CMDx
|
|
|
217
218
|
end
|
|
218
219
|
alias remove_attribute remove_attributes
|
|
219
220
|
|
|
221
|
+
# Declares expected context returns that must be set after task execution.
|
|
222
|
+
# If any declared return is missing from the context after {#work} completes
|
|
223
|
+
# successfully, the task will fail with a validation error.
|
|
224
|
+
#
|
|
225
|
+
# @param names [Array<Symbol, String>] Names of expected return keys in the context
|
|
226
|
+
#
|
|
227
|
+
# @example
|
|
228
|
+
# returns :user, :token
|
|
229
|
+
#
|
|
230
|
+
# @rbs (*untyped names) -> void
|
|
231
|
+
def returns(*names)
|
|
232
|
+
settings[:returns] |= names.map(&:to_sym)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Removes declared returns from the task.
|
|
236
|
+
#
|
|
237
|
+
# @param names [Array<Symbol>] Names of returns to remove
|
|
238
|
+
#
|
|
239
|
+
# @example
|
|
240
|
+
# remove_returns :old_return
|
|
241
|
+
#
|
|
242
|
+
# @rbs (*Symbol names) -> void
|
|
243
|
+
def remove_returns(*names)
|
|
244
|
+
settings[:returns] -= names.map(&:to_sym)
|
|
245
|
+
end
|
|
246
|
+
alias remove_return remove_returns
|
|
247
|
+
|
|
220
248
|
# @return [Hash] Hash of attribute names to their configurations
|
|
221
249
|
#
|
|
222
250
|
# @example
|
|
@@ -231,8 +259,8 @@ module CMDx
|
|
|
231
259
|
#
|
|
232
260
|
# @rbs () -> Hash[Symbol, Hash[Symbol, untyped]]
|
|
233
261
|
def attributes_schema
|
|
234
|
-
Array(settings[:attributes]).
|
|
235
|
-
|
|
262
|
+
Array(settings[:attributes]).to_h do |attr|
|
|
263
|
+
[attr.method_name, attr.to_h]
|
|
236
264
|
end
|
|
237
265
|
end
|
|
238
266
|
|
|
@@ -323,6 +351,10 @@ module CMDx
|
|
|
323
351
|
raise UndefinedMethodError, "undefined method #{self.class.name}#work"
|
|
324
352
|
end
|
|
325
353
|
|
|
354
|
+
# Returns a logger for this task. When a custom log_level or
|
|
355
|
+
# log_formatter is configured, the shared logger is duplicated
|
|
356
|
+
# so the original instance is never mutated.
|
|
357
|
+
#
|
|
326
358
|
# @return [Logger] The logger instance for this task
|
|
327
359
|
#
|
|
328
360
|
# @example
|
|
@@ -332,10 +364,17 @@ module CMDx
|
|
|
332
364
|
# @rbs () -> Logger
|
|
333
365
|
def logger
|
|
334
366
|
@logger ||= begin
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
367
|
+
log_instance = self.class.settings[:logger] || CMDx.configuration.logger
|
|
368
|
+
log_level = self.class.settings[:log_level]
|
|
369
|
+
log_formatter = self.class.settings[:log_formatter]
|
|
370
|
+
|
|
371
|
+
if log_level || log_formatter
|
|
372
|
+
log_instance = log_instance.dup
|
|
373
|
+
log_instance.level = log_level if log_level
|
|
374
|
+
log_instance.formatter = log_formatter if log_formatter
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
log_instance
|
|
339
378
|
end
|
|
340
379
|
end
|
|
341
380
|
|
data/lib/cmdx/version.rb
CHANGED
data/lib/locales/af.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
af:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "moet toeganklik wees via die
|
|
4
|
+
required: "moet toeganklik wees via die %{method} bronmetode"
|
|
5
5
|
undefined: "delegeer na ongedefinieerde metode %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "kon nie na %{type} omskep word nie"
|
|
8
8
|
into_an: "kon nie na %{type} omskep word nie"
|
|
9
9
|
into_any: "kon nie na een van: %{types} omskep word nie"
|
|
10
10
|
unknown: "onbekende %{type} omskep tipe"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "moet in die konteks gestel word"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Ongeldig"
|
|
13
15
|
unspecified: "Ongespesifiseer"
|
data/lib/locales/ar.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
ar:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "يجب أن يكون قابلاً للوصول عبر المصدر"
|
|
4
|
+
required: "يجب أن يكون قابلاً للوصول عبر طريقة المصدر %{method}"
|
|
5
5
|
undefined: "يفوض إلى طريقة غير معرفة %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "لا يمكن تحويله إلى %{type}"
|
|
8
8
|
into_an: "لا يمكن تحويله إلى %{type}"
|
|
9
9
|
into_any: "لا يمكن تحويله إلى واحد من: %{types}"
|
|
10
10
|
unknown: "نوع تحويل %{type} غير معروف"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "يجب تعيينه في السياق"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "غير صالح"
|
|
13
15
|
unspecified: "غير محدد"
|
data/lib/locales/az.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
az:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "mənbə vasitəsilə əlçatan olmalıdır"
|
|
4
|
+
required: "%{method} mənbə metodu vasitəsilə əlçatan olmalıdır"
|
|
5
5
|
undefined: "müəyyən edilməmiş metoda %{method} təyin edir"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "%{type} tipinə çevrilə bilmədi"
|
|
8
8
|
into_an: "%{type} tipinə çevrilə bilmədi"
|
|
9
9
|
into_any: "aşağıdakılardan birinə çevrilə bilmədi: %{types}"
|
|
10
10
|
unknown: "naməlum %{type} çevrilmə tipi"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "kontekstdə təyin edilməlidir"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Etibarsız"
|
|
13
15
|
unspecified: "Göstərilməyib"
|
data/lib/locales/be.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
be:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "
|
|
4
|
+
required: "павінен быць даступны праз зыходны метад %{method}"
|
|
5
5
|
undefined: "дэлегуе невызначанаму метаду %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "не ўдалося пераўтварыць у %{type}"
|
|
8
8
|
into_an: "не ўдалося пераўтварыць у %{type}"
|
|
9
9
|
into_any: "не ўдалося пераўтварыць у адзін з: %{types}"
|
|
10
10
|
unknown: "невядомы тып пераўтварэння %{type}"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "павінна быць усталявана ў кантэксце"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Няправільныя"
|
|
13
15
|
unspecified: "Не паказана"
|
data/lib/locales/bg.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
bg:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "трябва да
|
|
4
|
+
required: "трябва да е достъпен чрез изходния метод %{method}"
|
|
5
5
|
undefined: "делегира към недефиниран метод %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "не може да бъде преобразуван в %{type}"
|
|
8
8
|
into_an: "не може да бъде преобразуван в %{type}"
|
|
9
9
|
into_any: "не може да бъде преобразуван в един от: %{types}"
|
|
10
10
|
unknown: "неизвестен тип преобразуване %{type}"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "трябва да бъде зададено в контекста"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Невалидни"
|
|
13
15
|
unspecified: "Не е посочена"
|
data/lib/locales/bn.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
bn:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "
|
|
4
|
+
required: "%{method} সোর্স মেথডের মাধ্যমে অ্যাক্সেসযোগ্য হতে হবে"
|
|
5
5
|
undefined: "অসংজ্ঞায়িত পদ্ধতিতে %{method} অর্পণ করে"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "%{type} এ রূপান্তর করা যায়নি"
|
|
8
8
|
into_an: "%{type} এ রূপান্তর করা যায়নি"
|
|
9
9
|
into_any: "নিম্নলিখিতগুলির মধ্যে একটিতে রূপান্তর করা যায়নি: %{types}"
|
|
10
10
|
unknown: "অজানা %{type} রূপান্তর প্রকার"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "প্রসঙ্গে সেট করতে হবে"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "অবৈধ"
|
|
13
15
|
unspecified: "অনির্দিষ্ট"
|
data/lib/locales/bs.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
bs:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "mora biti dostupan
|
|
4
|
+
required: "mora biti dostupan preko izvorne metode %{method}"
|
|
5
5
|
undefined: "delegira nedefiniranoj metodi %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "nije mogao biti pretvoren u %{type}"
|
|
8
8
|
into_an: "nije mogao biti pretvoren u %{type}"
|
|
9
9
|
into_any: "nije mogao biti pretvoren u jedan od: %{types}"
|
|
10
10
|
unknown: "nepoznati tip pretvorbe %{type}"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "mora biti postavljeno u kontekstu"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Neispravni"
|
|
13
15
|
unspecified: "Nije naveden"
|
data/lib/locales/ca.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
ca:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "ha de ser accessible
|
|
4
|
+
required: "ha de ser accessible mitjançant el mètode font %{method}"
|
|
5
5
|
undefined: "delega al mètode no definit %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "no es va poder convertir a %{type}"
|
|
8
8
|
into_an: "no es va poder convertir a %{type}"
|
|
9
9
|
into_any: "no es va poder convertir a un de: %{types}"
|
|
10
10
|
unknown: "tipus de conversió %{type} desconegut"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "ha de ser establert en el context"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "No vàlides"
|
|
13
15
|
unspecified: "No especificat"
|
data/lib/locales/cnr.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
cnr:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "mora biti dostupan preko
|
|
4
|
+
required: "mora biti dostupan preko izvorne metode %{method}"
|
|
5
5
|
undefined: "delegira na nedefinisani metod %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "nije mogao konvertovati u %{type}"
|
|
8
8
|
into_an: "nije mogao konvertovati u %{type}"
|
|
9
9
|
into_any: "nije mogao konvertovati u jedan od: %{types}"
|
|
10
10
|
unknown: "nepoznati %{type} tip konverzije"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "mora biti postavljeno u kontekstu"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Neispravni"
|
|
13
15
|
unspecified: "Nije dat"
|
data/lib/locales/cs.yml
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
cs:
|
|
2
2
|
cmdx:
|
|
3
3
|
attributes:
|
|
4
|
-
required: "musí být přístupné přes
|
|
4
|
+
required: "musí být přístupné přes zdrojovou metodu %{method}"
|
|
5
5
|
undefined: "deleguje na nedefinovanou metodu %{method}"
|
|
6
6
|
coercions:
|
|
7
7
|
into_a: "nelze převést na %{type}"
|
|
8
8
|
into_an: "nelze převést na %{type}"
|
|
9
9
|
into_any: "nelze převést na jeden z: %{types}"
|
|
10
10
|
unknown: "neznámý typ převodu %{type}"
|
|
11
|
+
returns:
|
|
12
|
+
missing: "musí být nastaveno v kontextu"
|
|
11
13
|
faults:
|
|
12
14
|
invalid: "Neplatné"
|
|
13
15
|
unspecified: "Neurčeno"
|