2015-07-15 2 views
0

Я хочу изменить значение атрибута каждый раз, когда оно установлено, независимо от того, выполнено оно внутри конструктора или «писателем» (я не использую «строитель» или «по умолчанию» в этом случае). В основном атрибут (необязательный тип «Str») передается конструктору, и в некоторых случаях я хочу изменить его значение после этого, но в каждом сценарии я хочу сделать некоторое регулярное выражение на нем (например).Принудительное принуждение в Moose

Мой первый подход состоял в том, чтобы использовать метод BUILDARGS и around, оба из которых будут использовать одну и ту же функцию регулярного выражения, но тогда я задаюсь вопросом о принуждении. Единственная проблема заключается в том, что я не знаю, как создать определение подтипа/типа, которое будет принудительным принуждением независимо от того, что.

Например:

package Foo; 
use Moose::Util::TypeConstraints; 

subtype 'Foo::bar' => as 'Str'; 
coerce 'Foo::bar' 
    => from 'Str' 
     => via { 
      $_ =~ s/some_stuff//g; 
      $_ =~ s/other_stuff//g; 
      $_ =~ s/some_other_stuff//g; 
     }; 

has 'bar' => (isa => 'Foo:bar', coerce => 1); 

Я не хочу, чтобы определить подтип/типа с 'где' п как

subtype 'Foo::bar' => as 'Str' => where {$_ !~ /some_stuff/ && $_ !~ /other_stuff/ && ... }; 

, потому что кажется утомительным для меня.

Редактировать: Я ищу для комплексного решения я мог бы использовать не только с атрибутами типа «ул», но также «ссылку на массив», «HashRef» и т.д.

+0

Вы говорите, что принуждение не всегда происходит? В какой ситуации значение не принуждено? – ikegami

+0

@ikegami Foo-> new (bar => 'Some string') Принуждение не произойдет, потому что прошедшее значение уже является строкой. «Принуждение позволяет вам указывать Moose для автоматического преобразования одного типа в другой», и оба типа ввода и вывода являются строкой. Я не настаиваю на использовании этого метода, просто ищу лучший вариант. – roland16

+0

Значит, вы говорите, что принуждения никогда не происходит? Пожалуйста, уточните, в чем проблема. По крайней мере, продемонстрируйте это! – ikegami

ответ

0

Похоже, вы хотите trigger.

package Foo; 
use Moose; 

has 'bar' => (
    is  => 'rw', 
    isa  => 'Str', 
    trigger => sub { 
     my ($self, $value, $old_value) = @_; 
say 'in trigger'; 
     # prevent infinite loop 
     return if $old_value && $old_value eq $value; 

     my $original_value = $value; 
     $value =~ s/some_stuff//g; 
     $value =~ s/other_stuff//g; 
     $value =~ s/some_other_stuff//g; 

     # prevent infinite loop 
     return if $value eq $original_value; 

say '... setting new value'; 
     $self->bar($value); 
    }, 
); 

package main; 

my $foo = Foo->new(bar => 'foo some_stuff and other_stuff and some_more_stuff'); 
say $foo->bar; 

Я хочу, чтобы изменить значение атрибута каждый раз, когда он не установлен, независимо от того, если это делается в конструкторе или с помощью «писателя» (я не использую «строитель» или «по умолчанию 'в этом случае)

Это именно то, что срабатывает триггер. Док говорит почти дословно, что вы просили:

ПРИМЕЧАНИЕ: Триггеры будут срабатывать только при назначении атрибуту либо в конструкторе, либо с использованием записи. Значения по умолчанию и встроенные значения не будут вызывать запуск триггера.

Edit: Существовал ошибка в обнаружении в Inifite цикла. Теперь он работает и останавливается при втором вызове. Я оставил вывод debug для демонстрации.

in trigger 
... setting new value 
in trigger 
foo and and some_more_stuff 
+0

Вы получите бесконечную рекурсию. Триггерные огни ** после ** атрибут установлен, и поскольку вы снова устанавливаете «бар» в подпункте, триггер попадает в бесконечный цикл. Вышеприведенный пример будет работать, если вы установите атрибут таким образом '$ self -> {bar} = 'modified_value' в триггерном суб, но из того, что я прочитал handle $ self, как хеш-ссылка, является плохой практикой. – roland16

+0

Первая версия моего ответа не имела бесконечного цикла. Фактически, это ничего не изменило, потому что у меня была ошибка. Я обновил ответ с помощью версии, которая будет делать то, что вы хотите, без создания цикла inifite. – simbabque

+0

Ну, ваш вопрос был для 'Str', и вы явно сказали, что не хотите проверять тип своей строки в последней части вопроса. Проверка, нуждается ли строка в этих заменах, именно то, что тип делает, на котором будет основываться принуждение. Для вещей, которые не являются строкой, я согласен с тем, что принуждение имеет гораздо больший смысл. Но вы спросили об очень конкретном случае, и это ответ на этот конкретный вопрос. Возьми это или оставь. :) – simbabque

Смежные вопросы