I'm using Moose to create an object but the builder method '_initialize_log' is not able to retrieve the value of the name attribute.
Is there a way for me to run the method only after that attribute has been set?
EFT.pm
package EFT;
use Moose;
# Attributes
has name => (
is => "ro",
isa => "Str",
required => 1
);
has log => (
is => 'rw',
isa => 'Str',
builder => '_initialize_log'
);
sub _initialize_log
{
$self->{'log'} = "****\n";
$self->{'log'} .= $self->{'name'} . "\n";
$self->{'log'} .= `date`;
$self->{'log'} .= "****\n";
}
test.pl
#!/usr/bin/perl
use strict;
use warnings;
use EFT;
# Constants
use constant NAME => 'Test Script';
# Create script object
my $script = EFT->new(name => NAME);
print $script->{'log'};
Output
Use of uninitialized value in concatenation (.) or string at EFT.pm line 46.
****
Thu Mar 3 12:54:31 EST 2016
****
The object is still being constructed! Delay your attribute's initialization until after it's constructed. The following delays its initialization until it's used:
lazy => 1
You could also use a BUILD
method instead.
sub BUILD {
my $self = shift;
$self->_initialize_log();
}
Note that you had three bugs in _initialize_log
:
sub _initialize_log
{
my $self = shift; # <-- Won't even compile without this!
my $log = "****\n";
$log .= $self->name . "\n"; # <-- Removed reliance on Moose internals
$log .= `date`;
$log .= "****\n";
return $log; # <-- The value is to be returned.
}
To call it from BUILD
instead of as a builder, you'll need to change it as follows:
sub _initialize_log
{
my $self = shift;
my $log = "****\n";
$log .= $self->name . "\n";
$log .= `date`;
$log .= "****\n";
$self->log($log); # <--
}