Есть ли простой способ проверить, доступен ли атрибут Moose только для чтения? - PullRequest
6 голосов
/ 01 апреля 2010

В настоящее время я использую блок eval, чтобы проверить, что я установил атрибут только для чтения.Есть ли более простой способ сделать это?

Пример из рабочего кода:

#Test that sample_for is ready only
eval { $snp_obj->sample_for('t/sample_manifest2.txt');};
like($@, qr/read-only/xms, "'sample_for' is read-only");



ОБНОВЛЕНИЕ

Благодаряfriedo, Ether и Robert P за их ответы и Ether, Robert P и jrockway за их комментарии.

Мне нравится, как ответ Ether гарантирует, что $is_read_only является только истинным илиложное значение (т. е. но не кодовая ссылка), отрицая его с помощью !. Двойное отрицание также обеспечивает это.Таким образом, вы можете использовать $is_read_only в функции is(), не печатая кодовую ссылку.

См. Ответ Роберта П. ниже для наиболее полного ответа.Все были очень полезны и опирались на ответы и комментарии друг друга.В целом, я думаю, что он помог мне больше всего, следовательно, теперь он помечен как принятый ответ.Опять же, благодаря Ether, Robert P, friedo и jrockway.



На случай, если вам интересно, как я это делал сначала, вот документация о разнице между get_attribute иfind_attribute_by_name ( из класса :: MOP :: Class ):

$metaclass->get_attribute($attribute_name)

    This will return a Class::MOP::Attribute for the specified $attribute_name. If the 
    class does not have the specified attribute, it returns undef.

    NOTE that get_attribute does not search superclasses, for that you need to use
    find_attribute_by_name.

Ответы [ 3 ]

5 голосов
/ 02 апреля 2010

Технически, атрибут не должен иметь метод чтения или записи. Большую часть времени это будет, но не всегда. Пример (любезно украденный из комментария jrockway ) приведен ниже:

has foo => ( 
    isa => 'ArrayRef', 
    traits => ['Array'], 
    handles => { add_foo => 'push', get_foo => 'pop' }
)

Этот атрибут будет существовать, но не будет иметь стандартных читателей и писателей.

Таким образом, чтобы проверить в каждой ситуации, что атрибут был определен как is => 'RO', вам необходимо проверить и метод записи, и метод чтения. Вы можете сделать это с помощью этой подпрограммы:

# returns the read method if it exists, or undef otherwise.
sub attribute_is_read_only {
    my ($obj, $attribute_name) = @_;
    my $attribute = $obj->meta->get_attribute($attribute_name);

    return unless defined $attribute;
    return (! $attribute->get_write_method() && $attribute->get_read_method());
}

Кроме того, вы можете добавить двойное отрицание перед последним return, чтобы увеличить возвращаемое значение:

return !! (! $attribute->get_write_method() && $attribute->get_read_method());
5 голосов
/ 01 апреля 2010

Как указано в Class :: MOP :: Attribute :

my $attr = $this->meta->find_attribute_by_name($attr_name);
my $is_read_only = ! $attr->get_write_method();

$attr->get_write_method() получит метод записи (либо созданный вами, либо созданный) или undef, если его нет.

3 голосов
/ 01 апреля 2010

Вы должны получить это из метакласса объекта:

unless ( $snp_obj->meta->get_attribute( 'sample_for' )->get_write_method ) { 
    # no write method, so it's read-only
}

Подробнее см. Класс :: MOP :: Атрибут .

...