For those who don’t know, the
Config module for the Raku
programming language is a generic class to hold… well… configuration data.
modules to handle different configuration file formats, such as
Up until now, the module didn’t do much for you other than provide an interface that’s generally the same, so you won’t need to learn differing methods to handle differing configuration file formats. It was my first Raku module, and as such, the code wasn’t the cleanest. I’ve written many new modules since then, and learned about a good number of (hopefully better) practices.
For version 3.0, I specifically wanted to remove effort from using the
module on the developer’s end. It should check default locations for
configuration files, so I don’t have to rewrite that code in every other module
all the time. Additionally, configuration using environment variables is quite
popular in the current day and age, especially for Dockerized applications. So,
I set out to make an automated way to read those too.
The Old Way
First, let’s take a look at how it used to work. Generally, I’d create the default configuration structure and values first.
And after that, check for potential configuration file locations, and read any that exist.
.absolute call was necessary because I wrote the initial
.read method not supporting
IO::Path objects. A fix for this has
existed for a while, but wasn’t released, so couldn’t be relied on outside of
my general development machines.
If you wanted to add additional environment variable lookups, you’d have to check for those as well, and perhaps also cast them as well, since environment variables are all strings by default.
So, how does the new version improve this? For starters, the
.new method of
Config now takes a
Hash as positional argument, in order to create the
structure, and optionally types or default values of your configuration
foo has been made into the
Str type object, rather than a
This was technically allowed in previous
Config versions, but it comes with
actual significance in 3.0.
.new instead of
.read is a minor syntactic change, which saves 1 word
per program. This isn’t quite that big of a deal. However, the optional
argument will enable the new automagic features. The name you give to
arbitrary, but will be used to deduce which directories to check, and which
environment variables to read.
Automatic Configuration File Handling
name to the value
Config will consult the
configuration directories from the XDG Base Directory
It uses one of my other modules,
this, together with
Specifically, it will check my
that order) for any files that match the globs
If any files are found to match, they will be read as well, and the
configuration values contained therein, merged into
$config. It will load the
Config::Parser implementation based on the file’s extension. I
intend to add a number of these to future Rakudo Star releases, to ensure most
default configuration file formats are supported out of the box.
Automatic Environment Variable Handling
After this step, it will try out some environment variables for configuration
values. Which variables are checked depends on the structure (and
Config object. The entire structure is squashed into a 1-dimensional list
of fields. Each level is replaced by an
_. Additionally, each variable name
is prefixed with the
name. Lastly, all the variable names are uppercased.
For the example
Config given above, this would result in the following
environment variables being checked.
If any are found, they’re also cast to the appropriate type. Thus,
$PROJECT_FOO would be cast to a
Str, and so would
this case that doesn’t do much, since they’re already strings. But
$PROJECT_VERSION would be cast to an
Int, since it’s default value is also
Int type. This should ensure that your variables are always in the
type you expected them to be originally, no matter the user’s configuration
In addition to these new features,
Config now also makes use of my
Log module. This module is
made around the idea that logging should be simple if module developers are to
use it, and the way logs are represented is up to the end-user. When running an
application in your local terminal, you may want more human-friendly logs,
whereas in production you may want
JSON formatted logs to make it fit better
into other tools.
You can tune the amount of logging performed using the
environment variable, as per the
Log module’s interface. When set to
“debug”), it will print the configuration files that are being merged into your
Config and which environment veriables are being used as well.
A downside is that the application using
Config for its configuration must
Log to actually make the new logging work. Luckily, this is
quite easy to set up, and there's example code for this in
Too Fancy For Me
It could very well be that you don’t want these features, and you want to stick
to the old ways as much as possible. No tricks, just plain and simple
configuration handling. This can be done by simply ommitting the
.new. The new features depend on this name to be set, and won’t
do anything without it.
Alternatively, both the automatic configuration file handling and the
environment variable handling can be turned off individually using
:!from-env arguments respectively.
Config module should result in cleaner code in modules using it, and
more convenience for the developer. If you find any bugs or have other ideas
for improving the module, feel free to send an email to