Kinds and fields
A kind is a type of thing, such as a machine or a person. yen has no built-in kinds: you declare each one.
The fields of a kind are the data of each of its instances. This file declares a kind with two fields.
# A kind declares the fields of its instances. Every field has a type.{ yen, lib, ... }:{ yen.kinds.host.fields = { addr = yen.lib.str; # (1) cores = yen.lib.int; # (2) };}The kind host has two fields. (1) is addr, a string: yen.lib.str is its type. (2) is cores, an integer.
Types lists the types.
Now declare some instances. Any file can do this:
# Instances: `yen.<kind>.<name>`. The name is the attribute name.{ yen, ... }:{ yen.host.web = { addr = "10.0.0.1"; # (1) cores = 4; # (2) }; yen.host.db = { addr = "10.0.0.2"; cores = 16; };}An instance is yen.<kind>.<name>: yen.host.web is the instance web of kind host.
(1) sets its addr and (2) sets its cores.
Next, an aspect reads the fields. It gives one line per host to a sink. The root kind of the example collects these lines. You find it in the example code. The glossary defines the words.
# An aspect reads the fields of the nearest host.{ yen, ... }:{ yen.aspects.report = { at = yen.kinds.host; # (1) report = { host, ... }: # (2) { ${host.name} = "${host.addr} (${toString host.cores} cores)"; # (3) }; };}(1) says where the aspect is active: at every host. (2) asks yen for the nearest host, and (3) reads its fields.
The key report gives the element to the sink of the same name. This is what the flake gets:
{ db = "10.0.0.2 (16 cores)"; web = "10.0.0.1 (4 cores)";}Fields are strict
Section titled “Fields are strict”A missing field, an unknown field and a value that fails its type are error records.
Evaluation does not stop. The read gives null, and the errors query lists the problem.
Add this file to the example:
# A typo in a field name, and a string where an int goes.{ yen, ... }:{ yen.host.cache = { adr = "10.0.0.3"; cores = "8"; };}result.errors now has three records:
[ { class = "fixable"; code = "missing"; error = "missing addr"; fix = "set host:cache.addr"; from = "host:cache"; path = [ "addr" ]; want = "a string"; } { class = "fixable"; code = "unknown-field"; error = "unknown field adr"; fix = "declare yen.kinds.host.fields.adr, or use a declared field"; from = "host:cache"; near = [ "addr" ]; path = [ "adr" ]; } { class = "fixable"; code = "check"; error = "cores fails its check"; fix = "give cores a value of type an int"; from = "host:cache"; got = "8"; path = [ "cores" ]; want = "an int"; }]near names the field you probably meant.
{ addr = { type = "a string"; }; cores = { type = "an int"; };}