Reference

Everything public.

One section per package, in the order the guide reads them. Each item is the declaration the compiler sees and the sentence the source wrote about it. Types list their fields or variants, then the methods called on them.

moonconf

25 items

The tree every format reads into, the layers it is merged from, and the model it is bound to.

values

bind

pub fn bind(Node, @moonmodel.Model, known? : Array[@moonmodel.Model], knobs? : Bind) -> @json.Json raise Refused

Check a tree against a model and hand back the bound values as JSON, with defaults filled in and text read as the type it spells.

The JSON is the shape the model describes, so @json.from_json turns it into a struct of the caller's own. known resolves Ref fields by model name; a reference nothing resolves is carried through unchecked rather than guessed at.

closed

pub let closed : Bind

Bind the members the model describes and refuse the rest.

decimal

pub fn decimal(StringView) -> Double?

The real number text spells, or nothing.

layered

pub let layered : Knobs

Defaults below files below the environment below explicit overrides, with the stronger layer winning silently.

merge

pub fn merge(Array[Source], knobs? : Knobs) -> Node raise Refused

Merge a whole stack, weakest first, in the order knobs asks for.

Sources of the same tier keep the order they were given, so Source order is the tie-break and a caller never has to number anything.

native

pub fn native(Node) -> @json.Json

The tree as JSON, keeping the shape and dropping the provenance.

of_json

pub fn of_json(StringView, source? : String) -> Node raise Refused

Read a JSON document into the tree.

Positions are not carried: the reader this borrows reports where it refused, not where each value sat, so a value carries the source name and the first position. A refusal keeps the reader's own position.

of_toml

pub fn of_toml(StringView, source? : String) -> Node raise Refused

Read a TOML document into the tree.

of_yaml

pub fn of_yaml(StringView, source? : String) -> Node raise Refused

Read a YAML document into the tree.

One document, in YAML 1.2 core schema. Anchors, aliases and merge keys are resolved by the reader; what arrives here is the value.

open

pub let open : Bind

Bind the members the model describes and carry the rest through.

segments

pub fn segments(String) -> Array[String] raise Refused

Split a dotted path into its segments.

A dot separates members; \. is a literal dot, so a key that contains one can still be named. An empty segment — a..b, .a, a. — is refused rather than skipped, because a path with a hole in it is a typo.

spot

pub fn spot(String, At) -> String

The source and position part of a refusal, rendered as name@line:column.

start

pub let start : At

The first position in a source: what to use when nothing better is known.

validate

pub fn validate(Node, @moonmodel.Model, known? : Array[@moonmodel.Model], knobs? : Bind) -> Array[Refused]

Every way node fails to be what model describes, in tree order.

Binding stops at the first refusal, because a caller who is going to fail wants one clear message. A caller who wants to show a person everything wrong with a file at once uses this: it walks the whole tree and collects.

whole

pub fn whole(StringView) -> Int64?

The whole number text spells, or nothing.

Configuration text is mostly digits that a program has to read as a number, and the readers in this repository refuse rather than guess. Nothing is trimmed here: a value with a space in it is not a number, and saying so is better than quietly accepting it.

types

At

pub(all) struct At

Where in a document a value was written.

The offset is in UTF-16 code units from the start of the source, which is what a StringView indexes by. Line and column are one-based, because that is how an editor counts, and an error a reader cannot find in their file is half an error.

A source that does not report positions — the JSON, YAML and TOML readers this package borrows keep the tree but not the offsets — fills in { at: 0, line: 1, column: 1 }, and says so where it matters.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start of the source.

  • line : Int32

    The line the offset is on, counting from one.

  • column : Int32

    The column the offset is at, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::of(StringView, Int32) -> Self

    The position of offset in text, counted only when something has already gone wrong.

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Bind

pub(all) struct Bind

How to bind.

Fields
  • extra : Extra

    What an undescribed member means.

Methods
  • pub fn Bind::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Bind::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Bind::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Extra

pub(all) enum Extra

What to do with a member no field of the model describes.

Variants
  • Allow

    Carry it through. The default, because a configuration often has more in it than one model describes: shared settings, another program's section.

  • Refuse

    Refuse it. For a deployment where a misspelled key is a bug that must be caught at startup, not a typo that silently does nothing.

Methods
  • pub fn Extra::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Extra::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Extra::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Knobs

pub(all) struct Knobs

How to merge: the order of the tiers, and what two layers that disagree mean.

order runs from the weakest tier to the strongest, and a tier left out of it sorts below every tier in it, in the order the sources were given. Putting the tiers in a different order is how a caller reverses the whole stack, an overlay read after the base file say, without touching any parser.

Fields
  • order : Array[Tier]

    Tiers from weakest to strongest: the last one wins.

  • clash : @moonknob.OnClash[Node]

    What a value set differently by two layers means to the program: taken from the stronger layer silently or with a warning, aborted on, or decided by the caller's function. moonknob's, as in every library of the family.

  • strict : Bool

    Whether such a value is an error in the configuration itself, raised as Clash with both positions, for a deployment where an accidental override is a bug. Checked before clash.

Node

pub(all) struct Node

A value and the provenance that makes an error message usable: which source it came from, and where in that source it was written.

Fields
  • value : Value

    The value itself.

  • source : String

    The name the caller gave the source — a file name, env, defaults.

  • at : At

    Where in that source the value was written.

Methods
  • pub fn Node::bool(Self) -> Bool raise Refused

    The boolean.

  • pub fn Node::copy(Self) -> Self

    A deep copy: the tree a caller gets back is theirs to change without disturbing the one it came from.

  • pub fn Node::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Node::find(Self, String) -> Self?

    The value at path, or nothing.

    A segment of digits indexes into a list, so servers.0.host names the first server's host without a second notation to learn.

  • pub fn Node::flag(Bool, String, at? : At) -> Self

    A boolean node.

  • pub fn Node::from(Self, String, at? : At) -> Self

    The same value, said to come from somewhere else. A merge uses this to remember which layer won.

  • pub fn Node::has(Self, String) -> Bool

    Whether a path is present.

  • pub fn Node::int(Self) -> Int64 raise Refused

    The integer, or a Type refusal. A real with no fractional part is accepted, because 8080.0 and 8080 are the same port.

  • pub fn Node::is_list(Self) -> Bool

    Whether this is a list.

  • pub fn Node::is_map(Self) -> Bool

    Whether this is a mapping.

  • pub fn Node::kind(Self) -> String

    The name of the shape a value has, for error messages: text, integer, real, boolean, null, list, mapping.

  • pub fn Node::list(Self) -> Array[Self] raise Refused

    The members of a list.

  • pub fn Node::map(Array[(String, Self)], String, at? : At) -> Self

    A mapping node built from pairs, in the order given.

  • pub fn Node::merge(Self, Self, clash? : @moonknob.OnClash[Self], strict? : Bool, path? : String) -> Self raise Refused

    Merge two trees. over is the stronger one; strict and clash decide what happens where they disagree, as in Knobs.

    Mappings merge member by member, so a later file that sets one key under db keeps the rest of the earlier file's db. Lists replace rather than concatenate: a list in a configuration is nearly always one decision, which hosts or which plugins, and appending two decisions gives a value nobody wrote.

  • pub fn Node::need(Self, String) -> Self raise Refused

    The value at path, or a Missing refusal naming the path.

  • pub fn Node::need_bool(Self, String) -> Bool raise Refused

    The boolean at path.

  • pub fn Node::need_int(Self, String) -> Int64 raise Refused

    The integer at path.

  • pub fn Node::need_text(Self, String) -> String raise Refused

    The text at path.

    A value of another shape is refused with the path in the sentence, because a caller who asked for db.port wants to be told about db.port rather than about a position in a file.

  • pub fn Node::new(Value, String, At) -> Self

    A node of any value, with the source it came from and where in it.

  • pub fn Node::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Node::num(Int64, String, at? : At) -> Self

    An integer node.

  • pub fn Node::of_real(Double, String, at? : At) -> Self

    A real-number node.

  • pub fn Node::real(Self) -> Double raise Refused

    The number as a real.

  • pub fn Node::seq(Array[Self], String, at? : At) -> Self

    A list node.

  • pub fn Node::str(String, String, at? : At) -> Self

    A text node.

  • pub fn Node::table(Self) -> Table raise Refused

    The members of a mapping.

  • pub fn Node::text(Self) -> String raise Refused

    The text, or a Type refusal naming what was there instead.

  • pub fn Node::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Source

pub(all) struct Source

One layer of a configuration: a tree, the tier it belongs to, and the name that goes into error messages.

Fields
  • tier : Tier

    Which layer this is.

  • name : String

    The name the caller wants to see in an error: a file name, env.

  • node : Node

    The tree this layer contributes.

Methods
  • pub fn Source::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Source::new(Tier, String, Node) -> Self

    A source whose name is taken from the tree it carries.

  • pub fn Source::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Source::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Table

pub(all) struct Table

A mapping that remembers the order its members arrived in, because a configuration file does: an INI file written back with its sections sorted alphabetically is a different file, and a person diffing it sees noise instead of their change.

Fields
  • entries : Array[(String, Node)]

    The members, in the order they were written.

Methods
  • pub fn Table::copy(Self) -> Self

    A copy, one level deep: the members are shared, the mapping is not.

  • pub fn Table::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Table::get(Self, String) -> Node?

    The member called key, or nothing.

  • pub fn Table::has(Self, String) -> Bool

    Whether key has a member.

  • pub fn Table::is_empty(Self) -> Bool

    Whether the mapping has no members.

  • pub fn Table::items(Self) -> ArrayView[(String, Node)]

    The members in the order they were written.

  • pub fn Table::keys(Self) -> Array[String]

    The names, in the order they were written.

  • pub fn Table::length(Self) -> Int32

    How many members the mapping has.

  • pub fn Table::new() -> Self

    An empty mapping.

  • pub fn Table::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Table::remove(Self, String) -> Node?

    Drop key, giving back what it held.

  • pub fn Table::set(Self, String, Node) -> Unit

    Put value under key, in the place key already holds if it holds one.

    Keeping the position is what makes a merge readable: the winner of a clash stays where the losing value was, so the merged document still reads in the order a person wrote it.

  • pub fn Table::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Tier

pub(all) enum Tier

Which layer of a configuration a source belongs to.

The tiers are here rather than as a number the caller assigns because the order almost everybody wants — defaults, then files, then the environment, then whatever the command line said — is a fact about deployment, not about this repository, and naming it means a caller who wants the usual thing does not write it out.

Variants
  • Default

    Values the program carries with it, used when nothing overrides them.

  • File

    A file the deployment shipped, or the one named on the command line.

  • Env

    The process environment.

  • Override

    Whatever the caller declares last: flags, a test fixture, an override.

Methods
  • pub fn Tier::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Tier::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Tier::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Value

pub(all) enum Value

A value in a configuration tree.

Numbers keep their kind: an integer stays an integer so that a port number written as 8080 is not printed back as 8080.0, and so that a binding to an Int field can accept it without guessing.

Variants
  • Null

    Nothing was written, and nothing was meant.

  • Bool(Bool)

    true or false.

  • Int(Int64)

    A whole number.

  • Real(Double)

    A number with a fractional part.

  • Text(String)

    Text, however it was quoted.

  • List(Array[Node])

    An ordered sequence.

  • Map(Table)

    A mapping, in the order its members were written.

Methods
  • pub fn Value::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Value::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Value::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

errors

Refused

pub(all) suberror Refused

Why a configuration was refused, and where.

One error type for the whole repository's root package: reading a borrowed format, merging layers, looking a path up, binding to a model. A caller catches one thing and reads one message. The message names the source and the position when the value came from text, and names the field path — db.pool.size — whenever the refusal is about a place in the tree, because a message that says "expected an integer" without saying where is a message that sends the reader looking through the whole file.

Variants
  • Type(want~ : String, got~ : String, path~ : String, source~ : String, at~ : At)

    A value has the wrong shape. path is empty when the refusal is about a value asked for on its own, with no place in the tree to name.

  • Missing(path~ : String, want~ : String)

    A field the model requires was nowhere in the sources.

  • Unknown(path~ : String, got~ : String)

    A member no field of the model describes, under a closed binding.

  • Clash(path~ : String, first~ : String, second~ : String)

    Two layers set one value differently, under a strict merge.

  • Path(got~ : String, at~ : Int32)

    A path that does not parse: an empty segment, a stray dot.

  • Format(why~ : String, at~ : At?)

    A borrowed reader refused the document, or a value it produced could not be carried into the tree. at is the position the reader reported, when it reported one.

  • TooDeep(at~ : At, limit~ : Int32)

    Nesting past the limit. A document of ten thousand opens must not take the stack down with it.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/ini

14 items

INI: the file format with a section in brackets, a name, an = and a value, and as many dialects as there are programs that read it.

values

depth

pub let depth : Int32

The limit on interpolation chains. a = ${b} and b = ${a} is a cycle, and a chain of a thousand is a mistake.

dumps

pub fn dumps(Doc) -> String

Write the document back.

Values are written as they were read, so a file that is parsed and written again keeps the references it had: interpolation belongs to reading, and a writer that resolved it would turn a file a person can follow into one whose lines no longer say where a value came from.

extended

pub let extended : Knobs

A file with ${section:name} references instead of %(name)s.

literal

pub let literal : Knobs

A file where a value is a value, and a name may stand alone.

parse

pub fn parse(StringView, knobs? : Knobs) -> Doc raise Refused

Read an INI text.

Section headers stand at the start of a line; an option is a name, a delimiter, and a value; a line that starts with whitespace continues the value above it, joined with a newline, which is how a value spans lines in every file that has ever had a long one. A comment is a line of its own, starting with # or ;, and by default a # after a value is part of the value.

Options before the first header are refused rather than collected into a section nobody named: a file has a section, and a reader that invents one hides the missing line.

standard

pub let standard : Knobs

The usual file: = and :, # and ;, lower-case names, strict, no bare names, %(name)s interpolation.

types

At

pub(all) struct At

Where in the text a name or a value was written.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Case

pub(all) enum Case

What happens to the case of an option name.

Section names keep theirs, because two sections that differ only in case are two sections; option names are folded by default, because Port and port in one section are the same setting written twice, and a reader that treats them as two silently keeps a value nobody can find.

Variants
  • Lower

    Fold to lower case. The default.

  • Preserve

    Leave as written.

  • Upper

    Fold to upper case.

Methods
  • pub fn Case::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Case::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Case::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Doc

pub(all) struct Doc

A whole document: its sections, in the order they were written.

Fields
  • sections : Array[Section]

    The sections, the default one first when it is there.

  • knobs : Knobs

    The knobs the document was read with, which its lookups need.

Methods
  • pub fn Doc::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::get(Self, String, String) -> String raise Refused

    The value, with its references resolved.

    The lookup order is the one every INI reader shares: the section named, then the default section. A name in neither is NoOption, and a reference to a name in neither is an Interpolation refusal naming the reference, because the two mistakes are different: one is a setting that was never written, the other is a setting written in a way that points at nothing.

  • pub fn Doc::get_or(Self, String, String, String) -> String raise Refused

    The value, with a fallback for a name that is not there.

  • pub fn Doc::has_option(Self, String, String) -> Bool

    Whether the name has a value, in the section or in the defaults.

  • pub fn Doc::has_section(Self, String) -> Bool

    Whether the document has that section.

  • pub fn Doc::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::options(Self, String) -> Array[String] raise Refused

    The names a section answers to, in the order they were written: its own options, then the defaults it inherits and does not override.

    The defaults are in the list because they are what a lookup finds; a reader that listed only the lines under the header would hide half the settings a program can read.

  • pub fn Doc::raw(Self, String, String) -> String? raise Refused

    The value as written, without interpolation.

  • pub fn Doc::sections(Self) -> Array[String]

    The names of the sections, in the order they were written.

    The default section is not among them: it is where every section falls back to, not a section a program reads on its own.

  • pub fn Doc::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

  • pub fn Doc::tree(Self, source? : String) -> @moonconf.Node raise Refused

    The document as the shared tree: one mapping per section, with the defaults folded into every section that does not override them.

    The values are interpolated, because a caller taking the tree is taking the answers rather than the lines. A file that refers to another value is a file that means the value it refers to.

Entry

pub(all) struct Entry

One name and its value, as written.

Fields
  • name : String

    The name, with its case folded as the knobs ask.

  • value : String

    The value, as written: continuation lines joined with newlines, and no interpolation applied.

  • at : At

    Where the name was written.

Methods
  • pub fn Entry::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Entry::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Entry::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Interp

pub(all) enum Interp

How a value refers to another value.

Variants
  • None_

    A value is a value.

  • Basic

    %(name)s, taken from the same section, then from the defaults, and %% for a literal percent sign. The default, because it is what the oldest files in the wild use.

  • Extended

    ${name}, or ${section:name}, and $$ for a literal dollar sign.

Methods
  • pub fn Interp::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Interp::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Interp::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Knobs

pub(all) struct Knobs

How to read an INI text.

The defaults are the ones a file in the wild is written for: = and : both separate, # and ; start a comment line, option names are folded to lower case, a repeated name is an error, and %(name)s is interpolated. Every one of those is a switch because the format never had a specification, and a reader that cannot be told what a file means is a reader that cannot read half of them.

Fields
  • delimiters : String

    The characters that separate a name from its value.

  • comment : String

    The characters that start a comment line.

  • inline_comment : String

    The characters that start a comment after a value, once whitespace comes before them. Empty by default: value ; note is a value with a semicolon in it unless the reader is told otherwise.

  • case : Case

    What happens to the case of an option name.

  • strict : Bool

    Whether a repeated section or option is an error.

  • allow_no_value : Bool

    Whether a name with no value at all is allowed, as in a file of flags.

  • empty_lines_in_values : Bool

    Whether a blank line inside an indented block belongs to the value.

  • interp : Interp

    How a value refers to another value.

  • default_section : String

    The section whose values every other section falls back to.

Methods
  • pub fn Knobs::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Section

pub(all) struct Section

One section, in the order its options were written.

Fields
  • name : String

    The name between the brackets.

  • options : Array[Entry]

    The options, in the order they were written.

  • at : At

    Where the header was written.

Methods
  • pub fn Section::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Section::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Section::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

errors

Refused

pub(all) suberror Refused

Why an INI text was refused.

Variants
  • MissingSection(at~ : At)

    An option outside any section. A file whose first line is key=value is missing its [section], and saying so beats inventing one.

  • BadSection(at~ : At, got~ : String)

    A section header with no ], or with text after it.

  • DuplicateSection(at~ : At, name~ : String)

    A section header written twice, under the policy that refuses that.

  • DuplicateOption(at~ : At, name~ : String)

    A name written twice in one section, under the policy that refuses that.

  • BadLine(at~ : At, got~ : String)

    A line that is neither a section, an option, nor a continuation.

  • NoSection(section~ : String)

    A lookup in a section that is not in the document.

  • NoOption(section~ : String, option~ : String)

    A lookup of a name that is in neither the section nor the defaults.

  • Interpolation(why~ : String, at~ : At)

    % or ${ that does not make sense, or a name it refers to that is not there.

  • TooDeep(at~ : At, limit~ : Int32)

    Nesting past the limit.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/props

7 items

Java properties: the file format a Properties object has been writing since 1996, and every messages.properties in every jar since.

values

dumps

pub fn dumps(Doc, comment? : String) -> String

Write the pairs back, as store does: one key=value per line, escapes for everything outside printable ASCII, and a # comment first when there is one.

The pairs are written in the order they were read, once each, which is what a person diffing two files wants; the writer this follows writes them in hash order, which is not an order at all.

load

pub fn load(BytesView) -> Doc raise Refused

Read a properties file from bytes, as load(InputStream) does: ISO-8859-1, one byte to one character, with \uXXXX for everything else.

parse

pub fn parse(StringView) -> Doc raise Refused

Read a properties text into its pairs.

The grammar is java.util.Properties': a key, a separator that may be =, : or whitespace, and a value; # or ! starting a comment line; a line that ends in an odd number of backslashes continuing on the next; and \uXXXX for a character the encoding cannot carry.

A continuation joins with no character between the halves, and the leading whitespace of the continued line is dropped, which is what makes a long value wrap without changing.

types

At

pub(all) struct At

Where in the text a pair was written.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Doc

pub(all) struct Doc

A properties file: its pairs, in the order they were read.

A later pair with the same name wins, which is what a map does and what the reader this follows does. The order is kept because a file written back with its lines shuffled is a file nobody can diff.

Fields
  • pairs : Array[Pair]

    The pairs, in the order they were read, duplicates included.

Methods
  • pub fn Doc::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::get(Self, String) -> String?

    The value of key, or nothing.

  • pub fn Doc::has(Self, String) -> Bool

    Whether key is in the file.

  • pub fn Doc::items(Self) -> Array[(String, String)]

    The pairs as a reader would see them: once each, later value winning.

  • pub fn Doc::keys(Self) -> Array[String]

    The names, once each, in the order they first appear.

  • pub fn Doc::new(Array[Pair]) -> Self

    A document made of pairs, for a caller that builds one instead of reading one.

  • pub fn Doc::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

  • pub fn Doc::tree(Self, source? : String) -> @moonconf.Node

    The file as the shared tree: one mapping of names to values.

    Properties has no sections and no nesting of its own; a name with dots in it is one name, not a path, because that is what the format says. A caller who wants the dots read as nesting has a path to ask for in the layer above.

Pair

pub(all) struct Pair

One name and its value.

Fields
  • key : String

    The name, with its escapes decoded.

  • value : String

    The value, with its escapes decoded.

  • at : At

    Where the pair was written.

Methods
  • pub fn Pair::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Pair::new(String, String, at? : At) -> Self

    A pair made of a name and a value, at a position the caller supplies.

  • pub fn Pair::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Pair::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

errors

Refused

pub(all) suberror Refused

Why a properties text was refused.

Variants
  • BadEscape(at~ : At, got~ : String)

    A \u escape with fewer than four hex digits, or digits that are not hex.

  • BadByte(at~ : At, got~ : Int32)

    A byte that is not ISO-8859-1, when the text arrived as bytes.

  • Truncated(at~ : At)

    A line that ends inside a continuation and never continues.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/dotenv

13 items

.env: the file a deployment keeps its secrets in, read as the shell would read it.

values

dumps

pub fn dumps(Array[Entry]) -> String

Write the entries back as a .env text.

A value that a reader would otherwise split, quote or comment is quoted; a value that holds nothing special is written bare, because a file a person reads is the point of the format. An entry with no value is written as the bare name it was.

interpolated

pub let interpolated : Knobs

Values are resolved as the file is read.

limit

pub let limit : Int32

The longest text this reader accepts.

load

pub fn load(StringView, vars? : Map[String, String], knobs? : Knobs, source? : String) -> Map[String, String] raise Refused

The variables a .env text sets, with references resolved against the entries above them.

A later assignment wins over an earlier one, and a reference sees the value the name had at the point it was written. A name with no value sets nothing: it is a declaration, not an assignment.

parse

pub fn parse(StringView, source? : String) -> Doc raise Refused

Read a .env text into its assignments, in file order.

The grammar is the one .env files share in the wild:

  • KEY=VALUE, with an optional export in front and optional spaces around

the sign; KEY alone names a variable without giving it a value.

  • A key may be quoted, for a name with a space in it.
  • # at the start of a line, or after whitespace, starts a comment. A #

with a character before it is part of the value.

  • Single quotes take a value literally apart from \' and \\; double

quotes decode \n, \t, \r, \a, \b, \f, \v, \\, \' and \"; either may span lines.

  • A line that is none of those is kept in Doc::skipped, not made into an

error, so one stray line does not cost a deployment its configuration.

References are not resolved here: load does that, because a reference needs the entries above it.

tree

pub fn tree(StringView, vars? : Map[String, String], knobs? : Knobs, source? : String) -> @moonconf.Node raise Refused

The file as the shared tree: one mapping of names to values, resolved as load resolves them.

Each value keeps the line it was written on, so a refusal about a value can name the line of the file rather than the document as a whole.

verbatim

pub let verbatim : Knobs

Values are taken as written.

types

At

pub(all) struct At

Where in the text an entry was written.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Doc

pub(all) struct Doc

A read file: the assignments, and the lines that were not ones.

Fields
  • entries : Array[Entry]

    The assignments, in file order, duplicates included.

  • skipped : Array[Skipped]

    The lines that were not assignments, in file order.

Methods
  • pub fn Doc::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::get(Self, String) -> String?

    The value of key, the last one written winning.

  • pub fn Doc::keys(Self) -> Array[String]

    The names, once each, in the order they first appear.

  • pub fn Doc::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Doc::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Entry

pub(all) struct Entry

One assignment, with the place it was written.

Fields
  • key : String

    The name.

  • value : String?

    The value, with quotes removed and escapes decoded, or nothing when the line names a variable without giving it a value.

  • at : At

    Where the name starts.

Methods
  • pub fn Entry::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Entry::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Entry::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Knobs

pub(all) struct Knobs

How to read a .env file.

Fields
  • interpolate : Bool

    Whether ${A} and ${A:-b} are resolved against the entries above them. A bootstrap file for a program that reads its own variables wants this off.

Methods
  • pub fn Knobs::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Skipped

pub(all) struct Skipped

A line that is not an assignment.

A .env file in the wild has lines from other shells in it, and a reader that stops at the first one is a reader that leaves a program with no configuration. The line is kept here instead, so a caller can log it or fail on it, and the rest of the file still reads.

Fields
  • text : String

    The line as written, without its ending.

  • at : At

    Where it starts.

Methods
  • pub fn Skipped::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Skipped::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Skipped::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

errors

Refused

pub(all) suberror Refused

Why a .env text could not be read at all.

A line the grammar cannot parse is not one of these: it is kept in the document's Skipped list, because a reader that refuses a whole file over one bad line is a reader that leaves a deployment with no configuration at all. A refusal here means the input is not text this package can even walk.

Variants
  • TooLarge(at~ : At, limit~ : Int32)

    More text than a configuration file should ever be.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/expand

10 items

POSIX shell parameter expansion: the forms a .env file and an INI value use when they say ${HOME} or ${PORT:-8080}.

values

deferred

pub let deferred : Knobs

A reference to an unset variable is left as written.

depth

pub let depth : Int32

The limit on nested forms. ${A:-${B:-${C}}} is three; a text that nests itself a thousand times is a mistake, and the recursion has to stop somewhere short of the stack.

expand

pub fn expand(StringView, Vars, knobs? : Knobs) -> String raise Refused

Expand a text in the POSIX shell's parameter syntax.

${A}, $A, ${A:-b}, ${A-b}, ${A:=b}, ${A=b}, ${A:?msg}, ${A?msg}, ${A:+b}, ${A+b} and ${#A}, with \ escaping $, \, " and a backtick, and the word inside any of the forms expanded in turn. The colon forms also treat an empty value as missing, as the shell does.

A variable with no value is an error by default: a caller who knows an empty string is meant asks for lenient, and one that expands in two passes asks for { unset: Keep }.

lenient

pub let lenient : Knobs

A reference to an unset variable reads as empty.

strict

pub let strict : Knobs

A reference to an unset variable is an error.

types

At

pub(all) struct At

Where in the text something went wrong.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Knobs

pub(all) struct Knobs

How far to expand.

Fields
  • unset : Unset

    What a reference to a variable with no value means.

Methods
  • pub fn Knobs::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Knobs::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Unset

pub(all) enum Unset

What a reference to a variable that has no value means.

Variants
  • Fail

    A reference to nothing is an error. The default, and what set -u does: a missing setting is nearly always the bug, and a diagnostic at the point of use beats an empty string threaded through the program.

  • Empty

    A missing variable reads as the empty string. What a shell does without set -u, and what most configuration loaders do.

  • Keep

    A missing variable leaves the reference as written, ${A}, so a later stage can fill it in.

Methods
  • pub fn Unset::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Unset::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Unset::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Vars

pub(all) struct Vars

The variables a text may refer to, and where ${A:=b} writes.

Reading is one function and writing is another rather than a map, because the thing a caller has is usually not a map: the process environment cannot be written, a layered configuration writes to its override layer, and a test writes to a small table. A Vars with no set is read-only, and an assignment through it is refused rather than dropped.

Fields
  • get : (String) -> String?

    The value of a variable, or nothing when it has none.

  • set : ((String, String) -> Unit)?

    Where an assignment goes, when there is anywhere to put it.

Methods
  • pub fn Vars::lookup(Self, String) -> String?

    The value of name, or nothing.

  • pub fn Vars::none() -> Self

    No variables at all.

  • pub fn Vars::of((String) -> String?) -> Self

    The variables of a function, which cannot be assigned to.

  • pub fn Vars::of_map(Map[String, String]) -> Self

    The entries of a map, which an assignment updates.

  • pub fn Vars::write(Self, String, String) -> Bool

    Write name, answering whether there was anywhere to write it.

  • pub fn Vars::writing((String) -> String?, (String, String) -> Unit) -> Self

    The variables of a function, which an assignment also updates.

errors

Refused

pub(all) suberror Refused

Why a text was refused.

Variants
  • Unclosed(at~ : At)

    A ${ with no }.

  • BadName(at~ : At, got~ : String)

    A name that is not a name: ${}, ${1x}, ${a-b} outside an operator.

  • BadOperator(at~ : At, got~ : String)

    An operator this reader does not know, such as the substring form.

  • Undefined(name~ : String, at~ : At)

    A variable with no value, under the policy that refuses those.

  • ReadOnly(name~ : String, at~ : At)

    ${A:=b} with nowhere to write the assignment.

  • Required(name~ : String, why~ : String, at~ : At)

    ${A:?} when A is unset or empty.

  • TooDeep(at~ : At, limit~ : Int32)

    Nesting past the limit.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/hocon

6 items

HOCON: JSON with the punctuation relaxed, plus merging, references and includes -- the format Typesafe Config reads.

values

ambient

pub let ambient : Knobs

The usual reading: the document, then the process environment.

A name the document does not define is looked up in the environment, which is how path = ${HOME}/bin works without the caller arranging anything. On a target with no environment the lookup answers nothing, so the same document reads the same way everywhere it can.

parse

pub fn parse(StringView, knobs? : Knobs, source? : String) -> @moonconf.Node raise Refused

Read a HOCON document.

The syntax is JSON's with the punctuation relaxed — no commas needed, no quotes around a word that has no punctuation in it, = or : before a value, # or // starting a comment — plus the three things that make it a configuration language rather than a data format:

  • Merging. The same name twice merges its values: objects member by

member, and anything else — an array included — keeps the later one.

  • References. ${a.b} is the value at that path; ${?a.b} is that value

when it is there and nothing at all when it is not.

  • Includes. include "name" asks knobs.read for the text, which is how

this package reads a second file without doing any I/O itself.

plain

pub let plain : Knobs

A document that includes nothing and falls back to nothing: what it says is all there is. For a test, or for a program that must not be moved by the machine it runs on.

types

At

pub(all) struct At

Where in the text something was written.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Knobs

pub(all) struct Knobs

How far to look for a name a substitution refers to.

Fields
  • read : (String, String) -> String?

    Where an include reads from: the wrapper it was written with — file, url or classpath — and the name inside it. Answering nothing for a name makes the include optional, unless it was written required(...). Reading a file or a URL is the caller's job: this package does no I/O.

  • fallback : (String) -> String?

    Where a ${name} that the document itself does not define is looked up. The process environment by default; an overlay or a test fixture when the caller says so.

  • depth : Int32

    The limit on nesting.

Methods
  • pub fn Knobs::with_fallback((String) -> String?) -> Self

    A document whose unresolved names fall back to lookup.

  • pub fn Knobs::with_includes((String, String) -> String?) -> Self

    A document whose includes are read by from, told which wrapper was written: file, url or classpath.

  • pub fn Knobs::with_read((String) -> String?) -> Self

    A document whose includes are read by read, whatever wrapper they used.

errors

Refused

pub(all) suberror Refused

Why a HOCON text was refused.

Variants
  • Unexpected(at~ : At, got~ : String)

    A character that cannot appear where it does.

  • Unclosed(at~ : At, got~ : String)

    A string, an array or an object that never closes.

  • MissingValue(at~ : At, got~ : String)

    A key with no value after it.

  • Unresolved(path~ : String, at~ : At)

    A reference to a path that is not in the document.

  • Cycle(path~ : String)

    A reference that reaches itself.

  • MissingInclude(name~ : String, at~ : At)

    An include the caller could not supply, when it was marked required.

  • Concat(at~ : At, got~ : String)

    Values that cannot be joined: an object and a string, say.

  • TooDeep(at~ : At, limit~ : Int32)

    Nesting past the limit.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).

moonconf/hcl

8 items

HCL 2: the language a Terraform file and a Nomad job are written in.

values

parse

pub fn parse(StringView, context? : Context, source? : String) -> Body raise Refused

Read an HCL body in the native syntax.

A body is a list of members: name = expression is an attribute, and name labels { … } is a block. The expressions are evaluated as they are read, against context: a name is looked up there, a call is answered by a function there, and a string interpolates what an expression inside it evaluates to.

The syntax follows HCL 2's native form. Template directives (%{ if }), heredocs and for expressions are not part of this reader.

parse_json

pub fn parse_json(StringView, source? : String) -> Body raise Refused

Read an HCL body in the JSON syntax.

JSON has no way to say "this object is a block", so the reading is the one every HCL tool settles on: an object whose members are all objects is a block, and the member names are its labels; anything else is an attribute. A body is then {"resource": {"aws_instance": {"web": {…}}}}, with resource the block name and the two names inside it the labels.

standard

pub fn standard() -> Context

The functions every context starts with: the string and list operations a configuration file uses, and nothing that reads the world.

types

At

pub(all) struct At

Where in the text something was written.

Fields
  • at : Int32

    The offset in UTF-16 code units from the start.

  • line : Int32

    The line, counting from one.

  • column : Int32

    The column, counting from one.

Methods
  • pub fn At::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn At::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Block

pub(all) struct Block

A block of a body: a name, its labels, and the body inside its braces.

Fields
  • kind : String

    The name in front of the braces: resource, server, module.

  • labels : Array[String]

    The labels between the name and the braces, in order.

  • body : Body

    The contents.

  • at : At

    Where the name was written.

Methods
  • pub fn Block::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Block::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Block::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

Body

pub(all) struct Body

The members of a body, in the order they were written.

A body holds two kinds of thing, and the format keeps them apart: attributes, which are data — name = "web" — and blocks, which are the format's own nesting — server "web" { … }. A reader that folded the two together would make server { } and server = {} the same document, and they are not.

Fields
  • attributes : Array[(String, @moonconf.Node)]

    The attributes, in the order they were written.

  • blocks : Array[Block]

    The blocks, in the order they were written.

Methods
  • pub fn Body::blocks_of(Self, String) -> Array[Block]

    The blocks called kind, in the order they were written.

  • pub fn Body::equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Body::get(Self, String) -> @moonconf.Node?

    The value of the attribute called name, or nothing.

  • pub fn Body::not_equal(Self, Self) -> Bool

    Written by derive(Eq).

  • pub fn Body::to_repr(Self) -> @debug.Repr

    Written by derive(Debug).

  • pub fn Body::tree(Self, String) -> @moonconf.Node

    The members as the same tree the rest of this repository uses: attributes under their names, blocks under theirs, a repeated block name collecting an array.

Context

pub(all) struct Context

The names in scope while an expression is evaluated.

A name is a whole tree, not a string: var.region is a member of var, which is itself a mapping. Functions are values too — a caller adds one by putting a function in the table, which is how a special function is spelled without touching this package.

Fields
  • names : Map[String, @moonconf.Node]

    The names in scope, by their first segment.

  • functions : Map[String, (Array[@moonconf.Node]) -> @moonconf.Node raise Refused]

    The functions a call may use.

Methods
  • pub fn Context::bind(Self, String, @moonconf.Node) -> Self

    The same context with name bound to value.

  • pub fn Context::function(Self, String, (Array[@moonconf.Node]) -> @moonconf.Node raise Refused) -> Self

    The same context with name answered by body.

  • pub fn Context::new() -> Self

    A context with no names and no functions.

errors

Refused

pub(all) suberror Refused

Why an HCL text was refused.

Variants
  • Unexpected(at~ : At, got~ : String)

    A character that cannot appear where it does.

  • Unclosed(at~ : At, got~ : String)

    A string, a list, an object or a body that never closes.

  • BadBody(at~ : At, got~ : String)

    A member of a body that is neither an attribute nor a block.

  • UnknownName(name~ : String, at~ : At)

    A name nothing defines.

  • UnknownFunction(name~ : String, at~ : At)

    A function nothing defines.

  • BadArity(name~ : String, want~ : String, got~ : Int32, at~ : At)

    A function called with the wrong number of arguments.

  • BadOperation(why~ : String, at~ : At)

    An operation on values it does not take.

  • TooDeep(at~ : At, limit~ : Int32)

    Nesting past the limit.

Methods
  • pub fn Refused::output(Self, &Logger) -> Unit

    Written by the Show implementation.

  • pub fn Refused::to_string(Self) -> String

    Written by derive(Eq).