2010-04-01 9 views
6

Actualmente uso un bloque eval para probar que he establecido un atributo como de solo lectura. ¿Hay una manera más simple de hacer esto?¿Existe alguna manera simple de probar si un atributo de Moose es de solo lectura?

Ejemplo de código de trabajo:

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



ACTUALIZACIÓN

Gracias a Friedo, éter, y Robert P por sus respuestas y éter, Robert P, y jrockway por sus comentarios.

me gusta como la respuesta de éter asegura que $is_read_only es más que un valor verdadero o falso (es decir, pero nunca un coderef) negándola con un !. Double negation también proporciona eso. Por lo tanto, puede usar $is_read_only en una función is(), sin que imprima el valor del código.

Consulte la respuesta de Robert P a continuación para la respuesta más completa. Todos han sido muy útiles y se han basado en las respuestas y los comentarios de los demás. En general, creo que me ha ayudado más, por lo tanto, ahora está marcado como la respuesta aceptada. De nuevo, gracias a Ether, Robert P, friedo y jrockway.



En caso puede que se pregunte, como lo hice al principio, aquí es la documentación sobre la diferencia entre get_attribute y find_attribute_by_name (from Class::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. 
+0

eso sería mejor escribir como 'OK ($ snp_obj -> meta-> get_attribute ('sample_for') -> get_write_method(), "'sample_for' es de solo lectura"); '- en prueba fallida,' is() 'imprime el segundo argumento (que sería un coderef) ... sin mencionar que tiene los argumentos primero y segundo invertidos: 'is ($ has, $ expected, $ test_name)'. – Ether

+0

Si su matriz @attribute_names está cuidadosamente construida, debería estar bien; pero si el atributo no existe explotarás :) –

+0

+1 para saber cómo localizar el atributo en la superclase – user1027562

Respuesta

5

Técnicamente, un atributo no necesita tener un método de lectura o de escritura. La mayoría del tiempo lo hará, pero no siempre. Un ejemplo (robados gracia de jrockway's comment) es el siguiente: existirá

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

Este atributo, pero no tiene lectores y escritores estándar.

Para probar en cada situación que un atributo se ha definido como is => 'RO', debe comprobar tanto el método de escritura como el método de lectura.Se podía hacerlo con este subprograma:

# 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()); 
} 

Como alternativa, puede agregar una doble negación antes de la última return a boolify el valor de retorno:

return !! (! $attribute->get_write_method() && $attribute->get_read_method()); 
+1

Me encanta el primer ejemplo;) – jrockway

5

como se documenta en 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() obtendrá el método de escritura (ya sea eated o uno que se generó), o undef si no hay uno.

+0

¡Gracias! Sabiendo que devuelve 'undef' permite una prueba de una línea (traté de publicarlo aquí, pero no se veía muy bonito). –

+0

Bueno, en realidad ... Eso prueba si tiene un método de escritura. Eso no prueba si tiene un método de lectura. No tiene que tener ninguno, técnicamente. No es un atributo muy útil si no lo es, ¡pero puede tenerlo! –

+0

@Robert: estrictamente hablando, comprueba que el atributo "no se puede escribir" (no isa => 'rw'), que no es lo mismo que "solo lectura" (isa => 'ro'). – Ether

3

Usted debe ser capaz de obtener esta información de metaclase del objeto:

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

Ver Class::MOP::Attribute por más.

+0

Gracias! Eso es lo que necesitaba. –

Cuestiones relacionadas