Module: Hecks::Bluebook::DSL::IdentityDeclaration
- Included in:
- AggregateBuilder, EntityBuilder
- Defined in:
- lib/hecks/bluebook/dsl/identity_declaration.rb
Overview
identified_by — SHARED by AggregateBuilder and EntityBuilder
only (S9, ADR 0025 — "EntityBuilder's duplicate identified_by and
resolve_pending_identity! go"): a piece's own identity cannot
spell differently from its aggregate's, and until this slice it
was hand-duplicated onto both rather than shared.
A SEPARATE MODULE from AttributeCollector on purpose — every
attribute()-taking builder (Command, Query, PortOperation,
ValueObject, ...) includes that one too, and none of THEM
declares an identity of its own ; folding identified_by in
there made it answer for six builders that never earned the
word (syntax_conformance_spec.rb catches exactly this — a
builder answering a method the grammar never grants it).
Requires its includer to ALSO include AttributeCollector
(for attributes/resolve_identity_field!/resolve_identity_ type!, still declared there since every includer of THAT
module needs them) and to supply identity_pool (private) —
the value-object list a bare field's own type resolves
against: AggregateBuilder's own @value_objects + closed_sets,
or EntityBuilder's OWNER's, since a piece mints none of its own.
Instance Method Summary collapse
-
#identified_by_impl(*targets, as: nil, &definition) ⇒ Object
There are three live forms, deliberately distinguishable at the declaration site:.
Instance Method Details
#identified_by_impl(*targets, as: nil, &definition) ⇒ Object
There are three live forms, deliberately distinguishable at the declaration site:
identified_by AccountNumber, as: :number # one identity concept
identified_by do ... end # a bespoke concept
identified_by :branch, :number # an existing compound key
One symbol is retired: it cannot say whether the author means a
value concept or a field-shaped database key. Frozen source still
reaches the old interpretation through legacy_identified_by.
RENAMED FROM identified_by — item #13's full metaprogrammed
dispatch (slice 4c), same shared-mixin shape attribute_impl
already proved in slice 3: ONE renamed method, both Aggregate
and Entity Keyword rows name it in calls:. Bootstrap-
reachable (every self-hosted aggregate/entity declares an
identity), so in BOOTSTRAP_CALLS_FALLBACK for both contexts.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/hecks/bluebook/dsl/identity_declaration.rb', line 42 def identified_by_impl(*targets, as: nil, &definition) return legacy_identified_by(*targets, as: as, &definition) if MetaValidator.shadow_parsing? refuse_second_identity! if definition raise Malformed, "#{@name}.identified_by cannot combine a value-object type with a block" unless targets.empty? type_name = identity_value_object_name value_object = begin ValueObjectBuilder.build( type_name, owner_value_objects: identity_pool, &definition ) rescue NameError => error # A REMOVED SPELLING MUST REFUSE LOUDLY, not degrade into a raw # Ruby error — the one contract `EraGuard.shadow_parse` leans # on to know a normal parse genuinely could not read this text # (only `Malformed` triggers its shadow-mode retry, era_guard.rb's # own comment). The OLD `identified_by { name.value }` — a block # whose text was NEVER CALLED, only extracted (legacy_ # identified_by, below) — is exactly this shape: read under the # CURRENT grammar it is instead instance_eval'd as a value-object # DEFINITION, and a bare identifier like `name` inside it resolves # to nothing WordGate#method_missing recognizes, so Ruby itself # raises NameError. Left uncaught, that NameError skipped # shadow_parse's rescue entirely and reached callers as a raw # crash instead of the frozen-era fallback that exists for # precisely this text. raise Malformed, "#{@name}.identified_by do ... end could not be read as a value-object " \ "definition: #{error.}" end if value_object.attributes.empty? raise Malformed, "#{@name}.identified_by do declares no identity attributes" end install_identity_value_object!(value_object) @identity_type_pending = [value_object, as || :identity, attributes.size] return end raise Malformed, "#{@name}.identified_by names no identity" if targets.empty? if targets.one? && identity_type?(targets.first) @identity_type_pending = [targets.first, as, attributes.size] return end if targets.one? field = targets.first raise Malformed, "#{@name}.identified_by takes no as: — name the declared field itself" if as # Transitional compatibility: the self-hosted language and live # corpus still contain this form. Keep it readable until their # exemplar-led migration is complete; the final lifecycle cutover # replaces this assignment with the targeted refusal. @identity_field_pending = field return end unless targets.all? { |target| !identity_type?(target) } raise Malformed, "#{@name}.identified_by takes one value-object type or two or more attribute names, not both" end raise Malformed, "#{@name}.identified_by compound keys take no as:" if as @identity_fields_pending = targets end |