Cascading config parsing
Prompted by some comments about how to handle RAW files from cameras, I revisited App::imagestream , the program I use to automatically publish all images I touch to a gallery page on my website.
An experiment that I run with this program (and with App::fritzgrowl as well) is to specify the configuration information via POD. There is code in Config::Spec::FromPod and Config::Cascade that takes POD and turns it into a hash of hashes containing the configuration model. Then there is more code in App::ImageStream::Config to turn this model into a DSL for a config file, a parser for Getopt::Long or simply the defaults. Config::Cascade
then fills out the values, starting with the most specific values coming from the command line, the less specific values coming from the config file and the least specific values coming from the application defaults, all driven by the documentation.
=head2 C<< output DIR >>
=for config
repeat => 1,
Output directory
Specifies the output directory into which the output will be written.
Example:
output 'C:/ImageStream/';
May appear only once.
So far, the experiment has been successful in the sense that specifying the config items via POD forced me to document each configuration item immediately. Writing the DSL and Getopt evaluator was fun, and having them data-driven will make it easy to also inspect %ENV
for an intermediate stage of configuration between command line and configuration file. Having the first line be a really short description and always listing
an example also makes me think more about the values and how to best describe them.
The bad thing is of course that internationalization / localization will be nasty when specifying program data through program configuration. If you ruin the pod, the program won't work anymore, as it can't read its configuration anymore. This is currently of small concern to me as I don't plan on translating its documentation. But if some other well-meanung and unsuspecting individual translates the documentation, that'll be fun breakage at a distance.
Also bad is that my way of specifying out-of-band information implies embedding Perl again via =for
blocks. This is a nasty-but-convenient hack.
In the long run, Config::Spec::FromPod
should produce something suitable for consumption by Config::Model, so that I can reuse the GUI editors and the schema provided by it. But maybe I'll realize sooner that the experiment is doomed to fail, or I abandon the applications using it.
I haven't released the modules onto CPAN for two reasons. Firstly, because I think that while interesting, parsing POD for code is a debatable design choice. Second, the API of Config::Cascade
isn't that great yet, and it's missing the provider that fetches the values from %ENV
, and lots of use and documentation. I've only used the module in two applications, and in my experience, if I haven't used something at least three times, the API will likely be crap.
Leave a comment