Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

How to pass an argument to a Module?

by mascip (Pilgrim)
on Sep 09, 2012 at 12:28 UTC ( #992581=perlquestion: print w/replies, xml ) Need Help??
mascip has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to pass an argument to a module. Something which would look like this :

use Test::More tests => 5;
How can i do this for my own modules ?

~ ~ ~
Here is the context (that you shouldn't need, to answer my question) :
I have written a naive test module for operators overloading, and in each function i need to specify who is the class overloading the operator. I would like to specify it only once, when i load the My::Test::Operation module :

My::Test::Operation class => 'My::Percentage';

PS : i searched in Test::More and Test::Builder for an answer, but the code was too convoluted for me to find how it's done in these modules.

Replies are listed 'Best First'.
Re: How to pass an argument to a Module?
by Corion (Pope) on Sep 09, 2012 at 12:44 UTC

    See use (or perlmod). Both describe what use actually is.

    In short, if you implement a subroutine import in your module, it will get called at use time.

      I still didn't manage to do it with Perl6::Export::Attrs (i'll try more - help appreciated - details at the end of this message).
      But finally i managed to override the import() methods appropriately for the cases when Export is used. Simply overriding import() didn't work, as i lost the benefit of Export. I had to use the export_to_level() method (defined by Export) in the overriden import().
      Here is the simple sample code (all files start with use strict and warnings).

      package Mod2; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(subr); # Exported by default sub import { print "import() was called with arguments : @_\n"; my $my_arg = pop @_; # i have to pop(), # because export_to_level() doesn't want to see $my_arg print "my arg: $my_arg\n"; Mod2->export_to_level(1, @_); } sub subr { return "subr() was called\n"; } 1;
      And the script to run it :
      use Mod2 'argument'; print subr();
      Which displays :
      import() was called with arguments : Mod2 argument my arg: argument subr() was called
      It works !

      Now with Perl6::Export::Attrs, i tried this (with the same script, using Mod3 instead of Mod2; i also tried to not put any argument after use Mod3;) :

      package Mod3; use Perl6::Export::Attrs; sub subr :Export(:DEFAULT) { return "subr() was called\n"; } IMPORT{ print "inside the IMPORT block\n"; } 1;
      and obtained this output:
      inside the IMPORT block Can't call method "IMPORT" without a package or object reference at Mo line 11. Compilation failed in require at line 5. BEGIN failed--compilation aborted at line 5.
      Does anyone know how to use this IMPORT block properly?

        Does anyone know how to use this IMPORT block properly?

        Presumably the author. Seeing how the module never tests this IMPORT block business (Perl6-Export-Attrs-0.0.3/t/00.load.t), I would complain to the author.

        You can probably get away with writing  sub IMPORT {} , cause that works for BEGIN/END/... also

        $ perl -MO=Deparse,-p -e " IMPORT { warn(666); } " do { warn(666) }->IMPORT; -e syntax OK $ perl -MO=Deparse,-p -e " sub IMPORT { warn(666); } " sub IMPORT { warn(666); } -e syntax OK

      Thank you.
      I understand that i have to override import(). But as i use Perl6::Export::Attrs, i'm reading in the doc that i have to use an IMPORT block instead. I'm going to try this.

      Another idea for "cheating" : having a CLASS() method which would contain my parameter, and which i would override by monkeypatching.
      Not very clean though, i'll try the IMPORT thing.

Re: How to pass an argument to a Module?
by BillKSmith (Priest) on Sep 09, 2012 at 15:47 UTC

    I would prefer to write an ordinary subroutine to initialize the global variables at run-time. (Same general idea as the OO "new")


      Something like this?

      use Mod; Mod->initialize('argument');
      I'm going to try.

        If you module is a class, you have written a call to a class method. (That is even better than what I had in mind.) If not, the initialize function would have to be written, passed, and called the same way as every other function in the module.

Re: How to pass an argument to a Module?
by bulk88 (Priest) on Sep 10, 2012 at 02:21 UTC
    Rather than use use/import settings, which are global to the process (last package to "use" the module in question wins the config war), create a root constructor class, all future/heavy objects are created from the per package method of the root constructor object. Each package can have its own constructor object with per caller package "global" settings.