Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Dynamic Package Name & Subroutine Call

by awohld (Hermit)
on Dec 14, 2012 at 22:24 UTC ( #1008906=perlquestion: print w/ replies, xml ) Need Help??
awohld has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to call a package dynamically and pass data to a subroutine inside the dynamically chosen package. How can I get this to work?
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @pkgs = qw( One Two ); foreach my $pkg ( @pkgs ) { # this is the part I can't figure out... Test::$pkg::hello($pkg); } package Test::One; sub hello{ my $var = shift; print "Hello: $var\n"; } 1; package Test::Two; sub hello{ my $var = shift; print "Hello: $var\n"; } 1;

Comment on Dynamic Package Name & Subroutine Call
Download Code
Re: Dynamic Package Name & Subroutine Call
by awohld (Hermit) on Dec 14, 2012 at 22:32 UTC
    By George, I think I just figured it out:

    CHANGE:
    Test::$pkg::hello($pkg);
    TO:
    { no strict 'refs'; &{"Test::" . $pkg. "::hello"}($pkg); }
      The following works with strict on:
      (\&{"Test::${pkg}::hello"})->($pkg);
      The same, but more readable:
      my $sub = \&{"Test::${pkg}::hello"}; $sub->($pkg);

      Then again, explicitly using no strict 'refs'; might be better a good thing.

      That said, it looks like you have a method call (to which you're passing the wrong package name). If so, you should be using

      ("Test::".$pkg)->hello(...);
Re: Dynamic Package Name & Subroutine Call
by davido (Archbishop) on Dec 14, 2012 at 22:37 UTC

    A package is just a namespace identified by a string.

    package Test::One; sub hello{ my $var = shift; print "Hello: $var\n"; } 1; package Test::Two; sub hello{ my $var = shift; print "Hello: $var\n"; } 1; package main; use strict; use warnings; use Data::Dumper; my @pkgs = qw( One Two ); foreach my $pkg ( @pkgs ) { "Test::$pkg"->hello(); }

    This is one step toward full-fledged classes and objects, which may be a better solution in the longrun: perlobj.

    If you can't plan on passing the package name as the first parameter (which is what the Class->method() notation does), then you have to construct the fully qualified sub name, which means symbolic references and some ugly syntax:

    foreach my $pkg ( @pkgs ) { no strict 'refs'; &{'Test::' . $pkg . '::hello'}($pkg); }

    Update: Good job on figuring out the symbolic ref syntax on your own. Looks like we both came up with the same.


    Dave

      An alternative to no strict 'refs' would be:

      foreach my $pkg ( @pkgs ) { my $hello = "Test::$pkg"->can('hello'); $hello->() if $hello; }

      ... because can returns a coderef. In the case of packages that have inheritance (@ISA) this will act slightly differently to &{'Test::' . $pkg . '::hello'}().

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        can should be used for methods and only for methods, so that should be

        my $full_pkg = "Test::".$pkg; my $hello = $full_pkg->can('hello'); $full_pkg->$hello(...); # Or: $hello->($full_pkg, ...);

        which simplifies to:

        my $full_pkg = "Test::".$pkg; $full_pkg->hello(...);

        You don't even need can if the method name is variable.

        $full_pkg->$method_name(...);

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1008906]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (15)
As of 2015-07-02 09:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (33 votes), past polls