module Kwconfig:sig
..end
This module implements simple config files in refer format (see Kwrefer
).
A config file is parsed by Kwconfig.parse
, which makes certain
assumptions about the refer file. Before use, the config file can
be validated for the presence of required fields, and the values
of provided fields can themselves be validated, "fixed up" or
modified (Kwconfig.fixup
), and missing optional fields can be populated
with default values (Kwconfig.defaults
). The values of a field are
extracted from the parsed Kwconfig.t
with Kwconfig.find
, or en masse with
Kwconfig.section
.
A config file consists of distinct sections, which are the subsets of the refer records determined by the values of a distinguished field. For example, you might give your records a "section" field (the field name is up to you) and use:
%section ui
for records concerned with the user interface, and:
%section db
for records concerned with the database.
When you parse the config file, you would specify the
distinguished field like so: parse ~section:"section"
; any
records that don't have %section
field are lumped together in
what is effectively their own anonymous section.
Very simple config files with only one section don't need a
distinguished section field; just call parse
withouth the
~section
parameter and don't specify the ~section
parameter
for any other calls. Anytime you don't provide a ~section
, you
are referring to the anonymous section.
Technically, the parsed config file or section M.t
is keyed on
string options; explicitly named sections (e.g. %section ui
) are
entered as Some "ui"
; the anonymous section is entered as
None
.
There's no reason to use multiple refer records in a config file
unless you tag them with different sections. Typically, a config
file has one record per section. Since each record can have any
number of fields, and any field can repeat, when you query a
parsed config file for the field foo
with find foo
, you get
back a list of values -- each value being one repetition of the
requested field.
So this one-record config file:
%foo 1 %foo 2 %foo 3
Is the same as this two-record file:
%foo 1 %foo 2 %foo 3
Calling find "foo"
in each case results in:
["1"; "2"; "3"]
However, given this two-record config file with two sections:
%section one %foo 1 %section two %foo 2 %foo 3
then find "foo"
return []
(there is no anonymous section),
find ~section:"one" "foo"
returns ["1"]
, and find
~section:"two" "foo"
returns ["2";"3"]
.
You can validate a config file at two levels:
Kwrefer.schemas
) to Kwconfig.parse
.
For the second case, use validation functions from Kwvalid
and
the Kwconfig.validate
function.
Here's a schema for a simple config file with four fields:
%filename REQ UNIQ %max OPT UNIQ %development OPT UNIQ %user OPT REP
If this schema lives in the file /etc/config.schema
, and the
config file is /etc/config
, we can invoke Kwconfig.parse
like so:
let schema = "/etc/config.schema" in parse ~schema:(schema, Kwrefer.compile_file schema) "/etc/config"
Supposing that %filename
has to exist and be readable, that
%max
needs to be positive non-zero integer, that %development
has to be a Boolean, and %user
has to be a non-empty string, the
following list will serve to validate the field values:
let validators = Kwvalid.([ None, "filename", File.(existing && readable); None, "max", Num.W.any; None, "development", B.boolean; None, "user", String.notnull; ])
We can perform the field value validation like so:
validate validators config
module M:Kwmap.Make
(
sig
typet =
string option
val compare :'a -> 'a -> int
end
)
typesection =
(string * string) list
typet =
section M.t
Kwconfig.M
's mapping optional
section names to sections.exception Badschema of string list
exception Invalid of string * string list
val parse : ?schema:string * Kwrefer.schemas ->
?strict:bool ->
?section:string -> ?ignore:string list -> Kwchan.src -> t
parse ?schema ?section ?ignore chan
: parse a config file on chan
.
If you provide a schema
, the config on chan will be validated
against it; in this case, chan
will be read twice: it can't be a
pipe, and must be a Kwchan.Chan
opened on a regular file, or a
Kwchan.String
.
schema
: schema location (typically filename) and Kwrefer.schemas
used to validate the config filestrict
: whether or not to validate the config file in strict modesection
: the field that distinguishes different sectionsignore
: section field values that are to be ignored (e.g. for comment sections)chan
: the channel containing the config fileval find : ?def:string list -> ?section:string -> string -> t -> string list
find ?def ?section key config
: find key
fields in parsed config file config
.def
: default values for missing fields (default: []
)section
: the section to consider (default: None
)key
: the fieldnameval replace : ?section:string ->
string -> string -> t -> section M.t
replace ?section key value config
: replace all mappings with key
in section
with (key,value)
.section
: the section to consider (default: None
)key
: the fieldnamevalue
: the valueval section : M.key -> t -> section
section s config
: extract the entire section s
from the config
in the form of a coalesced alist.
See Kwlist.coalesce
.
s
: the sectionval fixup : (M.key * string * (string -> string)) list ->
t -> t
fixup sffs config
: fixup certain config fields by selectively applying functions.
The fixup function is applied to the particular field value.
Example: translate ~'s in a filename field:
fixup [None, "filename", Kwfile.squiggle ~respect_env:false] config
sffs
: list of fixup triples (section, key, fixup)val validate : (string option * string * Kwvalid.t) list ->
t -> (string * string * string) list * t
validate validators config
: validate field values in config
as specified by validators
.validators
: list of validation triples (section, key, validator)val defaults : (M.key * string * string list) list -> t -> t
defaults defs config
: add default values for certain config fields.
Named fields in particular sections that are absent in config
are
inserted with default values.
Example: provide default value for filename field:
defaults [None, "filename", ["/etc/default"]] config
defs
: list of defaults triples (section, key, defaults)val init : ?schema:string * Kwrefer.schemas ->
?strict:bool ->
?section:string ->
?ignore:string list ->
?file:string ->
?string:string -> (M.key * string * string list) list -> t
init ?file ?string defs
: initialize an app with a config file, setting defaults.
It's okay for ~file
not to exist, in which case the defaults
will apply.
schema
: schema location (typically filename) and Kwrefer.schemas
used to validate the config filestrict
: whether or not to validate the config file in strict modesection
: the field that distinguishes different sectionsignore
: section field values that are to be ignored (e.g. for comment sections)file
: the path to a config filestring
: the literal string text of a config filedefs
: list of defaults triples (section, key, defaults)