Module: Hecks::Projector::Target
- Included in:
- Hecks::Projections::Diagrams, Hecks::Projections::Model, Hecks::Projections::OIDC, Hecks::Projections::ParserTable, Hecks::Projections::Reference, Hecks::Projections::Shape, Hecks::Projections::Statements, Hecks::Projections::Vocabulary
- Defined in:
- lib/hecks/projector/target.rb
Overview
WHAT MAKES A MODULE A PROJECTION TARGET. Projector.register has
always accepted anything answering call(bluebook:, options:) —
this only removes the second step, so a target declares its own key
beside its own implementation instead of being registered from
somewhere else that has to be kept in sync with it.
module Hecks::Projections::OIDC
extend Hecks::Projector::Target
projects_as :oidc
module_function
def call(bluebook:, options: {}) = { ... }
end
NAMED Target, NOT Projection, on purpose. "Projection" already
means two other things in this codebase: Ports::Projection is
read-model catch-up (events folded into view state), and bin/project
forces that catch-up by hand. Neither has anything to do with
"canonical IR in, external artifact out". A third meaning under the
same word would make the two impossible to grep apart — and from a
domain's point of view project(X) really does read as "project TO
a target", so the narrower word is also the more accurate one.
Instance Method Summary collapse
-
#projection_declares ⇒ Object
Empty means "a chapter" — resolved HERE rather than as a default argument, because Behaviour::Chapter is not loaded yet when this file is.
- #projection_emits ⇒ Object
- #projection_key ⇒ Object
- #projection_requires ⇒ Object
-
#projects_as(key, requires: nil, declares: nil, emits: :artifact) ⇒ Object
Registering at declaration time means
requireing a target is the whole of installing it — there is no separate manifest that can silently disagree about which targets exist.
Instance Method Details
#projection_declares ⇒ Object
Empty means "a chapter" — resolved HERE rather than as a default argument, because Behaviour::Chapter is not loaded yet when this file is.
87 |
# File 'lib/hecks/projector/target.rb', line 87 def projection_declares = @projection_declares || [] |
#projection_emits ⇒ Object
89 |
# File 'lib/hecks/projector/target.rb', line 89 def projection_emits = @projection_emits || :artifact |
#projection_key ⇒ Object
82 |
# File 'lib/hecks/projector/target.rb', line 82 def projection_key = @projection_key |
#projection_requires ⇒ Object
91 92 93 94 |
# File 'lib/hecks/projector/target.rb', line 91 def projection_requires req = @projection_requires req.nil? || req.empty? ? [Bluebook::Behaviour::Chapter] : req end |
#projects_as(key, requires: nil, declares: nil, emits: :artifact) ⇒ Object
Registering at declaration time means requireing a target is
the whole of installing it — there is no separate manifest that
can silently disagree about which targets exist.
requires: NAMES A CAPABILITY, not a shape word.
This began as from: :chapter / from: :any — two hand-kept
symbols, admitted by duck-typing on .aggregates, which is a
guess at what "is a chapter" means. The capabilities were already
real by then: Hecks::IR is the ability to emit IR (its own
header says so), and Behaviour::Chapter is the ability to answer
as a chapter. So a projection names the module it needs, and
admission is a genuine check rather than a proxy for one.
projects_as :ir, requires: Hecks::IR
projects_as :vocabulary # chapter, the default
It also composes: a projection needing two capabilities names both, instead of a third symbol being invented for the pair.
THE FAIL-QUIET THIS CLOSES, unchanged in substance: every
construct emits its own IR, so handing a projector an AGGREGATE
instead of a chapter is the natural thing to try. bluebook: was
only ever a PARAMETER NAME, never a contract. :oidc failed
loudly (no aggregates method), but :shape returned
{"name" => "Order", "aggregates" => []} — well-formed,
confident, and wrong.
declares: NAMES AN AGGREGATE THE CHAPTER MUST HAVE.
A capability says what a construct can DO; this says what it must
CARRY. :vocabulary needs a chapter declaring a Vocabulary
aggregate, :parser_table one declaring Syntax — and both used
to state that as a raise in their own body, which is a
requirement written as behaviour instead of declared. Stated
here, the registry refuses before the projection runs and the
projection stops carrying a guard about its own admission.
emits: SAYS WHAT KIND OF ARTIFACT COMES BACK.
:artifact (the default) is one thing — a Hash, or a String.
:files is a TREE: a Hash of relative path => contents, which is
what a reference-page or codegen projection produces.
Declared rather than sniffed, deliberately. Inferring a tree from
an ordinary Hash is guesswork — {"name" => "Pizzas"} is
indistinguishable from a one-file tree — so write asks what the
projection said rather than inspecting what it returned.
73 74 75 76 77 78 79 80 |
# File 'lib/hecks/projector/target.rb', line 73 def projects_as(key, requires: nil, declares: nil, emits: :artifact) @projection_emits = emits @projection_key = key.to_sym @projection_declares = Array(declares) @projection_requires = Array(requires) Projector.register(@projection_key, self) @projection_key end |