Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Moose, if a role defines an attribute with a default, how do I change that default in my consuming class?

Tags:

perl

moose

moo

My Moose class consumes a role which I'm not allowed to change. That role defines an attribute with a default. I need my class to have that attribute, but with a different default.

Is that possible?

All I could come up with is surrounding the "new" method with some of my own code, as follows:

around new => sub {
    my ($orig, $self) = (shift, shift);
    return $self->$orig(@_, the_attribute => $new_value);
}

But I'm not sure if surrounding new is valid, and was also hoping for something more elegant.

like image 511
alexk Avatar asked Dec 15 '22 13:12

alexk


2 Answers

A better, simpler way is to write this in your class:

has '+the_attribute' => (
    default => sub{1},
}

has with a + lets you override just a specific property of an attribute.

Much simpler than surrounding BUILDARGS.

like image 181
alexk Avatar answered May 24 '23 07:05

alexk


You have the right idea, but you shouldn't override new. Moose::Manual::BestPractices says:

Never override new

Overriding new is a very bad practice. Instead, you should use a BUILD or BUILDARGS methods to do the same thing. When you override new, Moose can no longer inline a constructor when your class is immutabilized.

It's been a while since I've done this, but I think the following will do the trick:

around BUILDARGS => sub {
   my $orig  = shift;
   my $class = shift;
   return $self->$orig(
      the_attribute => $new_value,
      @_ == 1 ? %{ $_[0] } : @_,
   );
};

Notes:

  • I placed the new attribute first to allow it to be overridden.
  • I made it so both ->new({ ... }) and ->new(...) still work. You could use @_ instead of @_ == 1 ? %{ $_[0] } : @_ if you don't care about breaking ->new({ ... }).
like image 29
ikegami Avatar answered May 24 '23 08:05

ikegami