Module: Hitch::MCP::Internal::JsonValues

Defined in:
app/models/hitch/mcp/internal/json_values.rb

Overview

Shared recursive helpers for the JSON-value structures that cross MCP boundaries. Keys are never symbolized (INV-MCP-007).

Defined Under Namespace

Classes: Copier

Constant Summary collapse

DEFAULT_HANDLER =

Every rejecting boundary supplies its own on_invalid; this fires only when a policy rejects without one.

lambda do |reason, _detail|
  raise ArgumentError, "JSON value copy rejected (#{reason})"
end

Class Method Summary collapse

Class Method Details

.copy(value, keys: :as_is, symbols: :keep, foreign: :keep, finite: false, duplicates: :replace, freeze: false, max_depth: nil, max_objects: nil, on_invalid: DEFAULT_HANDLER) ⇒ Object

The one deep JSON copier. Each boundary states its policy:

keys:       :as_is, :string (String only), :stringify_symbols,
          :preserve (String copied, Symbol kept), or :to_s
symbols:    Symbol values — :keep, :to_s, or :reject
foreign:    values outside the JSON universe — :keep, :to_s, or :reject
finite:     reject non-finite Floats
duplicates: keys that collide after normalization — :replace or :reject
freeze:     deep-freeze the copy
max_depth / max_objects: structural caps

on_invalid receives (reason, detail) and either raises or returns the replacement for the entire copy. Reasons: :recursive, :depth, :objects, :key, :duplicate_key, :non_finite, :foreign.



39
40
41
42
43
44
45
46
# File 'app/models/hitch/mcp/internal/json_values.rb', line 39

def copy(value, keys: :as_is, symbols: :keep, foreign: :keep, finite: false,
  duplicates: :replace, freeze: false, max_depth: nil, max_objects: nil,
  on_invalid: DEFAULT_HANDLER)
  Copier.new(
    keys:, symbols:, foreign:, finite:, duplicates:,
    freeze:, max_depth:, max_objects:, on_invalid:
  ).call(value)
end

.deep_freeze(value) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'app/models/hitch/mcp/internal/json_values.rb', line 52

def deep_freeze(value)
  case value
  when Hash
    value.each { |key, child| deep_freeze(key); deep_freeze(child) }
  when Array
    value.each { |child| deep_freeze(child) }
  end
  value.freeze
end

.deep_string_copy_and_freeze(value) ⇒ Object



48
49
50
# File 'app/models/hitch/mcp/internal/json_values.rb', line 48

def deep_string_copy_and_freeze(value)
  copy(value, keys: :to_s, freeze: true)
end

.read(hash, key) ⇒ Object

String/Symbol-indifferent read that prefers the key exactly as given.



20
21
22
23
24
25
# File 'app/models/hitch/mcp/internal/json_values.rb', line 20

def read(hash, key)
  return unless hash.is_a?(Hash)
  return hash[key] if hash.key?(key)

  hash[key.is_a?(Symbol) ? key.to_s : key.to_sym]
end