Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Export again

by Cagao (Monk)
on Feb 21, 2011 at 17:09 UTC ( [id://889426]=perlquestion: print w/replies, xml ) Need Help??

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

I want to have a standard module which simply "uses" a load of other modules which all my classes/scripts use.

These are things like Data::Dumper and Time::HiRes

Time::HiRes is causing me a major headache, and I'm more interested in how to deal with this issue...

In my standard module I have Time::HiRes qw(gettimeofday);, which imports the gettimeofday() method to that namespace.

I then use my standard module and try to export gettimeofday() again, but it ain't working.

Undefined subroutine &MyStandardModules::gettimeofday

is as close as I can get

I'm trying crazy things like *gettimeofday = \$Time::HiRes::gettimeofday; but just confusing myself even more since I ain't got a clue what that really means :)

Replies are listed 'Best First'.
Re: Export again
by Eliya (Vicar) on Feb 21, 2011 at 17:40 UTC

    So you want MyStandardModules to use other modules and export routines from those modules into the package you use it from?

    If so, you could try something like this:

    package MyStandardModules; use Time::HiRes (); sub import { my $dest_pkg = caller(); eval "package $dest_pkg; Time::HiRes->import('gettimeofday');"; } 1;
    #!/usr/bin/perl -wl use strict; use MyStandardModules; print scalar gettimeofday();

    Exporter uses caller to determine where to export to, so you could use caller() yourself, and fake the respective package that import() is being called from (as done in the eval above).

    Update: a similar technique can also be used for lexical pragmas, like use strict (which don't really export anything):

    package MyStandardModules; use strict; sub import { strict->import(); } 1;
    #!/usr/bin/perl { use MyStandardModules; print $foo; # error } print $bar; # "OK", as outside of strict's scope __END__ $ ./ Global symbol "$foo" requires explicit package name at ./ lin +e 5. Execution of ./ aborted due to compilation errors.

      This way appeared the simplest, and works, tho I'm not 100% sure on what...

      eval "package $dest_pkg; Time::HiRes->import('gettimeofday');";

      Is actually doing? I've not seen an eval block being a simple string before?

        eval has two forms, eval EXPR (aka "string eval") and eval BLOCK.

        In this case, a string eval is needed because $dest_pkg isn't known before runtime of the import function.  And this is also the reason the eval is required at all.  In other words, the package statement is a compile-time thing, i.e. you can't say

        package $dest_pkg;

        So what the eval does is shift the compile-time of that particular code fragment to runtime.  This means that when you say use MyStandardModules; from within a package "Foo", $dest_pkg will be "Foo", and the following snippet will be compiled (and executed):

        package Foo; Time::HiRes->import('gettimeofday');

        which has the effect that when Exporter then determines the calling package in its import method (via caller), it will see package "Foo", which is what it then exports the requested routines or variables to.

Re: Export again
by trwww (Priest) on Feb 21, 2011 at 19:48 UTC

    You have to ->import the symbols in to your library:

    use warnings; use strict; package MyStandardModules; use Time::HiRes (); package main; Time::HiRes->import('gettimeofday'); print gettimeofday();

    I suggest either calling the function/method qualified with the namespace (ala my $time = Time::HiRes::gettimeofday()) or use()ing the module in the place you need the symbol imported.

    Could you explain your adversion to use()ing the module in the package where the function is needed?

      Thanks for all the help so far guys, it's all making sense.

      I'd like to move the "use" statements to one standard location instead of having to "use" several modules in all of my code, plus I can always then be certain that certain functions are always going to be available.

Re: Export again
by apomatix (Novice) on Feb 22, 2011 at 00:32 UTC

    All the solutions proposed are excellent. The symbol table manipulation you proposed failed because you assigned the scalar $gettimeofday from Time::HiRes (which probably is not defined anyway). Instead of

    *gettimeofday = \$Time::HiRes::gettimeofday;

    you have to use "&" to get the subroutine reference:

    *gettimeofday = \&Time::HiRes::gettimeofday;

    Alternatively, you could assign the entire symbol table entry using "*":

    *gettimeofday = \*Time::HiRes::gettimeofday;

    Then not only would your module get Time::HiRes's "gettimeofday" subroutine, but also any other Perl things (array, hash, etc) with the name "gettimeofday".

Re: Export again
by ciderpunx (Vicar) on Feb 21, 2011 at 17:50 UTC
    package MyStdMod; use Time::HiRes qw|gettimeofday|; use base 'Exporter'; our @EXPORTS = qw|gettimeofday|; 1;
    And then
    #!/usr/bin/perl use strict; use warnings; use 5.10.0; use MyStdMod; say MyStdMod::gettimeofday();
    I'm not sure if that is a good way to proceed.

Log In?

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-07-21 10:21 GMT
Find Nodes?
    Voting Booth?

    No recent polls found

    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.