Answer the question
In order to leave comments, you need to log in
Perl, Moose, attribute handling
I got lost in the rich forest of Moose possibilities.
How do I process an attribute after it has been set via attribute accessor or constructor?
Let's say there is:
package MyMod;
use Moose;
has 'page' => (
is => 'rw',
required => 1,
);
$mm = MyMod->new( page => 'abcd/efgh');
$mm->page('fghj/asdf');
Answer the question
In order to leave comments, you need to log in
has 'page' => (is => 'rw', isa => 'Str');
has '_page' => (is => 'rw', isa => 'Str', lazy_build => 1);
sub _build__page {
my $self = shift;
return $self->{page} =~ s/^.+\/(.+)$/$1/r;
}
around 'page' => sub {
my $orig = shift;
my $self = shift;
if (@_) {
$self->$orig(@_);
$self->_clear_page;
}
return $self->_page;
};
1. immediately process the attribute value set through the (new) constructor only in the BUILDARGS method (we get access to the attribute hash before creating the object) or BUILD (we process the attributes immediately after the object is created), method modifiers (before, around, trigger) do not are called when the attribute is set in the constructor;
2. you can use trigger (called when the value is set);
3. you can use around, check and change the value with each call, if necessary;
You cannot change the value through a trigger, it is called after the value is set. You can only understand if the value has been changed or not.
If you refer to $self->page('xxx') in the trigger, there will be an endless recursion.
You need this in the trigger: $self->{page} = 'xxx' is a direct access to the class attribute in perl, bypassing Moose method modifiers. In this case, there will be no recursion, because the trigger will not be called a second time from itself.
You can only do it through around, it will work in any case when you get the value of the attribute. Then in around you will need to do a substitution every time you get a value or create a separate meta-attribute in which to store the flag - whether the value is processed or not ...
There are no other ways, modifiers are not called from new, that's the whole point.
You can still like this :)))
Get extra. the _page attribute and store the changed value in it. Make it lazy_build => 1.
Create a _page builder:
sub _build__page {
my $self = shift;
return $self->{page} =~ s/\///g; #именно так, чтобы не возникало рекурсии при вызове из around ниже
}
if(@_){ #если устанавливаются параметры - очищаем _page, чтобы при следующем обращении вызвался его билдер
$self->_clear_page;
}
$self->$orig(@_); #проксируем на оригинальный метод
return $self->_page;#если мы меняем значение - будет вызван билдер для _page, его результат сохранится в _page и вернется, если не меняем вернется значение _page, которое там было раньше, второй раз код подмены для одного и того-же значения выполнятся не будет
optimized around:
if(@_){
$self->_clear_page;
$self->$orig(@_); #proxy to original method only if value is set
}
return $self->_page;
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question