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. :(
Have you tried UNIVERSAL's can method? You should be able to implement something like this:
I made a useless, one-line example to demonstrate:
But for clarity, I'd probably still write it as:
Is there a reason you are storing subroutine names instead of the references to code?
e.g.
You won't be passing the class name, but if that's important to you, you can use something like