Module: Bitfab::MockOverride

Defined in:
lib/bitfab/mock_override.rb

Overview

Selective mock overrides for replay. Mirrors the TypeScript SDK's mockOverride feature.

A mock override injects a custom value into a specific span (node) during replay: the matched span short-circuits its real execution and returns the value the processor produces, so downstream real code runs against the substituted output. This is a third mock mode alongside "run real code" and "replay recorded output" (see MOCK_STRATEGIES in replay.rb).

An override is a (match, value) pair, represented as a symbol-keyed hash { match:, value: }:

  • match is a callable (proc/lambda): match.call(node) -> boolean. node is a structural-metadata hash { trace_function_key:, span_name:, type:, original_span_id: } (symbol keys; original_span_id may be nil when the live span has no recorded counterpart). Matching must not depend on the recorded output.

  • value is EITHER a flat value OR a callable. A flat value is injected directly (e.g. value: { label: "refund" }). A callable is invoked with the ctx hash: value.call(ctx) where ctx is { node:, inputs:, kwargs:, get_original_output: } - inputs is the live replay positional args array, kwargs is the live keyword args hash (empty when the call used none), and get_original_output is a proc returning this span's recorded output (deserialized; raises if there is no recorded counterpart). Either way the resulting value IS the span's output (full replacement, no merge); nil is a legitimate injected value. To inject a proc as the literal output, wrap it in a callable value: value: ->(ctx) { the_proc }.

Unlike the TypeScript SDK, Ruby's span tree is fetched with outputs inline (get_span_tree), so get_original_output simply returns the inline recorded output. There is no lazy per-span fetch and Ruby is synchronous, so there is no async limitation.

Class Method Summary collapse

Class Method Details

.normalize(mock_override) ⇒ Array<Hash>

Normalize the per-call mock_override option (a single override hash, an array of them, or nil) into an array. First match wins downstream, so order is preserved.

Each override is validated: it must be a hash with a callable :match and must include a :value key. A forgotten :value raises rather than silently short-circuiting matched spans with nil (an explicit value: nil is a legitimate injected value and passes). Mirrors the guard on register_mock_override, and the Python/TypeScript SDKs, where the per-call override object requires a value.

Parameters:

  • mock_override (Hash, Array<Hash>, nil)

Returns:

  • (Array<Hash>)


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/bitfab/mock_override.rb', line 54

def normalize(mock_override)
  return [] if mock_override.nil?

  overrides = mock_override.is_a?(Array) ? mock_override : [mock_override]
  overrides.each do |override|
    unless override.is_a?(Hash) && override[:match].respond_to?(:call)
      raise ArgumentError,
        "mock_override requires a callable :match. Pass a " \
        "{ match:, value: } hash (or an array of them). value may be a " \
        "flat value or a callable."
    end
    unless override.key?(:value)
      raise ArgumentError,
        "mock_override requires a :value (a flat value or a callable); " \
        "pass value: nil explicitly to inject nil."
    end
  end
  overrides
end