2010-04-27 15 views
6

Estoy tratando de escribir un código abstracto para buscar a través de una lista de objetos similares para el primero cuyos atributos coinciden con valores específicos. Para hacer esto, necesito llamar a un grupo de métodos de acceso y verificar todos sus valores uno por uno. Me gustaría utilizar una abstracción de esta manera:En Perl, ¿cómo puedo llamar a un método cuyo nombre tengo en una cadena?

sub verify_attribute { 
    my ($object, $attribute_method, $wanted_value) = @_; 
    if (call_method($object, $attribute_method) ~~ $wanted_value) { 
     return 1; 
    } 
    else { 
     return; 
    } 
} 

Entonces puede recorrer un hash cuyas claves son los nombres de métodos de descriptor de acceso y cuyos valores son los valores que estoy buscando para esos atributos. Por ejemplo, si ese hash se llama %wanted, puede ser que utilice un código como este para encontrar el objeto que quiero:

my $found_object; 
FINDOBJ: foreach my $obj (@list_of_objects) { 
    foreach my $accessor (keys %wanted) { 
     next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor}); 
    } 
    # All attrs verified 
    $found_object = $obj; 
    last FINDOBJ; 
} 

Por supuesto, el único problema es que no call_method exsit. O lo hace? ¿Cómo puedo llamar a un método si tengo una cadena que contiene su nombre? ¿O hay una mejor solución para todo este problema?

Respuesta

5
my $found_object; 
FINDOBJ: foreach my $obj (@list_of_objects) { 
    foreach my $accessor (keys %wanted) { 
    next FINDOBJ unless $obj->$accessor() == $wanted{$accessor}; 
    } 
    # All attrs verified 
    $found_object = $obj; 
    last; 
} 

Sí, puede llamar a los métodos de esta manera. No hay cadena (ni ninguna otra) evaluación involucrada. También, sustituir == con eq=~ o en función del tipo de los datos ...

O, para algunos créditos adicionales, hacerlo de la manera funcional: (todo() debería realmente ser parte de la lista :: Util!)

use List::Util 'first'; 

sub all (&@) { 
    my $code = shift; 
    $code->($_) || return 0 for @_; 
    return 1; 
} 

my $match = first { 
        my $obj = $_; 
        all { $obj->$_ == $attrs{$_} } 
         keys %wanted 
        } @list_of_objects; 

Actualización: Es cierto que la primera solución es la menos ofuscada, por lo que es preferible. Pero como alguien que responde preguntas, ¡has añadido un poco de azúcar para que también te resulte interesante! ;-)

+0

Ye ah, acabo de descifrar esto hace unos pocos siglos por ensayo y error. Guay. –

+1

Solo uso 'List :: AllUtils'. O 'Util :: Any qw (: all)'. Pero en mi código de ejemplo trato de mantenerme en el núcleo. –

+0

Creo que para que esto funcione debes desactivar las verificaciones de rigor con 'no strict;' (no necesariamente globalmente) - ¿correcto? –

0

manera funcional es bueno, pero para principiantes como yo reglas: eval

test.pl

#!/usr/bin/perl -l 
use F; 
my $f = F->new(); 

my $fun = 'lol'; # method of F 

eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var 

F.pm

package F; 

sub new 
{ 
    bless {}; 
} 


sub lol 
{ 
    print "LoL"; 
} 
1; 

[root @ ALT-24 raíz] # perl test.pl

LoL

Cuestiones relacionadas