From c455896ae9e69e2498742ff795e7886dee1ffa23 Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Fri, 5 Feb 2021 09:55:25 +0100 Subject: Move source files into src --- _posts/2020-07-15-config-3.0.md | 181 ---------------------------------------- 1 file changed, 181 deletions(-) delete mode 100644 _posts/2020-07-15-config-3.0.md (limited to '_posts/2020-07-15-config-3.0.md') diff --git a/_posts/2020-07-15-config-3.0.md b/_posts/2020-07-15-config-3.0.md deleted file mode 100644 index 9fb33c0..0000000 --- a/_posts/2020-07-15-config-3.0.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -title: Config 3.0 -layout: post -tags: Raku Programming -social: - email: mailto:~tyil/public-inbox@lists.sr.ht&subject=Config 3.0 - mastodon: https://soc.fglt.nl/notice/9x8QT2TxD2dSlEYse8 -description: > - I've made a reasonably sized change to Raku's Config module, resulting in a - major version bump. This article details my reasoning behind it, and shows - some examples on how I think I solved the issues at hand. ---- - -For those who don't know, the -[`Config`](https://modules.raku.org/dist/Config:cpan:TYIL) module for the Raku -programming language is a generic class to hold... well... configuration data. -It supports -[`Config::Parser`](https://modules.raku.org/search/?q=Config%3A%3AParser) -modules to handle different configuration file formats, such as `JSON`, `YAML` -and `TOML`. - -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 `Config` -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. - -{% highlight perl6 %} -use Config; - -my $config = Config.new.read({ - foo => "bar", - alpha => { - beta => "gamma", - }, - version => 3, -}); -{% endhighlight %} - -And after that, check for potential configuration file locations, and read any -that exist. - -{% highlight perl6 %} -$config.read($*HOME.add('config/project.toml').absolute); -{% endhighlight %} - -The `.absolute` call was necessary because I wrote the initial `Config` version -with the `.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. - -## Version 3.0 - -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 -object. - -{% highlight perl6 %} -use Config; - -my $config = Config.new({ - foo => Str, - alpha => { - beta => "gamma", - }, - version => 3, -}, :name); -{% endhighlight %} - -{% admonition_md note %} -`foo` has been made into the `Str` *type object*, rather than a `Str` *value*. -This was technically allowed in previous `Config` versions, but it comes with -actual significance in 3.0. -{% endadmonition_md %} - -Using `.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 `name` -argument will enable the new automagic features. The name you give to `.new` is -arbitrary, but will be used to deduce which directories to check, and which -environment variables to read. - -### Automatic Configuration File Handling - -By setting `name` to the value `project`, `Config` will consult the -configuration directories from the [XDG Base Directory -Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html). -It uses one of my other modules, -[`IO::Path::XDG`](https://modules.raku.org/dist/IO::Path::XDG:cpan:TYIL), for -this, together with -[`IO::Glob`](https://modules.raku.org/dist/IO::Glob:cpan:HANENKAMP). -Specifically, it will check my `$XDG_CONFIG_DIRS` and `$XDG_CONFIG_HOME` (in -that order) for any files that match the globs `project.*` or -`project/config.*`. - -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 -appropriate `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 `name`) of -the `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. - -{% highlight sh %} -$PROJECT_FOO -$PROJECT_ALPHA_BETA -$PROJECT_VERSION -{% endhighlight %} - -If any are found, they're also cast to the appropriate type. Thus, -`$PROJECT_FOO` would be cast to a `Str`, and so would `$PROJECT_ALPHA_BETA`. In -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 -of the `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 -choices. - -## Debugging - -In addition to these new features, `Config` now also makes use of my -[`Log`](https://modules.raku.org/dist/Log:cpan:TYIL) 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 `$RAKU_LOG_LEVEL` -environment variable, as per the `Log` module's interface. When set to `7` (for -"debug"), it will print the configuration files that are being merged into your -`Config` and which environment veriables are being used as well. - -{% admonition_md note %} -A downside is that the application using `Config` for its configuration must -also support `Log` to actually make the new logging work. Luckily, this is -quite easy to set up, and there's example code for this in `Log`'s README. -{% endadmonition_md %} - -## 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 `name` -argument to `.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-xdg` -and `:!from-env` arguments respectively. - -## In Conclusion - -The new `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 -`https://lists.sr.ht/~tyil/raku-devel`. -- cgit v1.1