On this page
Own the room's working objects๏
Prerequisite: Rift setup. The workstation is the room's local binding canvas. It holds objects, attributes, and methods you give it; it is not another Spellbook or an implicit resolver.
The saved example binds the name subject in both the object and method stores.
The store= argument distinguishes them. It selects a method as the active target,
calls it, clears the target without deleting the binding, and releases the object.
Be explicit about retention๏
weak_ref=True requests weak storage. The lesson proves a non-weak-referenceable
value is refused rather than silently stored strongly. A strong binding retains
the object for the binding's lifetime; a weak binding does not give it that lifetime.
Keep room storage and world access separate. Retrieve permitted world objects through the room's command/view surfaces, then place the objects you need on the canvas. Expert rooms continue into operation and codegen.
The workflow in code๏
These are the core steps from the saved example. Use its complete linked script for all class definitions and setup.
1def main() -> None:
2 nexus = md.Nexus()
3 system_config = nexus.create_configuration()
4 system_config.with_rift_creation_enabled(True)
5 nexus.activate(system_config)
6
7 rift_config = nexus.create_rift_configuration()
8 rift_config.with_space_type("capability")
9 rift = nexus.create_rift(configuration=rift_config, rift_name="bench")
10 rift.mark_active()
11
12 workstation = rift.space.workstation
13 assert isinstance(workstation, md.Workstation)
14 assert workstation.owner_space_id == rift.space.space_id
15 print("workstation:", workstation.workstation_id)
16 print("owned by room:", workstation.owner_space_id == rift.space.space_id)
17
18 # THREE STORES. The same name in two stores is not a collision.
19 greeter = Greeter()
20 workstation.bind_object("subject", greeter)
21 workstation.bind_method("subject", greeter.greet)
22 print("bound 'subject' into two different stores")
23
24 from_objects = workstation.get("subject", store="objects")
25 from_methods = workstation.get("subject", store="methods")
26 assert from_objects is greeter
27 assert from_methods() == "hello from the canvas"
28 print("objects['subject'] is the instance; methods['subject'] is callable")
29
30 # THE READ DOOR. Ask the canvas what is on it.
31 summary = workstation.describe_bindings()
32 print("describe_bindings keys:", sorted(summary))
33 for store in ("objects", "attributes", "methods", "target_name"):
34 assert store in summary, store
35 assert "subject" in summary["objects"]
36 assert "subject" in summary["methods"]
37
38 # Five keys, and the docstring now says five. `target_store` names the
39 # store the active target came from - enough to round-trip it back
40 # through get(name, store=...).
41 assert set(summary) == {"objects", "attributes", "methods",
42 "target_name", "target_store"}
43 print("keys:", len(summary), "- documented and returned agree")
44
45 # ONE TARGET AT A TIME.
46 workstation.set_target("subject", store="methods")
47 assert workstation.get_target() is not None
48 print("target set from the methods store")
49
50 result = workstation.call_target()
51 assert result == "hello from the canvas"
52 print("call_target ->", result)
53
54 workstation.clear_target()
55 # Clearing deselects; it does not delete the binding underneath.
56 assert workstation.get("subject", store="methods") is not None
57 print("target cleared; the binding it pointed at is still there")
58
59 # WEAK BY REQUEST. A class instance can be weak-referenced.
60 workstation.bind_object("weak_subject", Greeter(), weak_ref=True)
61 print("weak binding accepted for a weak-referenceable object")
62
63 # ...and an int cannot. This RAISES rather than quietly storing it
64 # strongly, which is the whole point.
65 try:
66 workstation.bind_object("weak_number", 42, weak_ref=True)
67 raise AssertionError(
68 "expected a refusal - int cannot be weak-referenced"
69 )
70 except (TypeError, ValueError, RuntimeError) as error:
71 print("explicit weak binding refused:", type(error).__name__)
72
73 # No silent degrade means: it is not on the canvas at all.
74 after = workstation.describe_bindings()
75 assert "weak_number" not in after["objects"]
76 print("refused binding was NOT stored strongly as a fallback")
77
78 # release() takes it back off the canvas and hands it to you.
79 released = workstation.release("subject", store="objects")
80 assert released is greeter
81 assert "subject" not in workstation.describe_bindings()["objects"]
82 print("released 'subject' from objects; methods copy untouched:",
83 "subject" in workstation.describe_bindings()["methods"])
84
85 print()
86 print("the canvas holds; the command system resolves. separate jobs.")
87 print("weak when asked, never by accident - refuse instead of degrade")
Runnable examples๏
The workstation canvas โ Advanced 12
Static vs capability authority โ Advanced 11