tags:

views:

65

answers:

3

Hi, I have a package (really just one subroutine) I use frequently to parse config file etc. Basically it looks like this:

sub get_settings {
        my %config;
        my $config = 'path...';

        unless(-r $config) {
                die("Couldn't read config");
        }
        open CONFIG, '<', $config or die $!;
        while(<CONFIG>) {
                next if (($_ eq "\n") or /^\;/);
                chomp;
                my($setting, $value) = split(/=/, $_);
                $config{$setting} = $value;
        }
        return %config;
}

Pretty basic, but I was wondering how (and if) this could/should be re-written to OOP? Really just for learning, never quite seen when and why to use bless. =)

Thanks!

+1  A: 

The answer to the question has more to do with the programs you are using the package in than with the package itself.

If this a pretty large OOP based apps/scripts then it definitely makes sense to OOP it because that is what the customer expects (the apps and the people writing these apps/scripts). Also having imperative style libraries stick out like a sore thumb and create complexity.

Conversely if the package is used in shorter imperative scripts, then an OOP interface will conflict with the customer's expectation (i.e. the scripts + people developing them).

Maybe you are migrating between approaches (e.g. the script become big and unwieldy and need to be better organised, maybe with OOP) in that case a settings/config kind of Class is a good place to start as they tend to be well separated and have clear lines of responsability.

In short : do what makes most sense where the package is used.

Peter Tillemans
Say I plan to write a bigger script. What benefits do I get from doing it in OOP (when classes are just packages, objects just variables and methods just subroutines)?
laka
There are less moving pieces you need to keep in your head when working on a piece of code, because the objects (when properly designed and implemented) do their own stuff. This translates in less setup code, less protocol code, less cleanup code in the script because these typically are moved to the package and done when needed. This code is still there, it is just not visible from the client app and can be more easily shared over multiple uses.
Peter Tillemans
A: 

You can take a look at source code from modules on CPAN. For example Config::General should answer your questions...

sebthebert
A: 

Here is (hopefully!) a simple example of an OO based config abstraction using:

NB. You can use other modules or even roll your own. Below serves just as a general example.

RoomConfig.pm

package RoomConfig;
use Moose;
with 'MooseX::SimpleConfig';

has doors   => (is => 'rw', isa => 'Int', required => 1);
has windows => (is => 'rw', isa => 'Int', default  => sub {0});

1;

So above is our OO config class. Everything is neatly declared so you clearly know that config options are available and valid, ie. its self documenting.

So to create a room from a config file would be:

use RoomConfig;

my $box_room = RoomConfig->new_with_config( configfile => 'box_room.yaml' );

Because its a class i can also instantiate a room without a config file:

my $cupboard       = RoomConfig->new( doors => 1 );
my $utility_room   = RoomConfig->new( doors => 2 );
my $master_bedroom = RoomConfig->new( 
    doors      => 1,
    windows    => 2,   # dual aspect
);

And also with these particular modules we get extra features like this:

# below throws exception because room must have a door!
my $room_with_no_door_or_window = RoomConfig->new; 

Thus my configuration can easily come from a configuration file or by setting attributes.


And we can go further by extending our config for different types of rooms:

BathRoomConfig.pm

package BathRoomConfig;
use Moose;
extends 'RoomConfig';

has loos  => (is => 'rw', isa => 'Int', default  => sub {0});
has sinks => (is => 'rw', isa => 'Int', default  => sub {0});
has baths => (is => 'rw', isa => 'Int', default  => sub {1});

1;

And if we used this config (bathroom.yaml):

doors:  1
windows:    1
bath:   1
loos:   1
sinks:  2

Then you could do this:

use BathRoomConfig;

my $upstairs_bathroom = BathRoomConfig->new_with_config( 
    configfile => 'bathroom.yaml' 
);

my $closet_room = BathRoomConfig->new_with_config( 
    configfile => 'bathroom.yaml',
    baths      => 0,
    sinks      => 1,
    windows    => 0,
);

Note that $closet_room makes use of both the config file and setting attributes.

Also note that if my config file didn't have doors (ie. required property) then it would have thrown an error on new_with_config.


And finally we may find introspecting our defined config class handy:

use RoomConfig;

say "RoomConfig provides the following options:";

for my $attr (RoomConfig->meta->get_attribute_list) {
    next if $attr eq 'configfile';
    say '-> ', $attr;
}


Now there is nothing stopping you implementing most of this in a standard config package so at the end of the day its just horses for courses!

However the ease of managing all this is so much easier with OO and the features that these already written modules provide is big advantage especially in bigger projects.

/I3az/

draegtun