On 10/10/10 23:32, Jesse Luehrs wrote:
On Sun, Oct 10, 2010 at 10:00:17PM +0200, "Poul H. Sørensen" wrote:
Hi

I'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__

Attachment: 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>

Reply via email to