Замыкайте метод модификатор, сеттер и конструктор (новый): перехватывать все обновления атрибута - PullRequest
1 голос
/ 30 января 2012

Обновление

Код, который я разместил в моем первоначальном вопросе, иллюстрировал, как модификатор метода работает или не работает.Это не обязательно было иллюстрацией описания проблемы, которое я дал.Этот код должен быть.Это работает, но содержит взлом в триггере, который я использовал, чтобы кодировать требование отслеживания всех обновлений и действия на них в зависимости от значения, предоставленного сеттеру.делать работу.Обилие функций и возможностей не всегда делает вещи проще.По крайней мере, когда вы пытаетесь не изобретать какие-либо колеса и повторно использовать то, что можно использовать повторно.

Исходный вопрос

Похоже, модификатор метода around не вызывается как часть построения объекта(при звонке new).Тестовый пример здесь:

package Bla;
use Moose;
has 'eins', is => 'rw', isa => 'Int';
has 'zwei', is => 'rw', isa => 'Num';

around [qw/ eins zwei /] => sub {
    my $orig = shift;
    my $self = shift;
    return $self->$orig unless @_;
    my $val = shift;
    if ( $val == int $val ) {
        return $self->$orig( $val );
    }
    else {
        return $self->$orig( 1 );
        warn "replaced $val by 1";
    }
};

package main;
use Test::More;
use Test::Exception;

dies_ok { Bla->new( eins => 33.33 ) } 'dies because of Int type constraint';
my $bla = Bla->new( zwei => 22.22 );
is $bla->zwei, 22.22, 'around has not been called';
done_testing;

Позвольте мне объяснить, чего я хочу достичь.Есть класс, который имеет quantity и price (и еще несколько состояний).Когда приходит количество (через new или через сеттер, мне все равно), я хочу убедиться, что оно заканчивается как целое число (отсюда и ограничение).Если это не целое число, я хочу заменить его просто на 1 и сделать некоторые другие обновления объекта, например, сохранить исходное количество и умножить цену на исходное количество.И для конструктора, и для сеттера.

Что мне делать?Укажите подпрограмму, которая выполняет эту работу, и вызовите ее из around BUILDARGS и around quantity?

Ответы [ 2 ]

2 голосов
/ 31 января 2012

Когда я продолжаю бегать по стенам, я знаю, что сделал что-то не так, и я бегу по стенам. Дизайн отстой. Я думаю, что ключевая проблема в том, что у вас есть одно поле, служащее двум целям.

Если единственной целью orig_quantity является нормализация цены, я предложил вам нормализовать quantity и price после того, как они установлены. Это может быть сделано явно, или это может быть сделано неявно, когда вы пытаетесь получить их, как показано ниже.

has price => (
   accessor => '_price',
   isa      => 'Num',
   handles  => {
      price => sub {
         my $self = shift;
         return $self->_price(@_) if @_;
         $self->normalize();
         return $self->_price();
      },
   },
);

has quantity => (
   accessor => '_quantity',
   isa      => 'Num',
   handles  => {
      quantity => sub {
         my $self = shift;
         return $self->_quantity(@_) if @_;
         $self->normalize();
         return $self->_quantity();
      },
   },
);

sub normalize {
   my ($self) = @_;
   my $quantity = $self->_quantity();
   return if is_an_int($quantity);
   $self->_quantity(1);
   $self->_price($self->_price() / $quantity);
}

Если вам действительно нужно orig_quantity, то вы, вероятно, хотите, чтобы конструктор установил это напрямую и сделал quantity производным значением.

2 голосов
/ 31 января 2012

Как насчет этого?

package Bla;
use Moose;
use Moose::Util::TypeConstraints;

subtype 'MyInt',
  as 'Int';

coerce 'MyInt',
  from 'Num',
  via { 1 };

has 'eins', is => 'rw', isa => 'Int';
has 'zwei', is => 'rw', isa => 'MyInt', coerce => 1;

package main;
use Test::More;
use Test::Exception;

dies_ok { Bla->new( eins => 33.33 ) } 'dies because of Int type constraint';
my $bla = Bla->new( zwei => 22.22 );
is $bla->zwei, 1, '22.22 -> 1';

my $bla2 = Bla->new( zwei => 41 );
is $bla2->zwei, 41, '41 -> 41';

done_testing;
...