Module: Hecks::Bluebook::DSL::WordGate

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 — see word_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