Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

reaching into a perl script from a package

by Brad.Walker (Sexton)
on Oct 02, 2006 at 17:51 UTC ( #575915=perlquestion: print w/ replies, xml ) Need Help??
Brad.Walker has asked for the wisdom of the Perl Monks concerning the following question:

I have a package and an external Perl script. They are both mutually exclusive. But, I would like to modify my package and have it reach into the script to see if a function exists.

For example, ------ #! /usr/bin/perl sub func1() { } sub func2() { } 1;

In my package, I would like to do something like

my $ref_to_sub = \&func1;

Is this possible.


Comment on reaching into a perl script from a package
Select or Download Code
Re: reaching into a perl script from a package
by Fletch (Chancellor) on Oct 02, 2006 at 17:56 UTC

    Code in the outer main program is in the package main (by default, presuming no other package Somethingelse declarations of course); just use something along the lines of my $main_func1 = \&main::func1;.

    Update: Seconded that something like jimt's method below where the calling code specifies what the callback routine should be is a better way to do this.

Re: reaching into a perl script from a package
by kwaping (Priest) on Oct 02, 2006 at 18:17 UTC
    Why do you want to do this? I ask because there might be a better way to achieve the results you seek.

    It's all fine and dandy until someone has to look at the code.
Re: reaching into a perl script from a package
by davido (Archbishop) on Oct 02, 2006 at 18:22 UTC

    You're close. You just need to use the fully qualified name of the sub you're trying to find. And it wouldn't hurt to build in some error checking to alert you if the sub you're looking for doesn't exist. Here's an example:

    package MyTest; use strict; use warnings; sub findsub { my $subref; if( defined &main::testsub ) { $subref = \&main::testsub; } else { die "main::testsub doesn't exist.\n"; } $subref->( "Hello world!\n" ); } 1; package main; MyTest::findsub(); sub testsub { print shift; }


      I probably wasn't too clear. The function that I'm trying to test for resides in a Perl script that begins with:
      #! /usr/bin/perl.
      So I would assume that I can't do a "require" or "use" on it and then test for the function name using $package::func.

      The reason I need to do this is because I have a lot of Perl scripts written/maintained by someone else. I would like to pull them unmodified into my test harness and execute functions inside them without having to modify the code.

      Hope this clears it up and thanks for all the help. -brad w.

        Ok, so if I understand, you've got a script running, and within one of its used modules you wish to probe a completely different script to see if a particular function exists. Is that right?

        Maybe you should search for that sub's name in the output from B::Xref.


        Actually, you can require them. However, if there is any code inside that isn't wrapped in a sub, it will execute when the file is required. Example:
        #!/usr/bin/perl ### the file doing the requiring use strict; use warnings; use lib '/path/to/lib'; require(''); asdf();
        #!/usr/bin/perl ### the file being required use strict; use warnings; print "hi there\n"; sub asdf { print "well howdy"; } 1;
        ### the output hi there well howdy

        It's all fine and dandy until someone has to look at the code.
        Congratulations, you are re-inventing the Perl4 idiom for including subroutine libraries! From perlfunc

        do EXPR

        Uses the value of EXPR as a filename and executes the contents of the file as a Perl script.

        do '';

        is just like

        eval `cat`;

        except that it's more efficient and concise, keeps track of the current filename for error messages, searches the @INC directories, and updates %INC if the file is found. See Predefined Names in the perlvar manpage for these variables. It also differs in that code evaluated with do FILENAME cannot see lexicals in the enclosing scope; eval STRING does. It's the same, however, in that it does reparse the file every time you call it, so you probably don't want to do this inside a loop.

        If do cannot read the file, it returns undef and sets $! to the error. If do can read the file but cannot compile it, it returns undef and sets an error message in $@. If the file is successfully compiled, do returns the value of the last expression evaluated.

        Note that inclusion of library modules is better done with the use and require operators, which also do automatic error checking and raise an exception if there's a problem.

        You might like to use do to read in a program configuration file. Manual error checking can be done this way:

        # read in config files: system first, then user for $file ("/share/prog/defaults.rc", "$ENV{HOME}/.someprogrc") { unless ($return = do $file) { warn "couldn't parse $file: $@" if $@; warn "couldn't do $file: $!" unless defined $return +; warn "couldn't run $file" unless $return; } }


        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: reaching into a perl script from a package
by jimt (Chaplain) on Oct 02, 2006 at 19:18 UTC

    But, I would like to modify my package and have it reach into the script to see if a function exists.

    If it's possible, I'd recommend going the other way. Have the executing script tell your package that the function exists, instead of having the package try to probe it.

    With the suggested approaches here, you're hardwiring some function in your script into your package. What if the function moves? What if the function gets renamed? What if it gets deleted?

    This is clearly a side effect. Somebody goes into the script and modifies the function, they then need to go into the separate package and modify the link to the function. Nothing makes it explicitly clear that anything else should care, its not like you're talking about modifying a library function it's clear that other calls may be affected.

    So I think it'd be better to have the script tell the package instead. I'm thinking of something along these lines:

    package FooBar; sub set_function_ref { my $function = shift; #do someting interesting with it. } in sub interesting_fuction { # interesting things... } FooBar::set_function_ref(\&interesting_function);

    And you're decoupled. Your package can now safely work anywhere else, and not depend upon a particular function existing in a particular package. Anything that wants to use FooBar just calls set_function_ref with the value it wants it to operate on.

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2014-07-12 03:14 GMT
Find Nodes?
    Voting Booth?

    When choosing user names for websites, I prefer to use:

    Results (238 votes), past polls