2010-12-09 46 views
6

Je voudrais obtenir dynamiquement une liste des noms de fonctions (en tant que chaînes) ou des références de fonctions à partir de n'importe quel module Perl disponible sur mon système. Ceci inclurait des modules qui peuvent ou non avoir, par exemple, un tableau global @EXPORT_OK dans son espace de noms. Un tel exploit est-il possible? Comment l'arracher si c'est le cas?Puis-je obtenir dynamiquement une liste de fonctions ou de noms de fonctions à partir de n'importe quel module Perl?

Edit: De la lecture perlmod, je vois que %Some::Module:: sert de table de symboles pour Some::Module. Est-ce le bon endroit pour regarder? Si oui, comment est-ce que je peux réduire la table juste aux noms de fonction dans Some::Module?

Répondre

7

Vous êtes sur la bonne voie. Pour Wittle sur la table pleine de symbole pour seulement les sous-marins, quelque chose comme cela peut être fait (Pointe du chapeau « Mastering Perl », ch 8, pour la version principale de l'emballage de ce):

use strict; # need to turn off refs when needed 
package X; 

sub x {1;}; 
sub y {1;}; 
our $y = 1; 
our $z = 2; 

package main; 

foreach my $entry (keys %X::) { 
    no strict 'refs'; 
    if (defined &{"X::$entry"}) { 
     print "sub $entry is defined\n" ; 
    } 
} 

# OUTPUT 
sub y is defined 
sub x is defined 
+0

Neat. Je pense que je m'apprêtais à étudier la soumission du CPAN, 'Symbol :: Table', mais ses méthodes sont un peu avancées pour moi. –

+0

Cela échouera si collé dans un fichier avec 'use strict' en haut. Pour éviter les surprises, et pour préciser que c'est une technique avancée, ajoutez 'no strict 'refs'' avant' if (defined & {"X :: $ entry"}) {' – Narveson

+0

@Narveson, cela ne serait pas travailler, et ce n'est pas si terrible. Les scalaires du paquet X ont juste besoin d'avoir 'our' en face d'eux. –

7

Vous pouvez trouver ce simple script pratique:

#!/usr/bin/env perl 
use strict; 
use warnings;  
use Data::Dumper; 

# dump of object's symbol table: 
foreach my $className (@ARGV) 
{ 
    print "symbols in $className:"; 

    eval "require $className"; 
    die "Can't load $className: [email protected]" if [email protected]; 

    no strict 'refs'; 
    print Dumper(\%{"main::${className}::"}); 
} 

Mais, si vous faites cela dans le code de production, j'utiliser Package::Stash à la place:

my @subs_in_foo = Package::Stash->new('Foo')->list_all_symbols('CODE'); 
+0

Heureux que vous avez dit 'use strict' et le' top 'et 'pas de' refs 'strict si nécessaire. – Narveson

0

J'utilise Perl 5.20 . Cela fonctionne sur ma machine:

use strict; 

package foo; 
    our $some_var; 
    sub func1 { return 'func1'} 
    sub func2 { return 'func2'} 

package main; 
    sub callable { 
     my ($x) = @_; 
     return defined(&$x); 
    } 

    while (my ($k, $v) = each(%foo::)) { 
     if (callable($v)) { 
     print("$k\n"); 
     } 
    } 

    # output: 
    # func1 
    # func2