On 10/10/10 23:32, Jesse Luehrs wrote:
On Sun, Oct 10, 2010 at 10:00:17PM +0200, "Poul H. Sørensen" wrote:HiI'm trying to make a perl-module, where (some of) the attributes can be set by merging several configuration files, but I can't get it to work as expected/required...
Q1: Foo->new_with_options( ) how do I pass the configuration file as an argument?I believe that passing configfile => 'foo.conf' to new_with_options should do the right thing. If it doesn't, that should probably be fixed.
It seems to me that only the last configfile specified is parsed.
Q2: $foo->configfile( ) # or ->set_configfile( ) how do I parse a configfile later on after constuction?MooseX::ConfigFromFile (which MooseX::SimpleConfig uses) specifies that ->get_config_from_file returns a hashref of the config, which it then uses to populate attributes. You should be able to call this directly, and do whatever you want with the config hashref.Q3: --configfile answer1.xml --configfile answer2.xml how do I load and merge multiple configuration files?
I guess this is kind of same problem as in Q1
Q4: --configuration-file or --fille-de-configuration [pun intended] how do I call the command-line-flag anything else than "--configfile"?
Haven't tried it either, see attached solution
Q5: BUILD how do I load some default configuration files, before all the others?
I guess this would be fairly simple with the attached src.
sub BUILD {
my $self = shift;
my $default_config = $self->get_config_from_file('default.conf');
for my $attr ($self->meta->get_all_attributes) {
next if $attr->has_value($self);
next unless exists $default_config->{$attr->init_arg};
$attr->set_value($self, $default_config->{$attr->init_arg});
}
}
This got me really going - looking around in the vicinity of $self->meta->get_all_attributes(), found get_attribute(), which solves it all (I hope)
It is true that the current implementations for things like this aren't really ideal - they're all fairly old, and ConfigFromFile/SimpleConfig are also unmaintained. A better overall implementation might be nice, but you should talk about it either here or on IRC (#moose on irc.perl.org) to make sure your ideas for how it should look are reasonable(: -doy
Attached a small module and a smaller script and a bunch of cfg files - seems
to work
somehow, although I have not yet written any tests...
./foo.pl --configuration_file answer6.xml --configuratio answer7.xml
answer=42
answer0=answer1 answer1=answer1 answer2=answer2 answer3=config3 answer4=config4
answer5=config5 answer6=config7 answer7=config7 answer8=answer8 answer9=answer7
no more
Thanks for a swift response!
regards
Poul
--
print $Std{'Disclaimer'};
$CC = +-1; # the Computer Constant - very useful when writing loops. #
$|=printf "Just another [lazy] %s hacker\r",("PERL","perl")[$i+sleep 1] #
while $i=$i?0:$CC,1; ###
__EOF__
foo.pl
Description: Perl program
package Foo;
use Moose;
use Carp;
use English '-no_match_vars';
with qw(
MooseX::SimpleConfig
MooseX::Getopt
);
# MooseX::SimpleConfig is currently required by merge_config_from_file()
# which is implemented using get_config_from_file()
# This is on the "TO-BE-DONE" list somewhere...
use MooseX::Attribute::ENV;
use MooseX::SemiAffordanceAccessor;
=head1 NAME
Foo - Configuration of attribute-values
=head1 SYNOPSIS
use Foo;
=head2 ATTRIBUTES
=over 4
=item I<answer>
Default is c<42> (if course).
It takes the value of the environment variable B<ANSWER> .
It may be set in configuration files or on command-line
=cut
has answer =>
(
is => 'rw',
isa => 'Str',
traits => [ 'ENV' ],
env_key => 'ANSWER',
default => 42,
);
=item I<answer\d>
different answers (may be to the same question, I don't know)
=cut
has answer0 => ( is => 'rw', isa => 'Str', default => "answer1", );
has answer1 => ( is => 'rw', isa => 'Str', default => "answer1", );
has answer2 => ( is => 'rw', isa => 'Str', default => "answer2", );
has answer3 => ( is => 'rw', isa => 'Str', default => "answer3", );
has answer4 => ( is => 'rw', isa => 'Str', default => "answer4", );
has answer5 => ( is => 'rw', isa => 'Str', default => "answer5", );
has answer6 => ( is => 'rw', isa => 'Str', default => "answer6", );
has answer7 => ( is => 'rw', isa => 'Str', default => "answer7", );
has answer8 => ( is => 'rw', isa => 'Str', default => "answer8", );
has answer9 => ( is => 'rw', isa => 'Str', default => "answer7", );
=item I<configuration_file>
specify a ref. to a list of configuration files.
Loads the configuration files specified every time it is assigned a new value.
Thw write-accessor is I<configuration_file>( ), while the read-accessor is
I<get_configuration_file>().
=cut
has configuration_file =>
(
is => 'rw',
isa => 'ArrayRef[Str]',
default => sub { [] },
reader => 'get_configuration_file',
writer => 'configuration_file',
trigger => sub {
my ( $self, $new, $old ) =...@_;
$self->merge_config_from_file( @$new );
},
);
=back
=head2 METHODS
=over 4
=item $foo->I<merge_config>( CONFIG );
Takes C<CONFIG> - a reference to a HASH - and merges all its values into C<$foo>
(using the hash-key as attribute-name). Croak's if a hash-key does not match an
attribute name.
Example:
$foo->merge_config( { verbose => 1, dryrun => 1 } );
=cut
sub merge_config {
my ( $self, $config ) = @_;
foreach my $attrname ( keys %$config ) {
my $attr = $self->meta()->get_attribute( $attrname );
if ( defined( $attr ) ) {
$attr->set_value( $self, $config->{$attrname} );
}
else {
croak( "invalid configuration key '$attrname' found" );
}
}
}
=item $foo->I<merge_config_from_file>( FILE, ... );
For each C<FILE> specified, load the configuration and merges it into C<$foo>.
The same rules as with I<merge_config> applies here.
Example:
$foo->merge_config_from_file( qw( /etc/foo.xml ./foo.ini ) );
=cut
sub merge_config_from_file {
my ( $self, @files ) = @_;
foreach my $file ( @files ) {
unless (
eval {
$self->merge_config( $self->get_config_from_file( $file ) );
1;
}
) {
croak( "$EVAL_ERROR in configuration file '$file'" );
}
}
}
=back
=cut
__PACKAGE__->meta->make_immutable;
no Moose;
1;
__END__
<config><answer1>config1</answer1></config>
<config><answer2>config2</answer2></config>
<config><answer3>config3</answer3></config>
<config><answer4>config4</answer4></config>
<config><answer5>config5</answer5></config>
<config><answer6>config6</answer6></config>
<config><answer7>config7</answer7> <answer6>config7</answer6></config>
