Syntax Reference¶
ZOTI-YAML sources are files following the YAML 1.1 language specification. To aid organizing information into separate libraries and modules, ZOTI-YAML provides a set of language extensions, such as references and a module system.
Modules¶
Modules are the main organization units in ZOTI-YAML projects. Each
module name needs to reflect the path of its associated source
file. Assuming that a path NY_PATH
is in the search path, then the
file MY_PATH/path/to/MyModule.yaml
would correspond to the qualified
module name path.to.MyModule
. The search path can be controlled via:
the CLI flag
--pathvar
, see Configuration;the API, with the constructor for
zoti_yaml.handlers.Project
.
Each module consists in a YAML source file formatted as:
preamble
---
document
where preamble
contains directives, such as import declarations,
descriptions or other document-wide definitions, whereas
document
contains the actual source code.
Preamble¶
A module’s peramble is for the most part a free-form dictionary containing metadata preserved and used by downstream tools. ZOTI-YAML uses two of these entries:
module
(string)Mandatory field containing the qualified module name. It needs to reflect its path relative to the loading path, otherwise an error is raised upon its loading.
import
(list)List of imports. Each entry is a dictionay:
module
:(string) qualified name of module being imported.
as
:(string) short alias used in the document.
Document¶
Commands¶
ZOTI-YAML documents are regular YAML files that might contain some additional keywords followed by certain arguments, as documented below.
!default
[defaults, originals]¶
This keyword is followed by a list of exactly 2 YAML objects (i.e.,
trees), defaults and original. When the document tree is being
resolved, it recursivvely fills in the contents of original
according to the values in defaults recursively, based on the
active merge policy (see !policy:<merge_policy>
). The default
merge policy is !policy:union
.
A policy is a marked YAML node in the defaults tree, and is active from that node to all its childred until the last leaf node or until a node with a policy changing marker. E.g.:
!default
- !policy:A
root: # policy A holds
- foo: bar # policy A holds
- !policy:B
biz: # policy B holds
- baz # policy B holds
- buzz # policy B holds
- bam: blep # policy A holds
- root: ...
Example:
!default
- root:
- !policy:intersect
foo:
a: this is superseded by original
b: !policy:union+replace this supersedes the original
c: this will be ignored
d: !policy:union this is created
- bar: this is ignored (only the first element in a list in !defaults matters)
- root:
- foo:
a: this supersedes the default value
b: this is superseded by the default value
- foo:
d: this supersedes the default value
resolves to:
root:
- foo:
a: this supersedes the default value
b: this supersedes the original
d: this is created
- foo:
b: this supersedes the original
d: this supersedes the default value
!policy:<merge_policy>
any¶
Policy dictating how the defaults object is to be recursively
merged in originals (see !default
). The current policies are:
union
performs the union between originals and defaults where originals have priority if the same key is found.
union+replace
performs the union between originals and defaults where defaults have priority if the same key is found.
intersect
ignores fields from defaults whose keys are not explicitly found in originals. originals have priority when the same key is found.
intersect+replace
ignores fields from defaults whose keys are not explicitly found in originals. defaults have priority when the same key is found.
!ref
{module, path | name}¶
Reference to an element in a module. When resolved, this object contains the qualified name or path to a (unique) element. It may have the following keyword arguments:
- module: (optional, string)
A module name or an alias. It resolves to an explicit name. If none is specified it is assumed to be the current module.
- path: (mutually exlusive with name, string)
A path to an element in the tree (see
zoti_yaml.core.TreePath
).- name: (mutually exlusive with path, string)
An identifier of the element in a certain module.
The type of the reference depends on which tool in the downstream
uses it. If the tool works with, e.g. JSON trees (similar to
ZOTI-YAML) then specifying path is more reasonable as it is
being constructed into a zoti_yaml.core.TreePath
handler. However, if the tool works with other type of element
identifiers, name should be used, as it preserves the string for
downstream manipulation.
Example:
module: Foo
import: {module: Foo.Bar, as: Baz}
---
root:
- ref1: !ref {path: ../../ref2}
- ref2: !ref {module: Baz, name: "egg"}
resolves to:
module: Foo
import: {module: Foo.Bar, as: Baz}
---
root:
- ref1: {module: Foo, path: ../../ref2}
- ref2: {module: Foo.Bar, name: "egg"}
!attach
{ref, …}¶
Attaches a referenced node at the current location. This command can have any number of keyword arguments, of which one needs to be ref.
- ref: (object) Qualified
zoti_yaml.core.TreePath
-based reference to another node (see
!ref
). If the pathbegins with character
/
, it is absolute (i.e. relative to the root of the module)begins with a character other than
/
, it is relative to this node.
- …: (keyword pairs)
Arbitrary entries passed to the attached node in the following conditions:
if the attached node is not an object (i.e. dictionary), these entries are ignored;
if the attached node is an object but does not contain the said entry, it is ignored;
if the attached node is an object and contains the said entry, the argument entry replaces the original one. The original entry is stored at path
_info/_prev_attrs
underneath the attached node.
OBS1: If both the parent and referenced nodes contain positional
information, this will be captured in the _info/_pos
entry,
whose head will point to the original position of the referenced
node.
OBS2: !ref
commands are resolved before !attach
, thus
they can be used to construct references.
OBS3: when exchanging arguments between the caller and callee it
is recommended to use a dedicated field (e.g., check the
argfields argument of zoti_yaml.handlers.Project
)
Example:
module: Foo
---
root:
!attach
ref: {module: Bar, path: /root[bar]/refd}
a: this replaces the original
b: this is ignored
module: Bar
---
root:
- name: bar
refd:
a: this is replaced
c: this is carried from the original
resolves to:
module: Foo
---
root:
a: this replaces the original
c: this is carried from the original
Module Bar
remains unchanged.
!include
{file, name | (begin, end)}¶
One can import raw (chunks of) files using the the !include
command. It should be used to attach entire source code to
entries of certain nodes. Usage:
!include {file: path/relative/to/module.ext}
!include {file: path/relative/to/module.ext, name: block_name}
!include {file: path/relative/to/module.ext, begin: (keyword|number), end: (keyword|number)}
In the first case an entire file is included as raw text. In
the second case it extracts the portion of text between the
lines containing BEGIN block_name
and END
block_name
. In the third case the start and stop lines are
specified either as line numbers or by arbitrary keywords.
Position Information¶
In addition to the explicit behavior controlled with
commands, ZOTI-YAML implicitly stores positional metadata
for certain keys under an entry at _info/_pos
. Exactly which nodes
are marked for metadata is controlled via:
the CLI flag
--keys
, see Configuration;the API, with the constructor for
zoti_yaml.handlers.Project
.
For each key in the provided list, ZOTI-YAML will mark all first
children of its entry, provided that the children are objects
themselves. For example, if keys
is set to ["root", "node"]
, here
is how a processed yaml file could look like:
root:
- name: a # marked, child of "root"
_info: {_pos: ...}
foo:
node:
- name: b # marked, child of "node"
_info: {_pos: ...}
- bar: baz # marked, child of "node"
_info: {_pos: ...}
- name: b # marked, child of "root"
_info: {_pos: ...}
foo: bar
- baz # not marked, not an object
The positional metadata at _info/_pos
is presented as a list of
entries containing positional information. The last entry in a list
corresponds to the current position in the file. Every time a (marked)
node is parsed by ZOTI-YAML its current position is appended at the
end of the list. This mean that certain nodes can be “handed over”
between tools, and ZOTI-YAML will keep the history of their positions
(e.g. in intemediate files). In the following example the shown node
has been pre-processed by ZOTI-YAML in preparation for two other tools
(ZOTI-Graph and ZOTI-Gen), and its information has resided in two
different files.
_info:
_pos:
- [36, 14, 1066, 1220, app/ProdCons/Src.zog, zoti-graph-0.1.0]
- [20, 8, 740, 906, gen/graph/ProdCons.yaml, zoti-gen-0.1.0]
Check the API Reference for what each field means.
Configuration¶
The CLI tool can be run like any Python module depending on how it is
distributed. Configuration arguments are documented by passing
--help
. Each configuration parameter can be specified also in a
TOML file called zoticonf.toml
found in the
current folder, under the following sections:
[zoti]
# global configuration variables, read by all tools
[zoti.yaml]
# configuration variables for ZOTI-YAML. override global ones
[zoti.yaml.<class>]
# specialized configuration loaded with:
#
# $(ZOML) --spec <class>
#
# where <class> is replaced with an arbitrary name. Overrides
# parameters in [zoti.yaml]