GtBridge.Eval (gt_bridge v0.19.2)

Copy Markdown View Source

I am a per-session evaluation GenServer.

Each instance corresponds to a GT view's evaluation context (LeSharedSnippetContext). All snippets within the same view share one Eval process (same bindings).

I track object IDs registered in GtBridge.ObjectRegistry during my lifetime. When I terminate (session closed), I batch-remove all tracked objects from the registry.

Cleanup

GT's BeamSessionFinalizer sends POST /SESSION_CLOSE when the per-view GtSharedVariablesBindings is GC'd (page/inspector closed). The router calls EvalRegistry.remove/1 which terminates me, and terminate/2 batch-removes all tracked objects from the registry.

Summary

Functions

Returns a specification to start this module under a supervisor.

I encode an evaluation result for the wire.

I evaluate in the calling process and return the value, so the answer can travel back in the HTTP response rather than as a second message.

I drain and return all messages received by the eval process.

I return the current bindings as a map of name→serialized value. Internal bindings (:port, :command_id, :pid) are filtered out. Non-primitive values are registered in ObjectRegistry.

I return documentation for a module, function, or type.

Remove an object from the registry. Called by GT when a proxy object is garbage collected.

Types

t()

@type t() :: %GtBridge.Eval{
  bindings: Code.binding() | nil,
  env: Macro.Env.t() | nil,
  locals: [{atom(), arity()}],
  port: non_neg_integer(),
  registered_ids: MapSet.t(non_neg_integer())
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

complete(pid, code_prefix, source \\ nil)

@spec complete(GenServer.server(), String.t(), String.t() | nil) :: [String.t()]

encode_result(obj)

@spec encode_result(term()) :: String.t()

I encode an evaluation result for the wire.

I register complex values in GtBridge.ObjectRegistry and send an %{exid, exclass} reference, so GT receives a proxy it can inspect lazily rather than a fully materialised copy. Primitives travel by value.

eval(pid, code, command_id)

@spec eval(GenServer.server(), String.t(), String.t() | nil) :: any()

eval_stateless_sync(code, command_id, port)

@spec eval_stateless_sync(String.t(), String.t() | nil, pos_integer() | nil) :: term()

I evaluate in the calling process and return the value, so the answer can travel back in the HTTP response rather than as a second message.

A request already runs in its own process, so running inline gives the same isolation a spawned Task would.

flush()

@spec flush() :: [term()]

I drain and return all messages received by the eval process.

Like IEx's flush/0. Useful when user code subscribes the eval process to event brokers and you want to see what arrived.

flush()

get_bindings(pid)

@spec get_bindings(GenServer.server()) :: map()

I return the current bindings as a map of name→serialized value. Internal bindings (:port, :command_id, :pid) are filtered out. Non-primitive values are registered in ObjectRegistry.

h(other)

(macro)

I return documentation for a module, function, or type.

Bound as h in every eval session. Because I am a macro, I can parse dot-syntax like h(Enum.map) and h(Enum.map/2).

h(Enum)
h(Enum.map)
h(Enum.map/2)
h({Enum, :map})
h({Enum, :map, 2})

remove(id)

@spec remove(non_neg_integer()) :: :ok

Remove an object from the registry. Called by GT when a proxy object is garbage collected.

start_link(init_args)