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 chilling in the Monastery: (6)
As of 2014-10-01 09:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (392 votes), past polls