pileofrogs has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, wise Monks!

How do you get a ref to a method? EG, if I want a ref to Foo->new(), how do I do that? I can get a ref to Foo::new, but that doesn't do what I want. EG:

use Foo; my $new = \&Foo::new; my $obj = &$new(); # Bzzzt! without the ->, it doesn't pass the class # name as the 1st arg $new = sub { return Foo->new(@_) }; $obj = &$new(); # does what I want, but is this necessary?
I want to do this to make my tests simpler. I want to pass a code ref to a run_test() sub.

Replies are listed 'Best First'.
Re: Ref to Method?
by almut (Canon) on Mar 04, 2009 at 19:43 UTC

    In theory, you could bless your code reference $new into the package Foo, in order to associate a type with it:

    package Foo; sub new { my $arg = shift; my $class = ref($arg) || $arg; # finally some use for this cargo- +cult thing :) print "creating object of type $class\n"; return bless {}, $class; } package main; use strict; use warnings; my $new = bless \&Foo::new, "Foo"; # code object # and then one of: my $obj; $obj = $new->(ref($new)); # passes "Foo" $obj = $new->($new); # passes code object of type Foo $obj = $new->new(); # passes code object of type Foo $obj = $new->$new(); # passes code object of type Foo

    But don't do it, it's too confusing...  Also, you couldn't store/pass around any other args this way, as with the closure.

Re: Ref to Method?
by Bloodnok (Vicar) on Mar 04, 2009 at 19:13 UTC
    can returns a code ref - but you have to emulate the class/object invocation ... does this help ?

    Running this:

    package foo; sub bar { warn "$self(@_)" } sub tell { $ref = \&bar; warn "$ref" } package main; $ref = foo->can('bar'); warn "$ref"; &$ref('foo'); foo->tell();
    results in...
    CODE(0x914dfb8) at tst.pl line 9. (foo) at tst.pl line 3. CODE(0x914dfb8) at tst.pl line 4.

    A user level that continues to overstate my experience :-))

      That may be more obviously a method call as:

      my $ref = foo->can('bar'); warn "$ref"; foo->$ref(); foo->tell();
Re: Ref to Method?
by Narveson (Chaplain) on Mar 04, 2009 at 19:39 UTC

    I'm intrigued. Presumably the run_test sub can test a variety of methods in different packages, thus saving you some typing and giving you all the benefits that flow from Not Repeating Yourself.

    Could you possibly share an example?

    The benefits may be worth the tedium of having to type

    $new = sub { return Foo->new(@_) }; run_test( $new );

    Then again, Perl can save you this tedium by way of a wrapper for run_test. How about the following? (Untested.)

    sub test_package_method { my ($package, $method) = @_; my $code_ref = sub{ return $package->$method() }; run_test( $code_ref ); }

      Yup. That's the basic idea. A huge number of tests I write look like:

      my $thing = eval { blort($value) }; ok( !$@, 'blort didn't blow up') || diag $@;

      If I can, I like to populate a data structure with test specifics and then run a sub against the contents of that structure. One nice side affect is you can calculate plan tests => X. Ultimately, I'd like to be able to write tests in a config file.

Re: Ref to Method?
by ikegami (Patriarch) on Mar 04, 2009 at 19:46 UTC

    First, note that \&Foo::new is wrong for methods. It'll break if the method is inherited. That's why can should be used instead.

    How do you get a ref to a method

    my $method_ref = $obj_or_class->can('method');

    or even just

    my $method_name = 'method';

    You call it as follows:

    $obj_or_class->$method_ref()
    $obj_or_class->$method_name()

    It seems you might actually want to get a code reference to a method call. Yes, the following is necessary, because you can't get a code reference to an operator. They have insufficient information to be executed.

    $ref = sub { $obj_or_class->new(@_) }
Re: Ref to Method?
by zwon (Abbot) on Mar 04, 2009 at 18:53 UTC

    You can't, as Foo in Foo->new() is actually a parameter of the method.