Module: Hecks::Bluebook::DSL::AttributeCollector
- Included in:
- AggregateBuilder, CommandBuilder, EntityBuilder, PortOperationBuilder, QueryBuilder, ValueObjectBuilder
- Defined in:
- lib/hecks/bluebook/dsl/attribute_collector.rb
Defined Under Namespace
Instance Method Summary collapse
-
#attribute_impl(name, type = UNSET, default: nil, optional: false, pattern: nil, admits: nil, one_of: nil) ⇒ Object
admits:names a closed set that is ALREADY DECLARED elsewhere —. - #attributes ⇒ Object
-
#closed_sets ⇒ Object
Value objects synthesised from inline closed sets, collected here and installed by whoever owns value objects (the aggregate).
-
#list_of_impl(type) ⇒ Object
RENAMED FROM
list_of— item #13's full metaprogrammed dispatch (slice 5). -
#one_of_impl(*values) ⇒ Object
A closed set declared INLINE on the attribute:.
Instance Method Details
#attribute_impl(name, type = UNSET, default: nil, optional: false, pattern: nil, admits: nil, one_of: nil) ⇒ Object
admits: names a closed set that is ALREADY DECLARED elsewhere —
attribute :op, String, admits: "Vocabulary::QueryComparator"
which is the difference between it and one_of: one_of SYNTHESISES
a fresh value object named for the attribute, so it can only ever name
something new. admits points at a set the language already holds, so
the same set can be named from many places without being written twice.
QUALIFIED, because a closed set is a value object INSIDE an aggregate
and reference_to reaches heads only — so this is text, checked where
it is read rather than by reference resolution.
AND WRITTEN AS TEXT, not as the constant path Vocabulary::QueryComparator
it reads like. The constant spelling was tried — ConstShim returning
a Module so Ruby's :: reaches a second const_missing — and it
cannot hold: Facade::Surface installs every aggregate name as a
TOP-LEVEL constant, so the moment any facade exists, Vocabulary
resolves to that module and the shim is never asked. A spelling that
works only until a facade is built is worse than a quoted one.
THE TYPE POSITION TAKES A BARE CONSTANT, ALWAYS REQUIRED (ADR 0025,
"Attributes") — omitting it (a mint default of String) and quoting
it as text both refuse now. Neither had a real reason left: no
corpus attribute ever omitted the type, and ConstShim#const_missing
(S0b) already resolves a bare, not-yet-declared constant to the
SAME forward reference the quoted form existed for — a bareword
Name reaches a value object named "Name" declared later in the
same block exactly as "Name" used to, spell's own to_s
renders either one identically. Neither form appears in any frozen
era text (checked directly), so both are refused unconditionally —
nothing for MetaValidator.shadow_parsing? to answer for.
RENAMED FROM attribute — item #13's full metaprogrammed
dispatch (slice 3, whole-project table-unification survey).
The word attribute itself is no longer a real method any
builder answers directly: every (context, word) Keyword row
for it carries calls: "attribute_impl", and GenericDispatch
forwards the whole call here untouched — this method's own
body is exactly what attribute always was, unchanged, just
reached generically now rather than by Ruby's own direct
method lookup. attribute_collector_spec.rb (AttributeCollector has no method without a test — dsl_coverage_spec.rb) and the
bootstrap fallback (GenericDispatch::BOOTSTRAP_CALLS_FALLBACK) both
name this same string; they must never drift apart.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/hecks/bluebook/dsl/attribute_collector.rb', line 61 def attribute_impl(name, type = UNSET, default: nil, optional: false, pattern: nil, admits: nil, one_of: nil) # moved to the language: FieldName invariant, on Root.Attribute if type.equal?(UNSET) raise Malformed, "#{name} declares no type — attribute :#{name}, SomeType is required, " \ "there is no default" end # `list_of("X")` carries the same quoted text one level down — a # bare constant is required there too, checked before it unwraps # below, not after (once unwrapped, a plain String in the `type:` # slot looks identical to one that legitimately belongs there). quoted = type.is_a?(ListOf) ? type.type : type if quoted.is_a?(::String) raise Malformed, "#{name}'s type #{quoted.inspect} is quoted text — give the bare constant " \ "(#{quoted}) instead; a forward reference to a value object declared later " \ "in the same block already resolves without quoting" end refuse_unshared_pattern(name, pattern) if pattern type = synthesise_closed_set(name, type) if type.is_a?(OneOf) list = type.is_a?(ListOf) attributes << Attribute.new( name: name, type: list ? type.type : type, list: list, default: default, optional: optional, pattern: pattern, admits: admits ) install_inline_closed_set(name, one_of) if one_of end |
#attributes ⇒ Object
11 |
# File 'lib/hecks/bluebook/dsl/attribute_collector.rb', line 11 def attributes = @attributes ||= [] |
#closed_sets ⇒ Object
Value objects synthesised from inline closed sets, collected here and installed by whoever owns value objects (the aggregate).
15 |
# File 'lib/hecks/bluebook/dsl/attribute_collector.rb', line 15 def closed_sets = @closed_sets ||= [] |
#list_of_impl(type) ⇒ Object
RENAMED FROM list_of — item #13's full metaprogrammed
dispatch (slice 5). Called in an attribute's own TYPE
position (attribute :x, list_of(Y)), never through a def list_of any ONE builder answers as its own word — reached
via WordGate#word_gate_dispatch's new "Type"-context
fallback, the same one one_of_impl below uses. Bootstrap-
reachable (every core chapter's own list-typed attributes use
it), so GenericDispatch::BOOTSTRAP_CALLS_FALLBACK carries a
SINGLE ["Type", "list_of"] entry rather than one per calling
context — the bootstrap branch checks that key too now, same
reasoning as the ordinary fallback.
109 |
# File 'lib/hecks/bluebook/dsl/attribute_collector.rb', line 109 def list_of_impl(type) = ListOf.new(type) |
#one_of_impl(*values) ⇒ Object
A closed set declared INLINE on the attribute:
attribute :status, one_of("open", "shut")
Desugars to a value object named for the attribute, so it goes through exactly the machinery a hand-written one_of does — and so the attribute's type is still a DECLARED value object, which is now a structural rule rather than a predicate.
An earlier reading of this spelling parsed it and threw the values
away: the attribute became a plain String and the closed set meant
nothing, in a construct that looked supported. The desugaring is
pinned now — the same bluebook must always yield the same IR.
RENAMED FROM one_of — item #13's full metaprogrammed dispatch
(slice 5), same reasoning as list_of_impl above. SAME NAME as
ValueObjectBuilder#one_of_impl's own override on purpose —
that method's own super(*values) call (the no-block, bare
type-position case) resolves by METHOD NAME up the ancestor
chain, and renaming only one side would silently break it.
154 |
# File 'lib/hecks/bluebook/dsl/attribute_collector.rb', line 154 def one_of_impl(*values) = OneOf.new(values) |