Question

I have a class with an attribute set up as follows:

has _data => (
    is => 'ro',
    lazy => 1,
    builder => '_load',
);

sub _load {
    my $self = shift;
    return retrieve $self->_file;
}

However I now want to call a method already defined on the class before returning the data.

In old-school Perl OO, I'd be doing something like this:

sub _load {
    # Assuming laziness is implemented somewhere else.
    my $self = shift;
    $self->{_data} = retrieve $self->_file;
    $self->refresh;  # which does something with $self->{_data}
    return $self->{_data};
}

But I can't figure out a 'clean' way to do this in Moose.

I've considered the following, but think they are quite ugly, and that there must be a better way of doing this.

  • If I make _data read-write, I could potentially write the data to the accessor, call the method then return the value from the accessor for Moose to write back to the accessor.
  • If I turn it into a plain old method then I'd have to define another attribute, say _raw_data, store the data in there, modify refresh() to use that attribute, and everything else uses _data().
  • Violate encapsulation and access the underlying $self->{_data} directly.

I tried an after '_load' => \&refresh;, but that just created an endless loop.

Was it helpful?

Solution

This would be a nice use of triggers:

has _data => (
   is      => 'ro',
   lazy    => 1,
   builder => '_load',
   trigger => sub { shift->refresh },
);

Except that triggers don't work on default/built values - only on values passed to the constructor explicitly, or passed to a writer/accessor method. Sad face. :-(

One solution would be to rewrite your refresh method so that instead of operating on $self->_data, it can accept a parameter (perhaps falling back to operating on $self->_data if no parameter is given.

sub _load {
   my $self = shift;
   my $tmp = retrieve $self->_file;
   $self->refresh($tmp);
   return $tmp;
}

sub refresh {
   my $self = shift;
   my $data = scalar(@_) ? $_[0] : $self->_data;
   # do something with $data
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top