How can I create my Perl Moose class such that multiple mutually-dependent attributes are built in the proper order? In my case, I want to configure my Log::Log4perl object from a configuration file that is specified in my main configuration file.
If the initialization is truly mutually-dependent, you have a problem, since one of the attributes must necessarily be initialized before the other. But nothing about your description supports this. It sounds like creating the logger requires the config file, and that's it.
Just make the creation of logger lazy, giving config a chance to be set.
package Class;
use Moose;
has config => ( ... );
has logger => (
isa => 'Str',
is => 'ro',
lazy => 1,
default => sub {
my $self = shift;
my $config = $self->config
or die(...);
return Log::Log4perl->get_logger( $config->{logger} );
},
handles => [qw( info warn error fatal )],
);
Sample usage
my $o = Class->new( config => "..." );
$o->warn("...");
or
# Assuming config isn't required=>1.
my $o = Class->new();
$o->config("...");
$o->warn("...");
You can use the before method modifier (method hook) to force the attributes to build in a specific order:
package Z;
use Moose;
has config => (
isa => 'HashRef',
is => 'ro',
lazy => 1,
default => sub { print STDERR "called 'config'\n"; return { a => 'b' }; },
);
has logger => (
isa => 'Str',
is => 'ro',
lazy => 1,
default => sub { print STDERR "called 'logger'\n"; return 'Fred'; }
);
before 'logger' => sub {
my $self = shift;
print STDERR "called before 'logger'\n";
die "No logger!: $!\n" if !defined $self->config;
return;
};
package A;
my $z = Z->new();
print "logger: ", $z->logger, "\n";
print "config{a}: ", $z->config->{a}, "\n";
The output of this sample code, showing that config is built before logger via the before method modifier:
called before 'logger'
called 'config'
called 'logger'
logger: Fred
config{a}: b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With