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

Simple Module Tutorial

by tachyon (Chancellor)
on Aug 06, 2001 at 01:30 UTC ( #102347=perltutorial: print w/ replies, xml ) Need Help??

So you find the Perl docs on modules a bit confusing? OK here is the world's simplest Perl module domonstrating all the salient features of Exporter and a script that uses this module. We also give a short rundown on @INC and finish with a note on using warnings and modules. Here is the module code.

MyModule.pm

package MyModule; use strict; use Exporter; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(func1 func2); %EXPORT_TAGS = ( DEFAULT => [qw(&func1)], Both => [qw(&func1 &func2)]); sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } 1;

First we get a namespace by declaring a package name. This helps ensure our module's functions and variables remain separate from any script that uses it.

Use strict is a very good idea for modules to restrict the use of global variables. See use strict warnings and diagnostics or die for more details.

We need to use the Exporter module to export our functions from the MyModule:: namespace into the main:: namespace to make them available to scripts that 'use' MyModule.

We pacify strict with the use vars declaration of some variables. We can use an 'our' declaration in 5.6+

We now set a $VERSION number and make Exporter part of MyModule using the @ISA. See perlboot for all the gory details on what @ISA is or just use it as shown.

@EXPORT contains a list of functions that we export by default, in this case nothing. Generally the less you export by default using @EXPORT the better. This avoids accidentally clashing with functions defined in the script using the module. If a script wants a function let it ask.

@EXPORT_OK contains a list of functions that we export on demand so we export &func1 &func2 only if specifically requested to. Use this in preference to just blindly exporting functions via @EXPORT. You can also export variables like $CONFIG provided they are globals not lexicals scoped with my (read declare them with our or use vars).

%EXPORT_TAGS. For convenience we define two sets of export tags. The ':DEFAULT' tag exports only &func1; the ':Both' tag exports both &func1 &func2. This hash stores labels pointing to array references. In this case the arrays are anonymous.

We need the 1; at the end because when a module loads Perl checks to see that the module returns a true value to ensure it loaded OK. You could put any true value at the end (see Code::Police) but 1 is the convention.

MyScript.pl (A simple script to use MyModule)

#!/usr/bin/perl -w use strict; # you may need to set @INC here (see below) my @list = qw (J u s t ~ A n o t h e r ~ P e r l ~ H a c k e r !); # case 1 # use MyModule; # print func1(@list),"\n"; # print func2(@list),"\n"; # case 2 # use MyModule qw(&func1); # print func1(@list),"\n"; # print MyModule::func2(@list),"\n"; # case 3 # use MyModule qw(:DEFAULT); # print func1(@list),"\n"; # print func2(@list),"\n"; # case 4 # use MyModule qw(:Both); # print func1(@list),"\n"; # print func2(@list),"\n";

We use MyModule in MyScript.pl as shown. Uncomment the examples to see what happens. Just uncomment one at a time.

Case 1: Because our module exports nothing by default we get errors as &funct1 and &funct2 have not been exported thus do not exist in the main:: namespace of the script.

Case 2: This works OK. We ask our module to export the &func1 so we can use it. Although &func2 was not exported we reference it with its full package name so this works OK.

Case 3: The ':DEFAULT' tag *should* export &func1 so you might expect the error here to concern a missing &func2. In fact Perl complains about &func1. Hmm, what is going on here. The DEFAULT tag name is special and is automatically set in our modules %EXPORT_TAGS hash like this DEFAULT => \@EXPORT.

Case 4: We specified the export of both our functions with the ':Both' thus this works.

A note on @INC

When you issue a use MyModule; directive perl searchs the @INC array for a module with the correct name. @INC usually contains:

/perl/lib 
/perl/site/lib
.

The . directory (dot dir) is the current working directory. CORE modules are installed under perl/lib whereas non-CORE modules install under perl/site/lib. You can add directories to the module search path in @INC like this:

BEGIN { push @INC, '/my/dir' } # or BEGIN { unshift @INC, '/my/dir' } # or use lib '/my/dir';

We need to use a BEGIN block to shift values into @INC at compile time as this is when perl checks for modules. If you wait until the script is comiled it is too late and perl will throw an exception saying it can't find MyModule in @INC... The difference between pushing a value and unshifting a value into @INC is that perl searches the @INC array for the module starting with the first dir in that array. Thus is you have a MyModule in /perl/lib/ and another in /perl/site/lib/ and another in ./ the one in /perl/lib will be found first and thus the one used. The use lib pragma effectively does the same as the BEGIN { unshift @INC, $dir } block - see perlman:lib:lib for full specifics.

What use Foo::Bar means

use Foo::Bar does not mean look for a module called "Foo::Bar.pm" in the @INC directories. It means search @INC for a *subdir* called "Foo" and a *module* called "Bar.pm".

Now once we have "use'd" a module its functions are available via the fully specified &PACKAGE::FUNCTION syntax. When we say &Foo::Bar::some_func we are refering to the *package name* not the (dir::)file name that we used in the use. This allows you to have many package names in one use'd file. In practice the names are usually the same.

use Warnings;

You should test your module with warnings enabled as this will pick up many subtle (and not so subtle :-) errors. You can activate warnings using the -w flag in the script you use to test the module. If you add use warnings to the module then your module will require Perl 5.6+ as this was not available before then. If you put $^W++ at the top of the module then you will globally enable warnings - this may break *other modules* a script may be using in addition to your module so is rather antisocial. An expert coder here called tye tests with warnings but does not include them directly in his/her modules.

Hope this explains how it works.

cheers

tachyon

Update

Fixed a typo and added a few comments. Thanks to John M. Dlugosz. Rewrote and restyled tute for compatibility with versions of Perl < 5.6 thanks to crazyinsomniac. Also thanks to tye for reminding me that $^W++ is globally scoped and a bit antisocial for a module.

s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Comment on Simple Module Tutorial
Select or Download Code
Re: Simple Module Tutorial
by John M. Dlugosz (Monsignor) on Aug 06, 2001 at 04:30 UTC
    Very nice, getting everything into a short page like that. But, I have a few comments:

    Are you sure you want to make $VERSION a float, rather than a v-string? And if so, illustrate the three-digit convention (e.g. 5.005_001 for version 5.5.1).

    I'm also shocked that your pm file doesn't use strict!

    I would also suggest adding a comment to the 1; line, saying that this means "loaded OK".

    —John

      Thanks John I've updated the text a bit in line with your suggestions. Forgot the strict in the module! Oops it is back in its rightful place right at the top. I just used the simple $VERSION numbering because this is a simple tute :-) Here is an excerpt from the Exporter manpage for those interested.

      Module Version Checking The Exporter module will convert an attempt to import a number from a module into a call to $module_name->require_version($value). This can be used to validate that the version of the module being used is greater than or equal to the required version. The Exporter module supplies a default require_version method which checks the value of $VERSION in the exporting module. Since the default require_version method treats the $VERSION number as a simple numeric value it will regard version 1.10 as lower than 1.9. For this reason it is strongly recommended that you use numbers with at least two decimal places, e.g., 1.09.

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

        Yea, I just posted a tutorial on VERSION.

        For compatibility with mixing decimals and v-strings, the built-in UNIVERSAL::require_version uses three decimal digits per part.

        If you have $MyModule::VERSION= 1.12; (a decimal number) and do a use MyModule 1.20.1 qw/bar/, it will tell you that the module 1.120 and you asked for 1.020, so that's OK. You expected 1.20 to be greater than 1.12, not-OK.

        —John

(tye)Re: Simple Module Tutorial
by tye (Cardinal) on Aug 06, 2001 at 22:09 UTC

    $W++ will only give you run-time warnings and will affect other packages. Personally, I don't turn on warnings in modules that I write but I do make a point of testing them with warnings turned on (by putting "#!/usr/bin/perl -w" at the top of my test scripts).

            - tye (but my friends call me "Tye")

      Thanks I changed it from the lexically scoped 'use warnings;' so that this is applicable to versions < 5.6. but as it adds little value to the tutorial and has the unwanted side effects you point out I have just deleted it - saves a few lines of dubious value. I'll add a note on testing with warnings when I have a moment.

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Simple Module Tutorial
by beretboy (Chaplain) on Aug 18, 2001 at 15:07 UTC
    Exellent tutorial ++! I have never understood the writing of modules till now

    "Sanity is the playground of the unimaginative" -Unknown
      Fantastic stuff - I just converted a full script into a module (and added some bits) and it worked 1st time - WITH NO DEBUGGING REQUIRED (and yes - I am using strict)!!! I was very scared of modules before but now feel like I could write a hundred. Thanks very much for this - invaluable tutorial for a newbie like me :))))))
Re: Simple Module Tutorial
by Jaap (Curate) on Jul 22, 2002 at 09:35 UTC
    This is a nice tutorial tachyon. Are you considering writing a more advanced tutorial on modules (combined with OO)?

    Especially, what a GOOD module looks like. Should we use carp, dynaloader and what not?
Re: Simple Module Tutorial
by gawatkins (Monsignor) on Apr 10, 2003 at 11:44 UTC

    Great Tutorial, It helped to clear up the muddy water created by my Perl Black Book.

    Thanks again,

    Greg W.

Re: Simple Module Tutorial
by johnnywang (Priest) on Aug 09, 2004 at 22:58 UTC
    Quite some years have gone by since the inital post, just want to point out that "use vars" is now considered deprecated, instead, "our" is prefered. Another already mentioned point is not to use @EXPORT too much. So my basic module is like the following (I have a emacs function to output this):
    package MyModule; use strict; use Exporter qw(import); our $VERSION = 1.00; our @ISA = qw(Exporter); our @EXPORT_OK = qw(func1 func2); our %EXPORT_TAGS = ( DEFAULT => [qw(func1)], Both => [qw(func1 func2)]); sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } 1;
    For those emacs users, here's the simple script to generate the skeleton:
    (defun perl-new-module () "Generate a skeleton source for a traditional perl module." (interactive) (setq var (split-string (read-from-minibuffer "Enter module name (eg. Web::Test): "nil nil nil nil nil nil) " ")) (setq name (car var)) (insert (format "package %s;\n\n" name)) (insert "use strict;\n\n") (insert "use Exporter qw(import);\n") (insert "our @ISA = qw(Exporter);\n") (insert "our @EXPORT_OK = qw();\n") (insert "our %EXPORT_TAGS = ();\n") (insert "our $VERSION = 1.00; \n\n") (insert "\n\n\n\n\n\n") (insert "1;") (insert "\n") (previous-line 6) (end-of-line) )
      Quite some years have gone by since the inital post, just want to point out that "use vars" is now considered deprecated, instead, "our" is prefered.

      Some people prefer to use our rather than use vars (I'm one of them) - but the latter is not deprecated. Both do slightly different things and many people still prefer to use vars.

Re: Simple Module Tutorial
by twotone (Beadle) on Oct 14, 2007 at 05:06 UTC

    Great summary of module basics!

    Here's a little code I came up with to add my module location to @INC (in a cgi environment) by dynamically determining the document root for the script. It works on the remote apache server and when testing locally in windows. It might be of some interest:

    BEGIN { # get doc root from %ENV # implicitly declare file root path if %ENV not fount my $doc_root = $ENV{DOCUMENT_ROOT} || 'C:/Users/User/Documents/website/sites/mysite'; # change \ to / $doc_root =~ s/\\/\//g; # add module folder location $doc_root .= "/cgi-bin/cms/"; # add module location to @INC push(@INC,$doc_root); }
      This tutorial is great. The only problem is, that I get the following result, if I comment out all the cases:

      !rekcaH~lreP~rehtonA~tsuJ
      JUST~ANOTHER~PERL~HACKER!
      !rekcaH~lreP~rehtonA~tsuJ
      JUST~ANOTHER~PERL~HACKER!
      !rekcaH~lreP~rehtonA~tsuJ
      JUST~ANOTHER~PERL~HACKER!
      !rekcaH~lreP~rehtonA~tsuJ
      JUST~ANOTHER~PERL~HACKER!

      Shouldn't there be some error messages or warnings?
Re: Simple Module Tutorial
by chexmix (Hermit) on Aug 12, 2008 at 13:24 UTC
    I like this post very much, but the following is opaque to me for some reason:

    "Case 3: The ':DEFAULT' tag *should* export &func1 so you might expect the error here to concern a missing &func2. In fact Perl complains about &func1. Hmm, what is going on here. The DEFAULT tag name is special and is automatically set in our modules %EXPORT_TAGS hash like this DEFAULT => \@EXPORT."

    I confess I still don't know what is going on here, and am wondering if someone can help me out.

    The words "is automatically set in our modules %EXPORT_TAGS hash like this DEFAULT => \@EXPORT" seem inaccurate to me, since when I look up at the code for MyModule.pm, I see the line

    %EXPORT_TAGS = ( DEFAULT => qw(&func1),

    and not the line

    %EXPORT_TAGS = ( DEFAULT => \@EXPORT,

    Is the OP saying that the line as is in the MyModule.pm code is incorrect, because the "special" nature of DEFAULT overrides it with something else?

    Thanks. I feel I am blanking on something obvious here, but just can't see it this rainy morning.

      Is the OP saying that the line as is in the MyModule.pm code is incorrect, because the "special" nature of DEFAULT overrides it with something else?

      Yes. Exporter.pm wants :DEFAULT to match @EXPORT so the module is incorrect in trying to define its own meaning for :DEFAULT. Based on what you've quoted, it appears that Exporter.pm forces this issue, but the more important point is that you shouldn't set $EXPORT_TAGS{DEFAULT} yourself.

      - tye        

Re: Simple Module Tutorial
by Anonymous Monk on Mar 09, 2010 at 12:21 UTC
    Excellent representation of what seemed a tough nut to swallow. Thank you very much. Tanuj Bhargava
Re: Simple Module Tutorial
by sg (Pilgrim) on Feb 05, 2011 at 23:13 UTC

    Thanks for the exposition; my inclination regarding a simple module is as follows:

    MyModule.pm
    package MyModule; use strict; use warnings; use diagnostics; use Carp; our $VERSION = 1.08; sub see_me { my $foo = shift; print "\t\tDo you see this: $foo?\n"; } 1; __END__ last line of the module needs to be true; last line of the _file_ need not be true: 0;

    The above module is exercised by the following script:

    exercise_my_module.pl

    #!/c/opt/perl/bin/perl use strict; use warnings; use diagnostics; use Carp; use MyModule 1.05; #use MyModule 1.10; # will fail MyModule::see_me( 8 ); __END__
Re: Simple Module Tutorial
by Anonymous Monk on Mar 07, 2011 at 15:12 UTC

    Thanks to the writer for your trouble. But everyone seems to get it except me. I have tried to duplicate your results.

    I have:

    - MyScript.pl under /storage/username/PERL_SCRIPTS/dev

    - Test.pm under /storage/username/local/perl/site/lib/Test/Test.pm (I just replaced MyModule.pm with Test.pm).

    The module code is exactly the same. In MyScript.pl I have added

    use lib '/storage/username/local/perl/site/lib'; <p>and typed in the first two cases.</p> <code>perl MyScript.pl
    gives: Undefined subroutine &main::func1 called at MyScript.pl line 10

    Line 10 is:

    print func1(@list),"\n";

    after typing "use Test;"

    What am I missing here? Also, is the BEGIN command supposed to be used in the Perl script? It gives syntax errors when I try to use it.

    Thanks in advance,

    Gideon

      "Test" is a poor choice of a module name because there is a Core module of the same name (Test) which is part of the standard Perl distribution. Furthermore, since you placed your .pm file under a directory named "Test", you would need to type use Test::Test;. I strongly recommend you change the name of your module to something more unique in order to avoid this naming collision.

        Dear toolic,

        Thank you for your reply. I now have changed all instances of "Test" with "MyModule" and also changed the name of the module. MyModule.pm is now situated on

        /storage/username/local/perl/site/lib

        and I use

        use lib '/storage/username/local/perl/site/lib'; with the second case (as per the example):
        # case 2 use MyModule; print func1(@list),"\n"; print MyModule::func2(@list),"\n";

        but I still get the same error: Undefined subroutine &main::func1 called at MyScript line 15.

        Just to make sure I copied the module exactly from the example but to no avail. Interestingly, when I comment out the print func1 part, the line after that produces correct output. I hope that someone could point out to me where I am at fault.

        Best regards,

        Gideon

        Hi toolic

        For some reason I can't reply to your latest post but thanks a mil! I did copy the module exactly but not the script. Somehow I mixed up case 1 and case 2. I expected case 1 not to work but case 2 but instead of coding

        use MyModule qw(&func1);

        I simply used

        use MyModule;

        Thanks a lot for pointing it out, it seems to work now. I have learned quite a bit.

        Best regards,

        Gideon

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perltutorial [id://102347]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (7)
As of 2014-04-23 21:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (555 votes), past polls