module

Superconf

See Superconf::Option for the high-level overview. This file holds the process-wide singleton registry and its load/dump machinery.

Framework-agnostic: a terminal library and the app using it can both register into the same registry, so every option appears in one combined, dumpable list.

Constants

ENV_STRING = ->(s : String) do s.as(String | ::Nil) end

Parser for a String?-valued option: the built-in casts cover String but not the String | Nil union, so such options pass this proc explicitly. A present value is taken verbatim.

RESERVED_CLIS = {"--config", "--dump-config"}

The CLI flags load_args always registers itself. An option that claimed one of these would have its handler overwritten by the built-in (handlers are keyed by flag string), so it must be rejected up front — see ensure_cli_free.

Class methods

[](key : String) : AbstractOption

Look up an option, raising Superconf::Error if it isn't registered.

Source
[]?(key : String) : AbstractOption | Nil

Look up an option, or nil.

Source
app_name

Application name used by default_config_path (e.g. ~/.config/<name>/...).

Source
app_name=(app_name : String)

Application name used by default_config_path (e.g. ~/.config/<name>/...).

Source
configure!(file : String | Nil = nil, *, env : Bool = true, args : Bool = true) : Nil

Opt in to external configuration sources, in precedence order (lowest to highest): a config file, then environment variables, then command-line options. If file is given it is loaded; otherwise default_config_path is loaded when it exists. Pass file: "" to skip file loading entirely.

Source
configured?(key : String) : Bool

Whether option key carries a non-default value — i.e. some source (config file, env, CLI, runtime) actually configured it. A value equal to the default is treated as unconfigured, so library code can safely use this as "should the configured value override a programmatic one".

Source
default_config_path

The default per-user config path: $XDG_CONFIG_HOME/<app_name>/config.yml, or ~/.config/<app_name>/config.yml when $XDG_CONFIG_HOME is unset.

Source
dump(io : IO = STDOUT, format : Format = Format::Yaml) : Nil

Dump the full configuration to io in format. :yaml/:json produce valid, re-loadable config files; :env is a sourceable shell script; :pretty is a human table that also shows each value's source; :report is rich JSON with full per-option metadata.

Source
each

Iterate every option, ordered by key.

Source
env_name(opt : AbstractOption) : String

The environment-variable name for opt: its explicit env: if given, else env_prefix + the derived suffix. Computed lazily so a prefix set after registration still applies.

Source
env_prefix

Prefix prepended to derived environment-variable names (options that did not pass an explicit env:). The final application typically sets this once to brand the whole config space, e.g. Superconf.env_prefix = "CRYSTERM_". It is applied lazily, so it affects options registered before it is set too.

Source
env_prefix=(env_prefix : String)

Prefix prepended to derived environment-variable names (options that did not pass an explicit env:). The final application typically sets this once to brand the whole config space, e.g. Superconf.env_prefix = "CRYSTERM_". It is applied lazily, so it affects options registered before it is set too.

Source
get(key : String, type : T.class) : T forall T

Dynamic, string-keyed read. Prefer the typed accessor (Superconf.<name>) in normal code; this is for keys known only at runtime. Raises if the key is unknown or type doesn't match how the option was registered.

Source
load_args(argv : Array(String) = ARGV, *, consume : Bool = true)

Apply command-line options (at Source::CommandLine). Recognized flags are matched against the registry; two built-ins are always available:

  • --config FILE — additionally load a YAML/JSON config file
  • --dump-config [FMT] — dump configuration (yaml|json|env|pretty|report, default yaml) and exit

Unknown options are ignored so an app's own parsing is left intact. By default the real argv is consumed (recognized flags removed); pass consume: false to parse a copy non-destructively. Returns self.

Source
load_default_file

Load default_config_path if it exists; a no-op otherwise. Returns self.

Source
load_env

Apply matching environment variables (at Source::Env). No-op for any option whose env var is unset. Returns self for chaining.

Source
load_file(path : String)

Load a config file by path. JSON is valid YAML, so the same parser handles both .yml and .json.

Source
load_yaml(input : String | IO, origin : String = "YAML")

Load a YAML document (string or IO) at Source::ConfigFile. Accepts nested group mappings (screen: {resize_interval: 0.5}) and/or flat dotted keys (screen.resize_interval: 0.5). Unknown keys are ignored.

Source
register(key : String, default : T, *, env : String | Nil = nil, cli : String | Nil = nil, group : String | Nil = nil, description : String = "", parse : Proc(String, T) | Nil = nil, validate : Proc(T, Bool) | Nil = nil) : Option(T) forall T

Register a new option and return a typed handle whose #value you can read directly. The value type T is inferred from default.

cli and group are derived from key unless given; env defaults to a lazily-derived name (see env_name). For value types beyond the built-ins (Bool/Int*/Float64/String/Char/Time::Span/Enum) pass a parse proc. validate is an optional predicate run against every effective value (and against default); a false result raises Superconf::Error.

Registering a key that already exists raises — keys are unique.

Source
register_alias(alias_key : String, target_key : String, *, env : String | Nil = nil, cli : String | Nil = nil, group : String | Nil = nil, description : String | Nil = nil) : AbstractOption

Register an alias: a second name (alias_key) for an already-registered option (target_key). The alias shares the target's value, type, default, parsing and validation, and gets its own config key, env var and CLI flag (derived from alias_key unless overridden). Reading or writing either name affects the one shared value.

Use it, like set_default, when an app wants to promote a library's option under its own name. The library's name keeps working; the app's name becomes an equal surface beside it:

module Superconf
  option "screen.resize_interval", 0.2.seconds # declared by a library
end

Superconf.register_alias "myapp.refresh", "screen.resize_interval"
Superconf.set "myapp.refresh", 1.second             # writes the shared value
Superconf.get("screen.resize_interval", Time::Span) # => 1.second
# MYAPP_REFRESH / --myapp-refresh / `myapp.refresh:` now work too

Aliasing an alias is allowed and resolves to the same underlying option. Registering an alias_key that already exists raises; an unknown target_key raises. Call it early (before configure!/load_*). Returns the alias handle.

Source
registered?(key : String) : Bool
Source
set(key : String, value : T, source : Source = Source::Runtime, origin : String = "API") : Nil forall T

Dynamic, string-keyed write at Source::Runtime (always wins). Raises on type mismatch. Prefer Superconf.<name> = ... in normal code.

Source
set_default(key : String, value : T) : Nil forall T

Change the default of an already-registered option. Unlike set (which writes at Source::Runtime and wins over everything), this writes at Source::Default precedence, so a config file / env var / CLI flag / runtime assignment still overrides it. Use it when an app wants a different baseline than a library's registered default — e.g. crysterm choosing a different tput.read_timeout — while keeping it user-overridable.

Also updates the recorded default (so dumps and default_string stay consistent). If a higher-precedence source already set the value, the effective value is left untouched; only the recorded default changes. Call it early (before configure!/load_*).

Source
to_json

The configuration as a re-loadable JSON string.

Source
to_yaml

The configuration as a re-loadable YAML string.

Source

Macros

option(key, default, *, description = "", env = nil, cli = nil, group = nil, parse = nil, validate = nil)

Declare a typed option: registers it (so it gets an env var, CLI flag, config key, source tracking, and a line in every dump) and defines statically-typed accessors Superconf.<name> / Superconf.<name>=, where <name> is the key with dots turned into underscores.

Ergonomic front door — Superconf.screen_resize_interval returns the value directly, with no string key or type argument, reading a cached handle (no hash lookup). Libraries and apps use it by reopening the module:

module Superconf
  option "myapp.refresh", 1.second, description: "Refresh interval"
end

Superconf.myapp_refresh # => Time::Span (typed)
Superconf.myapp_refresh = 5.seconds

Accepts the same options as register, including parse: and validate:.

Source
option_alias(key, target, type, *, description = nil, env = nil, cli = nil, group = nil)

Declare a typed alias of target: registers an alias named key (see register_alias) and defines the typed accessors Superconf.<name> / Superconf.<name>= of value type type, where <name> is key with dots turned into underscores. The alias counterpart of option — the ergonomic, typed way for an app to promote a lower-level option:

module Superconf
  option_alias "myapp.refresh", "screen.resize_interval", Time::Span
end

Superconf.myapp_refresh = 1.second # writes the shared value
Superconf.myapp_refresh            # => Time::Span

type is the target option's value type. The target must already be registered when this runs (declare the library's option first).

Source

Nested types