Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Program configuration in the OOP world

by Tardis (Pilgrim)
on Apr 10, 2002 at 12:33 UTC ( [id://158006]=perlquestion: print w/replies, xml ) Need Help??

Tardis has asked for the wisdom of the Perl Monks concerning the following question:

My quest of creating a clean, strucutured, OOP-good set of programs and modules continues.

So far I have nicely abstracted my handling of various object types into seperate modules (each of which inherit most of their stuff from a superclass - less work for me so it's all good). I have also abstracted out the database layer into a seperate Backend module. Also good.

Now before I start to think about writing some bona-fide applications, I need to think about configuration data. The last thing I ever want to do in my new world of OOP-goodness is hardcode in directory paths and database access credentials. I'd rather eat a copy of Windows XP Home.

So now I'm puzzling about how to get data from a config file into my programs. Some criteria:
  • Configuration data needs to be available to modules and to the actual program
  • Minimize the amount of work needed to 'config-ize' a module or program
Note I'm not interested in the actual config data format at this stage, just how to make it available to everything.

My best idea so far is to have a Config package which reads the config file during a class constructer. Then the first time my Config package gets used, the data is read in, otherwise it's unnecessary.

Then, provide Class Methods to get at the config data. Probably simplest is an AUTOLOAD method which looks up the config values from a hash.

Problems I see with this:

  • Since there is no explicit construction, how do I tell it that I want a different config file during this run?
OK, so that idea bites pretty hard. Going on with this confessional debugging, lets try mark II:

  • Any module/program that might need a config item does something like:

    use Config; my $config = Config->new(); print "Root path is " . $config->root_path;

The key here being that if the Config module already 'knows' that is has an existing config object from a previous call, it will just pass that one back to the caller, so all modules/programs get the same data, and the config file need to be read only once.

In effect, each Config->new() call will merely get back the same reference to the single object, it is held in the Class and only created during the first Config->new call.

The other nice thing about this is that the new method could be modified so a config file override parameter could be passed in. So my user program can use that, and my called modules don't know the difference.

Flaws? Criticism? Pizza?

Replies are listed 'Best First'.
Config::General::Extended?
by RMGir (Prior) on Apr 10, 2002 at 12:41 UTC
Re: Program configuration in the OOP world
by broquaint (Abbot) on Apr 10, 2002 at 12:48 UTC
    The AppConfig module might be what you want. It's designed for managing application configuration information and will probably do everything you need and then some. It's interface is very nice and the actual config files are simple + powerful.
    <rhetorical>What more could you want ;-)</rhetorical>
    HTH

    broquaint

Re: Program configuration in the OOP world
by Biker (Priest) on Apr 10, 2002 at 12:46 UTC

    I was recently introduced to the Singleton module. It does a lot of what you want.

    If you want to roll your own 'config stuff' (business specific?) then this module may be of interest.


    Everything went worng, just as foreseen.

Re: Program configuration in the OOP world
by Tardis (Pilgrim) on Apr 10, 2002 at 12:58 UTC
    Thanks for the suggestions.

    A quick scan of them indicates that none of them will help me avoid either hard-coding config file paths into my modules, or needing to pass config hashes/objects into my modules so they know what's in the config file as well as my program.

    Time to put my code where my mouth is and attempt what I suggest above.... should be interesting.

      Don't despair. Put together the Class::Singleton and AppConfig suuguestions. Then you can just have:

      package Some::Module; use MyConfig; ## ... sub do_something { my $self = shift; my $config = MyConfig->instance; $self->_blah_de_blah() if $config->do_blah(); return $self->bloop() unless $config->no_bloop(); }

      Nobody had to pass anyone else anything.

        For an example of how to set this up with Class::Singleton (using just hardcoded info), see Re: how to make a universally inherited method?. For non-hardcoded info, just have it call some configuration reading routine to set the data.

        The usage suggested by Fletch is fairly simple and quite powerful. You just need to setup (read in) your configuration once and then it's available to all your modules in that process.

        Chris
        M-x auto-bs-mode

Re: Program configuration in the OOP world
by Tardis (Pilgrim) on Apr 14, 2002 at 12:34 UTC
    OK, I did it. Rather than my usual rant, lets post some bona-fide code. This is really rough, a lot of it is cut and paste from my other stuff, but at this point it's working. It may not work for you, as I've diked out a lot of the really ugly stuff before pressing submit ;-) Consider this untested.

    package Config; use strict; # always be strict use Carp; use vars qw ($AUTOLOAD); my ($config); # our global config object my (%config); # config hash, the actual config +data sub new { my $proto = shift; my $class = ref($proto) || $proto; # setup the new object my $self = { %config, }; bless ($self, $class); return ($self); } sub AUTOLOAD { my $self = $config; my $type = ref($self); my $name = $AUTOLOAD; $name =~ s/.*://; # strip fully-qualified portion unless ( defined $self->{$name} ) { croak "Can't access `$name' field in class $type"; } # just return the attribute return $self->{$name}; } sub read_config { my $conf_file = shift; open (FILE, "$conf_file") || return 0; while (<FILE>) { if ( /^(\w+)\s*=?\s*(.*)$/ ) { $config->{$1} = $2; carp "w00t! set $1 to $2"; } } close (FILE); return 1; } # package constructor BEGIN { my (@config_files); $config = Config->new; # we have an empty configuration object, lets read in # a config file # if we fail, fail silently, give the user code a chance to call rea +d_config # with it's own specifier @config_files = qw ( ../etc/journal.conf /usr/local/etc/journal.conf + ); # try each one until we succeed foreach (@config_files) { if (read_config ($_)) { last; } } # error check if (! $config ) { carp "Failed to get config"; } } # keep stuff happy 1;
    With a config file like this:

    rootdir = /usr/tmp
    My code can do this:

    use Config; print "Root Directory is " . Config->rootdir . "\n";
    All of my modules can use config;, the config data will only be read once.

    The other bit of my criteria, allowing for a user override of the config file I haven't yet nutted out. I have a feeling it's going to cause me problems, given that some of my modules need config data during their class constructers. I'll keep on that.

      May be it is late reply but anyway. Do not name your module Config. Perl distro already has core module Config. By giving your module same name you just asking for troubles. It is almost as bad as if you created your own perl module named lib.

      --
      Ilya Martynov (http://martynov.org/)

Re: Program configuration in the OOP world
by impossiblerobot (Deacon) on Apr 10, 2002 at 16:44 UTC
    I created my SiteConfig Module to provide transparent access to config data for my applications, using XML for storage. It is isn't object-oriented, but could provide the hash(es) for creating your solution.

    Of course, the CPAN modules are probably better, so you should probably just use one of them. :-)

    Impossible Robot

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://158006]
Approved by RMGir
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-04-19 12:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found