Module: Axn::Core::AmbientContext

Defined in:
lib/axn/core/ambient_context.rb

Overview

ambient_context is a reserved, always-present parent on every Axn. Its reader returns a Hash ({} by default) that subfields extract from via expects :x, on: :ambient_context. Reads are declaration-gated (a reader exists only for declared subfields), and the hash is filtered to the declared ambient keys — along their declared PATHS (PRO-2909), so a deeply nested ambient subfield resolves its value while the hash still never carries an undeclared sibling or a process-wide dump of Current state.

Defined Under Namespace

Modules: ClassMethods Classes: AmbientSubfieldTreeCacheEntry

Constant Summary collapse

PARENT =
:ambient_context

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.default_sourceObject

Default ambient-context source: a live view over every registered ActiveSupport:: CurrentAttributes. Core filters the result down to each Axn's declared ambient keys (see _filter_to_declared), so returning everything here is safe — undeclared keys are never readable and never injected.



181
182
183
184
185
186
187
188
189
190
# File 'lib/axn/core/ambient_context.rb', line 181

def self.default_source
  return {} unless defined?(ActiveSupport::CurrentAttributes)

  ActiveSupport::CurrentAttributes.descendants.each_with_object({}) do |klass, acc|
    # When two CurrentAttributes classes declare the same attribute, last-descendant-wins
    # silently (by design per spec — core filters to declared keys downstream, so undeclared
    # collisions never surface).
    acc.merge!(klass.instance.attributes)
  end
end

.included(base) ⇒ Object



22
23
24
# File 'lib/axn/core/ambient_context.rb', line 22

def self.included(base)
  base.extend(ClassMethods)
end

Instance Method Details

#ambient_contextObject

Instance reader used by ContractForSubfields.resolve_parent (public_send(:ambient_context)).

A failing provider is memoized as an ERROR (not {}) and re-raised on every subsequent read. This matters because automatic BEFORE-logging can be the FIRST read (a dynamic sensitive: predicate reading an ambient subfield is evaluated while building the log filter) — and CallLogger SWALLOWS logging errors. Memoizing {} there would hide the real failure from inbound validation (which reads ambient_context next) and report a bogus "can't be blank" instead of the provider's actual exception. Memoizing the error instead means the provider still runs at most once, but the real error surfaces at the first NON-swallowed read.

Raises:

  • (@__ambient_context_error)


201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/axn/core/ambient_context.rb', line 201

def ambient_context
  raise @__ambient_context_error if defined?(@__ambient_context_error)
  return @__ambient_context if defined?(@__ambient_context)

  begin
    @__ambient_context = _resolve_ambient_context
  # Memoizes whatever axn absorbs, not just StandardError, or "the provider still runs at most
  # once" (above) breaks for a provider that blows the stack: it would re-run on every read.
  rescue StandardError, *Axn::Extensions::SWALLOWABLE_BEYOND_STANDARD_ERROR => e
    @__ambient_context_error = e
    raise
  end
end