问题描述:

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);              # <--
}
相关阅读:
Top