Formats vaelii reads and does not write, and the plugin seam they arrive through.
A foreign reader is a bridge, not a feature: an engine-dialect dump and a translated
OpenCyc corpus are how knowledge that predates this build gets in, and each one is
finished the day its corpus has been converted once into the format we do write
(vaelii.impl.io.export). Carried in-tree it would be code that must keep compiling,
keep passing tests, and keep being read by whoever changes a record shape, in exchange
for nothing. So no reader ships here. This engine reads its own dump format and
nothing else, and the bridges are separate artifacts that teach it a format when
they are on the classpath — vaelii-foreign is the one we publish.
It ships a namespace holding a reader var and one resource, vaelii/foreign.edn,
which is a map of kind -> the var holding its reader map:
{:engine-dump vaelii.foreign.engine/reader
:cyc-corpus vaelii.foreign.cyc/reader}
Every copy of that resource on the classpath is read and merged, so a build reads the
union of the bridges it was given and several plugins compose without knowing about
each other. A manifest is edn, so it declares a name and can never run code, and
the symbols in it are resolved with requiring-resolve on use — a plugin's
namespaces are loaded when something actually asks for its format, and no reference to
one exists in this build's compile-time graph. register is the same registration
done in code, for an embedding application that has the reader in hand.
Nothing else in this repo names a reader namespace, and nothing here has to change to
add or drop a format. A build with no plugin refuses a foreign dump or corpus by
name instead of half-reading it, which is this file's job.
foreign_contract_test is what keeps all of that true.
A caller asks by kind and gets a map of functions, or nil:
(when-let [r (foreign/reader :engine-dump)] ((:decode-frame r) frame))
((:load-dir! (foreign/reader! :cyc-corpus)) kb path opts)
reader for a path that has a fallback (the importer reads its own dialect either
way), reader! for one that does not (there is no other way to load a corpus). What
a reader map holds is the reader's own business — the seam carries capability, not a
protocol, because two foreign formats have nothing in common but being on the way
out.
Formats vaelii **reads and does not write**, and the plugin seam they arrive through.
A foreign reader is a bridge, not a feature: an engine-dialect dump and a translated
OpenCyc corpus are how knowledge that predates this build gets in, and each one is
finished the day its corpus has been converted once into the format we do write
(`vaelii.impl.io.export`). Carried in-tree it would be code that must keep compiling,
keep passing tests, and keep being read by whoever changes a record shape, in exchange
for nothing. So no reader ships here. This engine reads its own dump format and
nothing else, and the bridges are **separate artifacts** that teach it a format when
they are on the classpath — `vaelii-foreign` is the one we publish.
## What a plugin does
It ships a namespace holding a `reader` var and one resource, `vaelii/foreign.edn`,
which is a map of `kind -> the var holding its reader map`:
{:engine-dump vaelii.foreign.engine/reader
:cyc-corpus vaelii.foreign.cyc/reader}
Every copy of that resource on the classpath is read and merged, so a build reads the
union of the bridges it was given and several plugins compose without knowing about
each other. A manifest is **edn**, so it declares a name and can never run code, and
the symbols in it are resolved with `requiring-resolve` **on use** — a plugin's
namespaces are loaded when something actually asks for its format, and no reference to
one exists in this build's compile-time graph. `register` is the same registration
done in code, for an embedding application that has the reader in hand.
Nothing else in this repo names a reader namespace, and nothing here has to change to
add or drop a format. A build with no plugin refuses a foreign dump or corpus **by
name** instead of half-reading it, which is this file's job.
`foreign_contract_test` is what keeps all of that true.
## Asking for a reader
A caller asks by kind and gets a map of functions, or nil:
(when-let [r (foreign/reader :engine-dump)] ((:decode-frame r) frame))
((:load-dir! (foreign/reader! :cyc-corpus)) kb path opts)
`reader` for a path that has a fallback (the importer reads its own dialect either
way), `reader!` for one that does not (there is no other way to load a corpus). What
a reader map holds is the reader's own business — the seam carries capability, not a
protocol, because two foreign formats have nothing in common but being on the way
out.(available? kind)Can this build read kind? For a caller deciding what to offer — the catalog does
not list a KB nothing here can load.
Can this build read `kind`? For a caller deciding what to *offer* — the catalog does not list a KB nothing here can load.
(formats)Every format this build can be asked for: kind -> the var holding its reader map.
Resolved on use, so an entry naming a namespace that is not here is not an error — it
is a plugin that has gone, or one whose jar is missing.
Every format this build can be asked for: `kind -> the var holding its reader map`. Resolved on use, so an entry naming a namespace that is not here is not an error — it is a plugin that has gone, or one whose jar is missing.
The classpath resource a plugin declares its formats in. Every copy of it is read, so the name is fixed and the plugin's own coordinates are its business.
The classpath resource a plugin declares its formats in. Every copy of it is read, so the name is fixed and the plugin's own coordinates are its business.
(reader kind)The reader map for kind, or nil when nothing on this classpath reads it.
Resolved through requiring-resolve, which is what keeps the reference out of the
compile-time dependency graph.
The reader map for `kind`, or **nil** when nothing on this classpath reads it. Resolved through `requiring-resolve`, which is what keeps the reference out of the compile-time dependency graph.
(reader! kind)The reader map for kind, or throw — naming the kind, and what this build does read.
For a path with no fallback.
The reader map for `kind`, or throw — naming the kind, and what this build does read. For a path with no fallback.
(register kind sym)Declare that sym — a qualified symbol naming a var that holds a reader map — reads
kind, in code rather than through a manifest. Wins over discovery, and returns the
full registry.
Declare that `sym` — a qualified symbol naming a var that holds a reader map — reads `kind`, in code rather than through a manifest. Wins over discovery, and returns the full registry.
(rescan)Forget the cached classpath scan, so the next lookup reads the manifests again.
Forget the cached classpath scan, so the next lookup reads the manifests again.
(unregister kind)Drop a registration register made. A format a manifest also declares stays
readable — this undoes the call, not the classpath.
Drop a registration `register` made. A format a manifest also declares stays readable — this undoes the call, not the classpath.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |