How do I call a function name that is stored in a hash in Perl?
I'm sure this is covered in the documentation somewhere but I have been unable to find it... I'm looking for the syntactic sugar that will make it possible to call a method on a class whose name is stored in a hash (as opposed to a simple scalar):
use strict; use warnings;
package Foo;
sub foo { print "in foo()\n" }
package main;
my %hash = (func => 'foo');
Foo->$hash{func};
If I copy $hash{func}
into a scalar variable first, then I can call Foo->$func
just fine... but what is missing to enable Foo->$hash{func}
to work?
(EDIT: I don't mean to do anything special by calling a method on class Foo
-- this could just as easily be a blessed object (and in my actual code it is); it was just easier to write up a self-contained example using a class method.)
EDIT 2: Just for completeness re the comments below, this is what I'm actually doing (this is in a library of Moose attribute sugar, created with Moose::Exporter):
# adds an accessor to a sibling module
sub foreignTable
{
my ($meta, $table, %args) = @_;
my $class = 'MyApp::Dir1::Dir2::' . $table;
my $dbAccessor = lcfirst $table;
eval "require $class" or do { die "Can't load $class: $@" };
$meta->add_attribute(
$table,
is => 'ro',
isa => $class,
init_arg => undef, # don't allow in constructor
lazy => 1,
开发者_如何学编程 predicate => 'has_' . $table,
default => sub {
my $this = shift;
$this->debug("in builder for $class");
### here's the line that uses a hash value as the method name
my @args = ($args{primaryKey} => $this->${\$args{primaryKey}});
push @args, ( _dbObject => $this->_dbObject->$dbAccessor )
if $args{fkRelationshipExists};
$this->debug("passing these values to $class -> new: @args");
$class->new(@args);
},
);
}
I've replaced the marked line above with this:
my $pk_accessor = $this->meta->find_attribute_by_name($args{primaryKey})->get_read_method_ref;
my @args = ($args{primaryKey} => $this->$pk_accessor);
PS. I've just noticed that this same technique (using the Moose meta class to look up the coderef rather than assuming its naming convention) cannot also be used for predicates, as Class::MOP::Attribute does not have a similar get_predicate_method_ref
accessor. :(
Foo->${\$hash{func}};
But for clarity, I'd probably still write it as:
my $method = $hash{func};
Foo->$method;
Is there a reason you are storing subroutine names instead of the references to code?
e.g.
use strict; use warnings;
package Foo;
sub foo { print "in foo()\n" }
package main;
my %hash = (func => \&Foo::foo);
$hash{func}->();
You won't be passing the class name, but if that's important to you, you can use something like
my %hash = ( func => sub { return Foo->foo(@_) } );
Have you tried UNIVERSAL's can method? You should be able to implement something like this:
## untested
if ( my $code = $object->can( $hash{func} ) ) {
$object->$code();
}
I made a useless, one-line example to demonstrate:
perl -MData::Dumper -le 'my %h = ( f => "Dump" ); my $o = Data::Dumper->new( [qw/1 2 3/] ); my $ref = $o->can( $h{f} ); print $o->$ref()'
精彩评论