Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Let a module call a sub of the caller

by voj (Acolyte)
on Sep 06, 2012 at 18:57 UTC ( #992164=perlquestion: print w/ replies, xml ) Need Help??
voj has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to create a Module that calls a sub defined by the caller. For instance:

use My::Module call => 'foo'; sub foo { ... };

Should call "foo" after compilation (not during BEGIN). Could the module somehow define an INIT block that calls the sub?

Comment on Let a module call a sub of the caller
Download Code
Re: Let a module call a sub of the caller
by SuicideJunkie (Priest) on Sep 06, 2012 at 19:11 UTC

    You can pass a reference to a sub, and let other code call that whenever you like...

    use strict; use warnings; { my $subref = sub { print "Hey, Hey!\n"; }; Foo($subref); } exit 0; sub Foo { my $callback = shift; print "Foo started\n"; $callback->(); print "Foo is done\n"; }
Re: Let a module call a sub of the caller
by moritz (Cardinal) on Sep 06, 2012 at 19:24 UTC
    Should call "foo" after compilation (not during BEGIN). Could the module somehow define an INIT block that calls the sub?

    The problem with that is that modules INIT and runtime are still compile time from the perspective of the calling script.

    You could run it in an END block, which is also after compilation, but I could imagine that that's too late for your purpose. So I don't know any solution, except via source filters (or maybe evil hijacking of DESTROY subs, depending on when exactly the routine should run).

    Speaking of which, what is your purpose? Maybe there's a better solution to it if we know the bigger picture.

      I just wanted to facilitate the use of a Module and avoid exorting into the caller's namespace. In particular, the Module does not just call the method but does some processing to pass it the right parameters. The same could be done with an export:

      use My::Module qw(call); call(\&foo); sub foo { ... };

      I am not that familiar with the processing phases BEGIN,INIT,END, that's why I asked. Is there a way to call the method at the END of execution of the caller?:

      use My::Module call => 'foo'; sub foo { ... }; # foo is called at the end
        I am not that familiar with the processing phases BEGIN,INIT,END, that's why I asked. Is there a way to call the method at the END of execution of the caller?

        END time is the same for all, so yes, that works:

        # file CallMe.pm package CallMe; use 5.010; use strict; use warnings; my @to_call; sub import { my ($self, @routines) = @_; my $call_package = (caller(1))[0]; push @to_call, $call_package. "::$_" for @routines; } END { no strict 'refs'; $_->() for @to_call; } 1;

        And then in your script:

        use 5.010; use lib '.'; use CallMe 'foo'; sub foo { say 42 } say 'in mainline';

        prints

        in mainline 42
Re: Let a module call a sub of the caller
by sundialsvc4 (Monsignor) on Sep 06, 2012 at 22:44 UTC

    This is an excellent application for what is known in computer-science circles as a closure.   Which Perl supports very well.

    You can, within a subroutine, define a variable to be a “code reference,” that is to say, to a particular sub that you define on-the-spot and which can refer to local variables or anything else that is “visible” at the particular place where you define that sub.  

    Your caller should simply define one of those closures, and pass it in as a parameter to the routine, who simply calls it.   The closure will execute in the context of the code that created it ... that is to say, “your caller.”

    “It’s slick to the point of being positively elegant,” and it works.   (May I kindly refer you to a plethora of existing docs here and elsewhere on the Internet for the gory procedural details.)

Re: Let a module call a sub of the caller
by ikegami (Pope) on Sep 06, 2012 at 23:57 UTC

    The same mechanisms pragmas use to clean themselves up can be used here. Here's an example:

    call_when_scope_is_compiled.pm:

    package call_when_scope_is_compiled; use Sub::ScopeFinalizer qw( scope_finalizer ); sub import { my ($class, $sub) = @_; $^H{__PACKAGE__ . '::'} = scope_finalizer { $sub->() }; } 1;
    $ perl -E' say "post"; use call_when_scope_is_compiled \&foo; sub foo { say "foo!" } BEGIN { say "pre"; } ' pre foo! post

    It also works for narrower scopes.

    $ perl -E' { use call_when_scope_is_compiled \&foo; sub foo { say "foo!" } BEGIN { say "pre"; } } BEGIN { say "post"; } ' pre foo! post
Re: Let a module call a sub of the caller
by clueless newbie (Friar) on Sep 07, 2012 at 12:00 UTC

    Does this do what you want?

    #!/usr/bin/perl use strict; use warnings; use v5.10; sub YadaYada { say "YadaYada"; }; use Xyzzy (\&YadaYada); say "Executing ".__PACKAGE__; INIT { say __PACKAGE__."::INIT"; }; END { say __PACKAGE__."::END"; };
    package Xyzzy; use Data::Dumper; use strict; use warnings; use v5.10; my $external; sub import { shift; $external=$_[0]; }; say "Executing ".__PACKAGE__; INIT { say __PACKAGE__."::INIT"; $external->(); }; END { say __PACKAGE__."::END"; }; 1;

    yields

    Executing Xyzzy Xyzzy::INIT YadaYada main::INIT Executing main main::END Xyzzy::END
Re: Let a module call a sub of the caller
by tobyink (Abbot) on Sep 07, 2012 at 12:38 UTC

    B::Hooks::EndOfScope or perhaps Hook::AfterRuntime (or even a combination of the two) ought to do the trick.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Let a module call a sub of the caller
by Jenda (Abbot) on Sep 07, 2012 at 13:20 UTC
    use My::Module call => sub { ... };

    The catch is that if the anonymous subroutine you pass to the module gets called directly from within the import() subroutine, you may not call subroutines defined under the use statement. So you may have to move the use statement a little lower in the code. It doesn't have to be right on top!

    Jenda
    Enoch was right!
    Enjoy the last years of Rome.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://992164]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2014-07-24 05:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (158 votes), past polls