Class: CMDx::Context
Overview
Shared data object passed through task execution. Wraps a symbol-keyed
hash; supports ctx.foo/ctx.foo = 1/ctx.foo? dynamic accessors via
#method_missing. Runtime freezes the root context during teardown so
nested subtasks can't mutate the outer task's state after completion.
Instance Attribute Summary collapse
-
#strict ⇒ Boolean
Enables strict mode — when true, dynamic readers via #method_missing raise
NoMethodErrorfor unknown keys instead of returningnil.
Class Method Summary collapse
-
.build(context = EMPTY_HASH) ⇒ Context
Normalizes
contextinto a Context instance.
Instance Method Summary collapse
- #[](key) ⇒ Object?
-
#as_json ⇒ Hash{Symbol => Object}
JSON-friendly hash view.
-
#clear ⇒ Context
Removes every entry.
-
#deconstruct ⇒ Array<Array(Symbol, Object)>
Pattern-matching support for
case context in [...]. -
#deconstruct_keys(keys) ⇒ Hash{Symbol => Object}
Pattern-matching support for
case context in {...}. -
#deep_dup ⇒ Context
Returns a deep copy.
-
#deep_merge(context = EMPTY_HASH) ⇒ Context
Like #merge but recursive into Hash values: a nested Hash key collision merges the two Hashes instead of replacing the left with the right.
-
#delete(key) {|Symbol| ... } ⇒ Object?
Removed value.
- #dig(key, *keys) ⇒ Object?
- #each {|key, value| ... } ⇒ Context, Enumerator
- #each_key {|Symbol| ... } ⇒ Context, Enumerator
- #each_value {|Object| ... } ⇒ Context, Enumerator
- #empty? ⇒ Boolean
-
#eql?(other) ⇒ Boolean
(also: #==)
Equal when
otheris a Context with the same underlying hash. -
#fetch(key) ⇒ Object
Hash-like fetch.
-
#freeze ⇒ Context
Freezes the context and its backing hash.
- #hash ⇒ Integer
-
#initialize(context = EMPTY_HASH) ⇒ Context
constructor
A new instance of Context.
- #key?(key) ⇒ Boolean
- #keys ⇒ Array<Symbol>
-
#merge(context = EMPTY_HASH) ⇒ Context
Merges another context/hash-like into this one in place.
-
#retrieve(key, value = nil) { ... } ⇒ Object
Fetch-or-store.
- #size ⇒ Integer
-
#store(key, value) ⇒ Object
(also: #[]=)
Stores
valueunderkey, symbolizing the key. -
#strict? ⇒ Boolean
Whether dynamic reads for unknown keys raise instead of returning
nil. -
#to_h ⇒ Hash{Symbol => Object}
The underlying table (not a copy).
-
#to_json(*args) ⇒ String
Serializes the context to a JSON string.
-
#to_s ⇒ String
Space-separated
key=value.inspectpairs. - #values ⇒ Array<Object>
Constructor Details
#initialize(context = EMPTY_HASH) ⇒ Context
Returns a new instance of Context.
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/cmdx/context.rb', line 43 def initialize(context = EMPTY_HASH) @table = if context.respond_to?(:to_hash) context.to_hash elsif context.respond_to?(:to_h) context.to_h else raise ArgumentError, "must respond to `to_h` or `to_hash`" end.transform_keys(&:to_sym) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, **_kwargs) ⇒ Object (private)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Provides dynamic read/write/predicate access to context keys.
ctx.name— reads@table[name],nilwhen absent (raisesNoMethodErrorwhen #strict? is true and the key is absent).ctx.name = val— storesvalunder:name.ctx.name?— truthy check for@table[:name].
283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/cmdx/context.rb', line 283 def method_missing(method_name, *args, **_kwargs, &) if @table.key?(method_name) @table[method_name] elsif method_name.end_with?("=") @table[method_name[..-2].to_sym] = args.first elsif method_name.end_with?("?") !!@table[method_name[..-2].to_sym] elsif strict? raise NoMethodError, "unknown context key #{method_name.inspect} (strict mode)" end end |
Instance Attribute Details
#strict ⇒ Boolean
Enables strict mode — when true, dynamic readers via #method_missing
raise NoMethodError for unknown keys instead of returning nil.
Set by Task#initialize from Task.settings.strict_context.
39 40 41 |
# File 'lib/cmdx/context.rb', line 39 def strict @strict end |
Class Method Details
.build(context = EMPTY_HASH) ⇒ Context
Normalizes context into a Context instance. Passes through an
unfrozen Context unchanged (so nested tasks share state); unwraps
anything with #context (e.g. a Task); wraps hashes/hash-likes into
a new Context with symbolized keys.
22 23 24 25 26 27 28 29 30 |
# File 'lib/cmdx/context.rb', line 22 def build(context = EMPTY_HASH) if context.is_a?(self) && !context.frozen? context elsif context.respond_to?(:context) build(context.context) else new(context) end end |
Instance Method Details
#[](key) ⇒ Object?
96 97 98 |
# File 'lib/cmdx/context.rb', line 96 def [](key) @table[key.to_sym] end |
#as_json ⇒ Hash{Symbol => Object}
JSON-friendly hash view. Aliases #to_h for conventional as_json
callers (e.g. Rails); values pass through unchanged — non-primitive
entries rely on their own as_json / to_json.
215 216 217 |
# File 'lib/cmdx/context.rb', line 215 def as_json(*) to_h end |
#clear ⇒ Context
Removes every entry.
186 187 188 189 |
# File 'lib/cmdx/context.rb', line 186 def clear @table.clear self end |
#deconstruct ⇒ Array<Array(Symbol, Object)>
Pattern-matching support for case context in [...].
244 245 246 |
# File 'lib/cmdx/context.rb', line 244 def deconstruct @table.to_a end |
#deconstruct_keys(keys) ⇒ Hash{Symbol => Object}
Pattern-matching support for case context in {...}.
237 238 239 |
# File 'lib/cmdx/context.rb', line 237 def deconstruct_keys(keys) keys.nil? ? @table : @table.slice(*keys) end |
#deep_dup ⇒ Context
Returns a deep copy. Non-mutable scalars are shared; Hashes/Arrays are
recursively duplicated; other objects fall back to #dup (and then
to the original on StandardError).
253 254 255 256 257 |
# File 'lib/cmdx/context.rb', line 253 def deep_dup ctx = self.class.allocate ctx.instance_variable_set(:@table, compute_deep_dup(@table)) ctx end |
#deep_merge(context = EMPTY_HASH) ⇒ Context
Like #merge but recursive into Hash values: a nested Hash key collision
merges the two Hashes instead of replacing the left with the right.
Non-Hash values follow last-write-wins (context wins).
88 89 90 91 92 |
# File 'lib/cmdx/context.rb', line 88 def deep_merge(context = EMPTY_HASH) other = self.class.build(context) @table = compute_deep_merge(@table, other.to_h) self end |
#delete(key) {|Symbol| ... } ⇒ Object?
Returns removed value.
179 180 181 |
# File 'lib/cmdx/context.rb', line 179 def delete(key, &) @table.delete(key.to_sym, &) end |
#dig(key, *keys) ⇒ Object?
112 113 114 |
# File 'lib/cmdx/context.rb', line 112 def dig(key, *keys) @table.dig(key.to_sym, *keys) end |
#each {|key, value| ... } ⇒ Context, Enumerator
160 161 162 |
# File 'lib/cmdx/context.rb', line 160 def each(&) @table.each(&) end |
#each_key {|Symbol| ... } ⇒ Context, Enumerator
166 167 168 |
# File 'lib/cmdx/context.rb', line 166 def each_key(&) @table.each_key(&) end |
#each_value {|Object| ... } ⇒ Context, Enumerator
172 173 174 |
# File 'lib/cmdx/context.rb', line 172 def each_value(&) @table.each_value(&) end |
#empty? ⇒ Boolean
149 150 151 |
# File 'lib/cmdx/context.rb', line 149 def empty? @table.empty? end |
#eql?(other) ⇒ Boolean Also known as: ==
Equal when other is a Context with the same underlying hash.
195 196 197 |
# File 'lib/cmdx/context.rb', line 195 def eql?(other) other.is_a?(self.class) && (to_h == other.to_h) end |
#fetch(key) ⇒ Object
Hash-like fetch. Supports a default value, default block, or raises
KeyError just like Hash#fetch.
105 106 107 |
# File 'lib/cmdx/context.rb', line 105 def fetch(key, ...) @table.fetch(key.to_sym, ...) end |
#freeze ⇒ Context
Freezes the context and its backing hash. Runtime calls this on the root task's context during teardown.
263 264 265 266 |
# File 'lib/cmdx/context.rb', line 263 def freeze @table.freeze super end |
#hash ⇒ Integer
201 202 203 |
# File 'lib/cmdx/context.rb', line 201 def hash @table.hash end |
#key?(key) ⇒ Boolean
134 135 136 |
# File 'lib/cmdx/context.rb', line 134 def key?(key) @table.key?(key.to_sym) end |
#keys ⇒ Array<Symbol>
139 140 141 |
# File 'lib/cmdx/context.rb', line 139 def keys @table.keys end |
#merge(context = EMPTY_HASH) ⇒ Context
Merges another context/hash-like into this one in place. Keys from
context win on conflict.
76 77 78 79 80 |
# File 'lib/cmdx/context.rb', line 76 def merge(context = EMPTY_HASH) other = self.class.build(context) @table.merge!(other.to_h) self end |
#retrieve(key, value = nil) { ... } ⇒ Object
Fetch-or-store. Returns the existing value, or stores and returns the
default (from block if given, else value).
124 125 126 127 128 129 130 |
# File 'lib/cmdx/context.rb', line 124 def retrieve(key, value = nil) nk = key.to_sym @table.fetch(nk) do @table[nk] = block_given? ? yield : value end end |
#size ⇒ Integer
154 155 156 |
# File 'lib/cmdx/context.rb', line 154 def size @table.size end |
#store(key, value) ⇒ Object Also known as: []=
Stores value under key, symbolizing the key. Overwrites any
existing entry.
66 67 68 |
# File 'lib/cmdx/context.rb', line 66 def store(key, value) @table[key.to_sym] = value end |
#strict? ⇒ Boolean
Returns whether dynamic reads for unknown keys raise instead
of returning nil.
56 57 58 |
# File 'lib/cmdx/context.rb', line 56 def strict? !!@strict end |
#to_h ⇒ Hash{Symbol => Object}
Returns the underlying table (not a copy).
206 207 208 |
# File 'lib/cmdx/context.rb', line 206 def to_h @table end |
#to_json(*args) ⇒ String
Serializes the context to a JSON string. Symbol keys are emitted as
strings by the json stdlib.
224 225 226 |
# File 'lib/cmdx/context.rb', line 224 def to_json(*args) to_h.to_json(*args) end |
#to_s ⇒ String
Returns space-separated key=value.inspect pairs.
229 230 231 |
# File 'lib/cmdx/context.rb', line 229 def to_s @table.map { |k, v| "#{k}=#{v.inspect}" }.join(" ") end |
#values ⇒ Array<Object>
144 145 146 |
# File 'lib/cmdx/context.rb', line 144 def values @table.values end |