Codegen meta-model — paste blocks
Table of Contents
This page is the concept note for paste blocks, applicable to any
metaclass's segments, not only Entity's. It is ORE Studio's extension
to the MASD logical model: Physical Space already has a notion of
protected regions (see § "Protected regions" below), but as a
mechanism belonging to physical space, scanned from generated output.
ORE Studio instead models a paste block as a field on the logical
metaentity itself — a segment composes zero or more PasteBlock
instances, each with its own kind ID, the same way it composes any
other typed field:
This page explains the mechanism once; every segment page that has concrete block kinds (SQL, Repository, Service, Protocol, NATS, Qt, Generator) links back here instead of re-explaining it, and hosts its own block kinds inline rather than in one central registry — a Repository paste block belongs on the Repository page, not in a separate index, because you need it while reading about the repository facet, not some other time.
Physical model mapping
Paste blocks are not a segment themselves — this page is a concept
note, not a hub-and-spokes segment page — so there is no facet of
its own to map to here. A paste block exists within a segment (see
each segment's own structural diagram, e.g. SQL's SqlSchemaExtraDropStatements),
and it is that owning segment's facet the content ultimately projects
into. See "Finding a block kind" below for which segment page (and
therefore which facet) hosts each concrete block kind.
Terminology: this is a protected region
"Paste block" is not a MASD concept — it is ORE Studio's
project-specific name for an instance of the formally-named MDE
mechanism, the Physical Space § "Protected regions", the same naming
mismatch already flagged for stereotype metatype (see Applied
MASD's note on that). Read that section first for the general
mechanism, the tool-naming survey across XPand/Acceleo/EGL/JET
MOFScript, and the formal comparison this is drawn from
(Greifenberg et al. 2015).
One thing worth being precise about: ORE Studio's paste blocks are
not the classic protected-region implementation described there.
The classic mechanism is a round-trip one — the generator scans
the previous generated output for marker comments, extracts
whatever handwritten content it finds inside them, and reinserts it
into the newly generated file; this is exactly the mechanism whose
known drawback is an unstable/non-unique marker ID silently losing
content, because the source of truth for the handwritten content is
the generated file itself. ORE Studio's paste blocks invert this:
the handwritten content lives in the entity model (the .org
file), never in generated output, and codegen does a one-directional,
stateless substitution — render the template, then regex-replace
<<paste:UUID>> markers with content read straight from the model.
There is no "scan the old output" step and nothing to lose on
regeneration, because generated output is never the source of truth
for anything. Whether this project-specific variant deserves its own
name distinct from "protected region," or whether "paste block" should
just be retired in favour of a MASD-aligned term for it, is an open
question — not decided on this page.
Why the mechanism exists
Most of a generated file is fully templated: given the entity's fields and knobs, the output is fully determined. But some code is genuinely entity-specific and cannot be derived from the model — a bespoke query method, a custom NATS message type, a hand-written constructor initialiser. Rather than making that entity's file partially hand-written (losing regeneration safety for the whole file), codegen defines fixed slots inside its templates that an entity model may fill with verbatim code. The generated file stays 100% regenerable; only the slot's content is entity-authored.
The two levels of identity
A block kind is the slot itself — a concept, like an interface.
It has a stable UUID, declared once by whichever segment page owns
it, and referenced by that facet's templates via a
<<paste:UUID>> marker.
A block instance is one entity's concrete filling of that slot —
like a class implementing an interface. Its own :ID: is per-entity,
per-block; many entities may implement the same kind, each with a
different instance UUID for their own copy.
This split means templates and entity files never need to coordinate UUID changes: a template references a fixed kind UUID forever; each entity file independently declares what it implements.
How an entity attaches a block
Inside the entity model, a sub-heading under the relevant section
(e.g. ** Custom service methods under * C++) carries a babel
block whose :implements: header argument names the kind UUID:
** Custom service methods #+begin_src cpp :name declaration :implements 2D4EA0F9-6AF6-45A5-A959-F672BF866C6A , std::vector<domain::country> list_countries_for_party( , const boost::uuids::uuid& party_id, , std::uint32_t offset, std::uint32_t limit); #+end_src
The babel block's :name (declaration above) is for human/Emacs
navigation only — :implements is what codegen actually reads.
How the marker resolves
Codegen is a post-rendering substitution pass: mustache renders the
whole template first, using the entity's ordinary fields and knobs;
then a regex pass replaces every <<paste:UUID>> marker with the
concatenated bodies of every sub-heading in the current entity whose
:implements: matches that UUID. If no sub-heading implements a
given kind, the marker is replaced with an empty string (and a
single trailing newline collapses), so an entity that needs none of
a facet's paste blocks produces exactly the same output as if the
markers weren't there.
The well-known babel block name inside an implementing sub-heading is
body for a single free-form insertion. Some kinds instead expect
declaration=/=implementation pairs (a header slot and a matching
.cpp slot for the same custom method) — each segment page states
which name(s) its kinds expect.
Finding a block kind
Concrete block kinds are documented on the segment page for the facet whose generated file they inject into:
- SQL — extra
DROPstatements. - C++ Repository — extra member declarations, out-of-class implementations,
.cppincludes. - C++ Service — extra includes, custom public methods, extra private members, constructor init,
.cppimplementations. - C++ Protocol — custom message includes and types.
- C++ NATS — handler early-exit override, extra includes, custom methods, extra private members.
- C++ Qt — detail-dialog hierarchy tree seam, private members, header includes, composite child-entity tables seam, entity-set load hook.
- C++ Generator — custom declarations and implementations.
See also
- Codegen org-entity meta-model — the hub this page is a segment of.
- Physical Space § "Protected regions" — the formal MDE concept this page's mechanism is a project-specific instance of.
- Greifenberg et al., A Comparison of Mechanisms for Integrating Handwritten and Generated Code for Object-Oriented Programming Languages (2015) — the formal comparison across tools/mechanisms.