Module: Hecks::Bluebook::DSL::WordGate
- Included in:
- AdapterBuilder, AggregateBuilder, BluebookBuilder, CommandBuilder, DomainPortBuilder, EntityBuilder, HecksagonBuilder, LifecycleBuilder, PolicyBuilder, PortBuilder, PortOperationBuilder, ProcessManagerBuilder, ProcessManagerBuilder::HandlerBuilder, QueryBuilder, ReadModelBuilder, TranslationAggregateBuilder, TranslationBuilder, ValueObjectBuilder, WorldBuilder
- Defined in:
- lib/hecks/bluebook/dsl/word_gate.rb
Overview
THE RUBY-SIDE word_gate (rust/parser/src/parse/mod.rs's own,
read there first — this is the same job, one level up: Rust's own
gate refuses a mistyped/inadmissible WORD directly, at the
moment it reads a line of .bluebook SOURCE TEXT, before any
per-construct parsing runs. Ruby never lexes source text — a
.bluebook file IS Ruby, so given("x") is ALREADY a real
method call by the time any of this code runs, and Ruby's own
method dispatch already refuses an ARITY mismatch on an
EXISTING method for free. What Ruby's own dispatch does NOT do
is consult the self-hosted grammar table AT ALL — a mistyped
word (giv3n("x")) or a word used in the wrong context
(identified_by inside a command block) just raises Ruby's
own generic NoMethodError, naming nothing about what the
language actually admits. This module closes that gap.
method_missing/respond_to_missing? ONLY — a word this
builder class already answers with an ordinary def (or a
shared mixin method like AttributeCollector#attribute) never
reaches this module at all; Ruby's own method lookup finds it
first, and item #13's later slices haven't removed every one of
those yet. This WAS "zero behavior change for every currently-
valid line in the entire corpus" in its own first slice — since
item #13's full metaprogrammed dispatch (slice 1, whole-project
table-unification survey) started REMOVING the hand-written
methods this module's own admissibility check used to defer to,
some words now execute for real here too, via GenericDispatch
— see that module's own header for exactly which ones, and the
full account of what was verified before each was migrated. A
mistyped or wrongly-contexted word still gets the same real,
helpful, table-driven refusal Rust's own word_gate already
gives, instead of Ruby's own generic NoMethodError — that half
is genuinely unchanged.
self.class::GRAMMAR_CONTEXT — each including class names which
row of the self-hosted Context closed set it corresponds to
(AggregateBuilder::GRAMMAR_CONTEXT = "Aggregate", etc.) — the
SAME string word_gate's own context parameter already is on
the Rust side, read off the identical table.
BOOTSTRAPPING GATED, the same reason RuleReference#lookup
already is (rule_reference.rb's own comment has the full
story) — the meta-domain's own bootstrap calls dozens of
keywords on itself before its own grammar table exists to
check them against. For most words, this module steps aside
entirely during bootstrap (super, Ruby's own ordinary
NoMethodError) — the exact behavior every builder already had
before this module existed, and (unlike RuleReference) there
is deliberately no fallback covering the whole ~200-row table —
that would defeat the entire point.
ONE NARROW EXCEPTION, added in item #13's full metaprogrammed
dispatch (slice 3, whole-project table-unification survey):
GenericDispatch::BOOTSTRAP_CALLS_FALLBACK, a SMALL, EXPLICIT
table naming the same (context, word) -> method pairs the real
calls: column would say once it exists — used ONLY for words
BOTH migrated to the calls: shape AND bootstrap-reachable
(attribute, today). This is the one place in this whole arc a
bootstrap fallback was worth building despite RuleReference's
own precedent against it: it duplicates NO logic, only a METHOD
NAME — attribute_impl's own real, hand-written body is called
either way, bootstrap or not, so there is nothing here that can
drift the way a full behavioral duplicate could.
TWO FURTHER PIECES, both slice 5:
- `word_gate_dispatch` is the same admission+dispatch logic
`method_missing` below runs, factored out so a class with
its OWN class-level `method_missing` (`HecksagonBuilder`'s/
`WorldBuilder`'s genuinely open-ended verb vocabulary) can
call it directly and fall back to its own open-verb handling
only when this returns `NOT_ADMITTED` — a class-level `def`
always wins over an included module's in Ruby's own method
resolution, so their OWN `method_missing` is the only one
that ever runs for them, and this is what lets a real,
closed-set word (`port`/`realm`/`latest`) still reach
`GenericDispatch` despite that.
- the "Type"-position fallback inside `word_gate_dispatch`
itself, for `one_of`/`list_of` — called inside an
attribute's own type argument, with `self` as whatever
builder is currently `instance_eval`ing, never a dedicated
"Type" builder `self.class::GRAMMAR_CONTEXT` could ever
name. See that method's own comment.
Constant Summary collapse
- NOT_ADMITTED =
A caller with its OWN class-level
method_missing(HecksagonBuilder/WorldBuilder— seeword_gate_dispatch's own header) checks for this to tell "not a word the grammar admits at all" apart from every other outcome below (a real dispatch, or a raised refusal) — never raised itself, so a caller can fall through to its own open-ended handling instead. Object.new.freeze
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(word, *args, **kwargs, &block) ⇒ Object (private)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/hecks/bluebook/dsl/word_gate.rb', line 105 def method_missing(word, *args, **kwargs, &block) if MetaValidator.bootstrapping? fallback = GenericDispatch::BOOTSTRAP_CALLS_FALLBACK # Own context first, "Type" second — the same order the # ordinary (non-bootstrapping) `word_gate_dispatch` path # below checks them in, for the same reason: `list_of`/ # `one_of` used in an attribute's own type position never # arrive with `self.class::GRAMMAR_CONTEXT == "Type"`. target = fallback[[self.class::GRAMMAR_CONTEXT, word.to_s]] || fallback[["Type", word.to_s]] return send(target, *args, **kwargs, &block) if target return super end result = word_gate_dispatch(word, args, kwargs, block) return super if result.equal?(NOT_ADMITTED) result end |