Class: Kobako::Catalog::Namespaces

Inherits:
Object
  • Object
show all
Defined in:
lib/kobako/catalog/namespaces.rb

Overview

Kobako::Catalog::Namespaces — per-Sandbox registry of Kobako::Namespace entities. Holds the Namespace / Member bindings and the preamble emitted on Frame 1 (docs/behavior.md B-07..B-11).

Public API:

namespaces = Kobako::Catalog::Namespaces.new
namespace = namespaces.define(:MyService)  # => Kobako::Namespace
namespace.bind(:KV, kv_object)             # => namespace (chainable)
namespaces.encode                          # => msgpack bytes for Frame 1
namespaces.lookup("MyService::KV")         # => kv_object

Namespaces live at Kobako::Namespace. Per-dispatch routing is Kobako::Transport::Dispatcher‘s responsibility — the Dispatcher receives this registry and the Catalog::Handles as arguments from the Runtime#on_dispatch Proc that Kobako::Sandbox#initialize installs (docs/behavior.md B-12). The registry holds an injected Catalog::Handles reference so dispatch target resolution and host→guest auto-wrap share the same Sandbox-owned allocator (docs/behavior.md B-19).

Instance Method Summary collapse

Constructor Details

#initialize(handler: Catalog::Handles.new) ⇒ Namespaces

Build a fresh registry. handler is an internal seam that injects a pre-configured Catalog::Handles; tests pass one whose next_id is pinned near MAX_ID to exercise the B-21 cap-exhaustion path without 2³¹ allocations. Production callers leave it at the default.



37
38
39
40
41
# File 'lib/kobako/catalog/namespaces.rb', line 37

def initialize(handler: Catalog::Handles.new)
  @namespaces = {} # : Hash[String, Kobako::Namespace]
  @handler = handler
  @sealed = false
end

Instance Method Details

#define(name) ⇒ Object

Declare or retrieve the Namespace named name (idempotent — docs/behavior.md B-10). name is a constant-form name as a Symbol or String (must satisfy Namespace::NAME_PATTERN). Returns the Kobako::Namespace for that name, creating it if it does not exist. Raises ArgumentError when name is malformed, or when called after the owning Sandbox has been sealed by its first invocation (docs/behavior.md B-07).

Raises:

  • (ArgumentError)


50
51
52
53
54
55
56
57
58
59
60
# File 'lib/kobako/catalog/namespaces.rb', line 50

def define(name)
  raise ArgumentError, "cannot define after first Sandbox invocation" if @sealed

  name_str = name.to_s
  unless Namespace::NAME_PATTERN.match?(name_str)
    raise ArgumentError,
          "Namespace name must match #{Namespace::NAME_PATTERN.inspect} (got #{name.inspect})"
  end

  @namespaces[name_str] ||= Namespace.new(name_str)
end

#encodeObject

Encode the preamble as msgpack bytes for stdin Frame 1 delivery (docs/behavior.md B-02). Routes through Kobako::Codec::Encoder like every other host-side wire encode so there is a single codec path; the preamble carries only Strings and Arrays, so none of the kobako ext types actually fire. Structure: [[“Namespace”, [“MemberA”, “MemberB”]], …]. Returns a binary String of msgpack bytes.



82
83
84
# File 'lib/kobako/catalog/namespaces.rb', line 82

def encode
  Codec::Encoder.encode(@namespaces.values.map(&:to_preamble))
end

#lookup(target) ⇒ Object

Resolve a target path of the form “Namespace::Member” to the bound Host object. target is a two-level path using the :: separator. Returns the bound Host object. Raises KeyError when the namespace or the member is not bound.

Raises:

  • (KeyError)


66
67
68
69
70
71
72
73
# File 'lib/kobako/catalog/namespaces.rb', line 66

def lookup(target)
  namespace_name, member_name = target.to_s.split("::", 2)
  namespace = @namespaces[namespace_name]
  raise KeyError, "no namespace named #{namespace_name.inspect}" if namespace.nil?
  raise KeyError, "no member in target #{target.inspect}" unless member_name

  namespace.fetch(member_name)
end

#seal!Object

Mark the registry as sealed. Called by Sandbox on the first invocation. After sealing, #define raises ArgumentError. Idempotent.



88
89
90
91
# File 'lib/kobako/catalog/namespaces.rb', line 88

def seal!
  @sealed = true
  self
end

#sealed?Boolean

Returns true when #seal! has been called, false otherwise.

Returns:

  • (Boolean)


94
95
96
# File 'lib/kobako/catalog/namespaces.rb', line 94

def sealed?
  @sealed
end