Perl read_config sub, oop or not?
I have a pa开发者_如何学运维ckage (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!
Here is (hopefully!) a simple example of an OO based config abstraction using:
Moose
MooseX::SimpleConfig
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.
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.
You can take a look at source code from modules on CPAN. For example Config::General should answer your questions...
精彩评论