..it's not clear to me why you consider that an advantage. it's shorter there's no doubt, but there's a lot of information in the first case that's not in the second case: mainly an easy way to disambiguate between "i want the second item from the section named 'servers'" and "i want the section named '2' in the section named 'servers'"
The inspiration came from Template::Toolkit's way of dereferencing variables - it's clean, easy to read and, (imho) perfect for configuration. Assuming your YAML is correct, there will never be a confusion between 'the second item from the section named servers' and 'the section named 2'. The reason for this is that the value at 'dbconfig.servers' is either a scalar, a hash ref, or an array ref, so assuming it is not a scalar, it has to be one of the two - not ambiguous. My module doesn't do validate the underlying YAML - it assumes that you know what you're doing. In order to validate it, you could use Kwalify to check the data against a schema. I've been using this module for over a year, and it has never been an issue for me.
It would be helpful to know what types of error handling/messages does your mod produce when config values can't be found -- or when a value can be found, but it is not in the right context (ie: i ask for 'dbconfig.servers.2.host' but 'servers' is a hash, or 'host' is a single item ut i've asked for an array. (these are examples of the types of errors i'm worried about since you use your own string based lookup syntax instead of letting people rely on standard perl sigls and error messages.
In your example, the '2' could equally be the third element in an array, or a key called '2'. So the module doesn't differentiate between these. There is really only one error at data lookup time, and that is: "unknown key '2' at 'dbconfig.servers'". So the key either exists or it doesn't, and if it doesn't, it throws an exception. As I said above, this has never been a problem for me. I think, because you're working with configuration data, you generally know what it looks like before you run the program. It's not the same as (eg) parsing user submitted data from a website.
The use of singletons and the need to create a subclass seems obnoxious and unnecessary. if the goal is to let people both: 1) load a config set in one place, and refer to it from elsewhere in the code without passing an object refrence arround; 2) load multiple config sets; then instead of making them create a seperate package for each set, why not let them declare a global (or package) variable for each set and assuign an instance of your object to it. that way they can control the scoping...
Yes... I think I might have gone a bit overboard with the whole minimalism thing, when I was writing it. I wanted it to just work, be shared between mod_perl modules, and require the minimum work to get access to it.
In practice, it is really easy to use
- the only slight annoyance being that you have to create a file as follows:
file: My/Config.pm:
--------------------
package My::Config;
use base 'Burro::Config';
1;
- Then you load the data once (eg for mod_perl, in startup.pl):
File: startup.pl:
-----------------
use My::Config '/path/to/config/dir';
-
Then for any module that needs access to the config, you just add this to module file:
File: My/Module.pm:
-------------------
use My::Config;
$value = C('key1.key2.etc...');
I fully admit that I'm doing some stuff in the import sub which may not be the best idea, I'd welcome feedback on that. But the fact is that it works, and it is easy to use and easy to maintain (eg when moving code around)
So I'm wondering if others would find it sufficiently useful for me to release it to CPAN?
Clint
PS Thanks for taking the time to read and respond - I realise it was a long loooong post.
| [reply] [d/l] [select] |
Assuming your YAML is correct, there will never be a confusion between 'the second item from the section named servers' and 'the section named 2'. The reason for this is that the value at 'dbconfig.servers' is either a scalar, a hash ref, or an array ref, so assuming it is not a scalar, it has to be one of the two - not ambiguous.
The YAML in question will be a config file, which means it's likely that it will be created by a hand by a person -- and not auto generated by code, so assuming it is "correct" is a bad assumption. Frankly I can't possibly imagine how you can consider that syntax unambiguous: you tell me, is "a.b.2.3" referring to $conf->{'a'}->{'b'}->{'2'}->{'3'} or $conf->{'a'}->{'b'}->[2]->[3] ?
...because you're working with configuration data, you generally know what it looks like before you run the program. It's not the same as (eg) parsing user submitted data from a website.
You may know what the data looks like, because you wrote the config parsing module, and the config files, and the apps that use the config parsing module. Joe Blo who writes an app using your module may not understand it as well, and John Smith who uses Joe Blo's app and needs to write the config files for it REALLY may not understand what's going on.
In practice, it is really easy to use
... the only slight annoyance being that you have to create a file as follows ... Then you load the data once (eg for mod_perl, in startup.pl) ... Then for any module that needs access to the config, you just add this to module file
That does not sound easy to use ... particularly the part about having to create a seperate mini little perl module for each config dir i want to read from, or the fact that i have to use the module one way in exactly one palce in my app, but every other place in my app i have to use it a different way.
| [reply] [d/l] [select] |
... assuming it is "correct" is a bad assumption.
If somebody is editing the config file, they're probably changing something that you originally wrote. They are much more likely to get the values themselves wrong, rather than to change the type of a data structure. So obviously, if you're in this situation, you would need to validate the data before using it. Just as with any data from a suspect source. Fine. Being certain that it's a hash or an array will be nowhere near enough to be sure that you have good data coming in.
...I can't possibly imagine how you can consider that syntax unambiguous: you tell me, is "a.b.2.3" referring to $conf->{'a'}->{'b'}->{'2'}->{'3'} or $conf->{'a'}->{'b'}->[2]->[3]?
I'm not suggesting that we replace all references to variables in Perl with this, but for the kind of data that I need to use, this notation makes for very easy reading. The typical use of lists of values in configuration data (in my experience), is that you want the whole list so that you can iterate through it. So you ask for the whole list:
@hostnames = C('db.servers.search');
foreach my $hostname.... etc
So practically speaking, I do not find this confusing. I can't be so way out there - lots of Template::Toolkit users do exactly the same thing without complaining.
...having to create a seperate mini little perl module for each config dir i want to read from
You misunderstand me. You need one subclass per application, and one directory tree with all your config data. I've been using this module for mod_perl applications, and there it makes sense to load all your data once at startup, so that the memory is shared between the child processes. I have all my config data in one directory tree. I have a single config module (which subclasses Burro::Config; for the entire application. I specify use MyApp::Config 'dir'; once in my application, and in every other module where I want to use it, I specify use MyApp::Config
Is that really so difficult?
UPDATE : That said, I realise that this is not the normal way that Perl modules work, and this is the part I have the most doubt about. It would be easy enough to change it to returning a config object which you could then pass around all of your modules. It pretty much does that already, behind the scenes. I just figured that this way was shorter and more convenient, but I concede that it may not fit into the way others like to do things.
Clint
| [reply] [d/l] [select] |