User Guide¶
Yaml Cheat Sheet¶
Usually YAML structure is denoted by indentation.
Quire Tricks¶
Underscore Names¶
Integers¶
Integers can be of base 10, just like everybody used to. It can also start
with 0x
to be interpreted as base 16, and if it starts with zero it is
interpreted as an octal number.
Units¶
A lot of integer values in configuration files are quite big, e.g. should be expressed in megabytes or gigabytes. Instead of common case of making default units of megabytes or any other arbitrary choice, quire allows to specify order of magnitude units for every integer and floating point value. E.g:
int1: 1M
int2: 2k
int3: 2ki
Results into the following, after parsing:
int1: 1000000
int2: 2000
int3: 2048
Note that there is a difference between prefixes for powers of 1024 and powers of the 1000.
The following table summarizes all units supported:
Unit | Value |
---|---|
k | 1000 |
ki | 1024 |
M | 1000000 |
Mi | 1048576 |
G | 1000000000 |
Gi | 1073741824 |
T | 1000000000000 |
Ti | 1099511627776 |
P | 1000000000000000 |
Pi | 1125899906842624 |
E | 1000000000000000000 |
Ei | 1152921504606846976 |
Variables¶
YAML has a notion of anchors. You can anchor the node with ampersand &
,
and then alias it’s value with star *
. Here is an example:
var1: & some_value
var2: *amp
When encountering the code above, the parser sees:
var1: some_value
var2: some_value
It’s very powerful and very useful thing. You can even anchor entire hierarchy:
map1: &a
key1: value1
key2: value2
map2: *a
Yields:
map1:
key1: value1
key2: value2
map2:
key1: value1
key2: value2
This is powerful for keeping yourself from writing too much code. But it only allows to substitute the whole yaml node. So there is more powerful scalar expansion:
var1: &var some_value
var2: $var
Note we replaced the aliasing using star *
with dollar sign $
. This
doesn’t look more powerful. But now we can override the value from the command
line:
./myprog -Dvar=another_value
Which yields:
var1: some_value
var2: another_value
You can also substitute a part of the string:
_target: &target world
var1: hello $target
Let’s play with it a bit:
$ ./myprog -f test.yaml -P
var1: hello world
$ ./myprog -f test.yaml -Dtarget=foo -P
var1: hello foo
There are two things interesting above:
- Anchors and scalar variables are somewhat interchangable
- Command-line variables override anchors. So latter may be used as default values
Note using underscored names for declaring variables. It’s described in quire tricks.
There is even more powerful form of variable expansion:
_n: &n 100
int1: ${2*n}k
This leverages several features. Let’s see the result:
int1: 200000
Few comments:
- The
${...}
expands an expression not just single variable - The variable is referenced without dollar
$
inside the expression - The result of substitution is parsed using same rules as plain scalar, so may use units as well.
Note
You can’t use variables when declaring mapping key. The only case where you can is inside a Template.
Templates¶
Even more powerful construction in a combination with variables is a template. Template is basically an anchored node which has some variable references, and may be used with different variable values in different contexts. For example:
_tpl: &price !NoVars
chair: $x dollars
table: ${x*4} dollars
shops:
cheap: !Template:price
x: 50
expensive: !Template:price
x: 150
The example above will be expanded as the following:
shops:
cheap:
chair: 50 dollars
table: 200 dollars
expensive:
chair: 150 dollars
table: 600 dollars
The templates may be arbitrarily complex. There are few limitations:
- Template-scoped variables may only be scalar
- The anchored node is expanded too, you may either use
!NoVars
like in example, or define all the variables to get rid of warnings ofUndefined variable
- Variables in tags are not supported
Note, the limitation #1, doesn’t limit you to use anchor or templates inside
a template (the anchored node), just the scoped variables inside the template
invocation (the items of a mapping tagged !Template
) must be scalar. And
anchors are never scoped.
Note
The variable expansion in mapping keys work only for template, but doesn’t work in all other cases.
Includes¶
All includes have common structure. They are denoted by tagged scalar, with the special tag. With the scalar being the path/filename to include. After parsing the yaml but before converting the data into configuration file structure, the node is replaced by the actual contents of the file(s).
Few more properties that are common for all include directives:
- All paths are relative to the configuration file name which contains the include directive (in fact relative to the name under which file is opened in case it symlinked into multiple places)
- Include directives can be arbirarily nested (up to the memory limit)
- File inclusion is logical not textual, so (a) each file must be a full valid YAML file (with the anchors exception described below), and (b) the included data is contained at the place where directive is (unlike many other configuration systems where inclusion usually occurs at the top level of the config), but you can include at the top level of the config too
- Variable references are not parsed in include file names yet, but it’s on todo list, so do not rely on include paths that contain dollar signs
- There is a common namespace for anchors and variables between parent and include files, but this behavior may be changed in future
Include Raw File Data¶
The !FromFile
tag includes the contents of the file as a scalar value.
For example if somefile.txt
has the following contents:
line1
: line2
The following yaml:
text: !FromFile "somefile.txt"
Is equivalent to:
text: "line1\n: line2"
The context of the file is not parsed. And it’s the only way to include binary data in configuration at the moment.
Include Yaml¶
The !Include
tag includes the contents of the file replaceing the
node that contains tag. For example:
# config.yaml
items: !Include items.yaml
# items.yaml
- apple
- cherry
- banana
Is equivalent of:
items:
- apple
- cherry
- banana
Include Sequence of Yamls¶
The !GlobSeq
tag includes the files matching a glob-like pattern, so that
each file represents an entry in the sequence. Each included file is a valid
YAML file.
The pattern is not full glob pattern (yet). It may contain only a single star and an arbitrary prefix and suffix.
For example:
# config.yaml
items: !GlobSeq fruits/*.yaml
# fruits/apple.yaml
name: apple
price: 1
# fruits/pear.yaml
name: pear
price: 2
Is equivalent of:
items:
- name: apple
price: 1
- name: pear
price: 2
Note
The entries are unsorted, so you should not use the !GlobSeq
in
places sensitive to positions for items. You should use plain sequence
with !Include
for each item instead
This construction is particularly powerful with merge key
<<
. For example:
# config.yaml
<<: !GlobSeq config/*.yaml
# config/basics.yaml
firstname: John
lastname: Smith
# config/location.yaml
country: UK
city: London
Is equivalent of:
firstname: John
lastname: Smith
country: UK
city: London
Multiple sets of files might be concatenated using unpack operator.
Include Mapping From Set of Files¶
The !GlobMap
tag includes the files matching a glob-like pattern, so that
each file represents an entry in the mapping. The key in the mapping is
extracted from the part of the filename that is enclosed in parenthesis. Each
included file is a valid YAML file.
The pattern is not full glob pattern (yet). It may contain only a single star and an arbitrary prefix and suffix. It must contain parenthesis and the star character must be between the parenthesis.
# config.yaml
items: !GlobSeq fruits/(*).yaml
# fruits/apple.yaml
title: Russian Apples
price: 1
# fruits/pear.yaml
title: Sweet Pears
price: 2
Is equivalent of:
items:
apple:
title: Russian Apples
price: 1
pear:
title: Sweet Pears
price: 2
You can also merge mappings from the multiple directories and do other crazy
things using merge operator <<
.
Merging Mappings¶
We use standard YAML way for merging mappings. It’s achieved using <<
key
and either mapping or a list of mappings for the value.
The most useful merging is with aliases. Example:
fruits: &fruits
apple: yes
banana: yes
food:
bread: yes
milk: yes
<<: *fruits
Will be parsed as:
fruits:
apple: yes
banana: yes
food:
bread: yes
milk: yes
apple: yes
banana: yes