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 ‘NoMethodError` for unknown keys instead of returning `nil`.
Class Method Summary collapse
-
.build(context = EMPTY_HASH) ⇒ Context
Normalizes ‘context` into 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 ‘other` is 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 ‘value` under `key`, 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.inspect` pairs.
- #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.
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 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? && !@table.key?(method_name) raise NoMethodError, "unknown context key #{method_name.inspect} (strict mode)" else @table[method_name] 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 |