I'm not apologizing!
This is Advent, not Lent! It's a time for giving wonderful things, not for feeling stupid about the dumb things we did. I've published plenty of stupid unneeded code, and maybe someday I'll make a big list of my screwups, but for now it's not happening. I'm gonna shove this present down your throat and you're gonna love it.
Ho ho ho. Now I have chainsaws, too.
It's Called "Config::MVP"
There are a lot of config-reading libraries. There are hundreds of them. There are even some that I like, so what the heck was I thinking? I was thinking, "using any of those other hundreds of modules is going to suck for what I want to do." What I wanted to do, at the time, was screw around with my procmail settings, but that's another story.
I had a few major goals:
make "configuration for a plugin" also mean "load the plugin"
allow plugins to help validate and contextualize their own configuration
allow any given plugin to be loaded multiple times
force plugins to be kept in a specific order
I ended up using the INI format because it was so easy to work with, and because I'd already started down that road before formulating what I really wanted. (That's how Config::INI was born, which is also another story.) So, here's an example of all of the above features in use:
Hey, look! It's configuration just like Pod::Weaver! Dist::Zilla and Pod::Weaver both use Config::MVP to great effect. It works like this: every block of the configuration is associated with a plugin -- we use String::RewritePrefix to expand the short form into a package name. If there's something after the slash, we use that as the plugin's name. That way we can have (for example) multiple
Generic sections like we see above. We just can't have two sections named
Packages can provide methods like
mvp_aliases to tweak how its inputs are handled. For example, one plugin might let you provide multiple entries for
author while another would not. These methods aren't required, so any package can be treated as a plugin by Config::MVP.
The Config Sequence
There are a few ways to read in MVP-style config, but as far as I know, everything serious right now uses Config::MVP::Reader::INI. Any reader, though, will return a Config::MVP::Sequence object. It's easy to deal with -- it lets you get at your plugin configuration as a list of plugins or by name. For example:
By establishing an explicit order, rather than using a hash, the user who writes the config file can always know in what order his plugins will act. By requiring unique names, we know that we can always get at any plugin by name and that we can identify sources of trouble unambiguously when things go pear shaped.
Although the INI file reader is the only serious reader right now, writing more is made trivial by using the Config::MVP::Assembler system... but let's not focus on that. INI files are fine. Still, since there might be other really great offerings, there's something like Config::Any for MVP: Config::INI::Reader::Finder, which looks for known types of MVP config files and tries to read any of them:
This will look for any kind of plugin it knows how, using the associated extensions. It will look for config.ini, but it could also look for config.json or config.pl if readers were written.
Config::MVP doesn't make sense when a simple hashref is really all you need, but for many more complex systems it can save lots of time and make plugins much easier to manage. I'm looking forward to hearing about other people making MVP an important asset in their applications in the coming year.