Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

No include

Some simple languages, like PHP, offer an include() to include a file literally. Perl does not. Then how can you still load code from other files?

There are many ways to do this in Perl, but there is no easy way to get close to what most people expect of an include(). People who want to include files usually come from simpler languages, or have no programming experience at all. The hardest thing they will have to learn is that you should not want to include a file.

That may sound harsh, but it's a Perl reality. In Perl, we don't include or link libraries and code reuse isn't usually done by copying and pasting. Instead, Perl programmers use modules. The keywords use and require are meant for use with modules. Only in the simplest of situations you can get away with abusing require as if it were some kind of include(), but it's easy to get bitten by how it works: it only loads any given file once.

Creating a module

What is a module, anyway? perlmod defines it as: just a set of related functions in a library file, i.e., a Perl package with the same name as the file.

Creating a module is EASY, but it is a little more work than just creating a file with code in it. First, you need to think of a module name. This is the basis for both the filename and the package name, and these have to be synchronised for some features to work. For project specific modules, I always create a new top-level namespace with the name of the project. For example, NameOfTheProject/SomeModule.pm is a good filename (in real life, use something a little more meaningful). The corresponding package is NameOfTheProject::SomeModule. Use CamelCaps like this, because everyone else does too.

The file must be in a directory that is listed in @INC. To find out what your @INC is, run perl -V. The current working directory (listed as its symbolic name . (a single dot)) should be listed. To begin with, putting the module in the script's directory is a good idea. It is the easiest way to keep things organized. If you want to put the module somewhere else, you will have to update @INC, so that perl knows where to find it. An easy way to do get code like this in the main script:

use lib 'path/to/the/modules'; # The example module could be path/to/the/modules/NameOfTheProject/Som +eModule.pm

What goes in the module itself doesn't require much explanation. I'll just give a complete example of a simple NameOfTheProject::SomeModule:

use strict; package NameOfTheProject::SomeModule; sub some_function { # put sane code here return 123; } 1;
Just list all the subs as you usually would, put a package statement at the top and a true value at the bottom (1 will suffice). Obviously, use strict is a good idea. You should never code a module that does not have this. Beware: A use strict; statement in the main script has no effect on the module.

A module runs only once. That means that for code to be reusable, it must be in a sub. In fact, it's considered very bad style to do anything (except declaring and initializing some variables) in the module's main code. Just don't do that.

You can now load the module and use its sub, simply by doing:

use NameOfTheProject::SomeModule; print NameOfTheProject::SomeModule::some_function(); # prints 123

You can have the module export its sub(s) to the caller's namespace (that is: the package the use statement is in. By default, this is main). For this, put after the package statement:

use base 'Exporter'; our @EXPORT_OK = ('some_function');
Then, when useing the module, you can request that some_function be imported to your namespace with:
use NameOfTheProject::SomeModule ('some_function'); print some_function(); # prints 123
To have it exported automatically, use @EXPORT instead of @EXPORT_OK. This will eventually bite you if the function names are generic. For example, many people get bitten by LWP::Simple's get function. It is not unlikely that you already have one.

There are more ways to export functions. I of course prefer to use my own module Exporter::Tidy. Not only because it's smaller and often faster, but mostly because it lets the user of a module define a prefix to avoid clashes. Read its documentation for instructions.

For the export/import mechanism, it is very important that the filename, the package name and the name used with use are equal. This is case sensitive. (Ever wondered why under Windows, use Strict; doesn't enable strict, but also doesn't emit any warning or error message? It has everything to do with the case insensitive filesystem that Windows uses.)

Stubbornly still wanting to include

Sometimes, a module just isn't logical. For example, when you want to use an external configuration file. (Many beginners and people who post code online put configuration in the script itself for ease of use, but this makes upgrading the script harder.) There are many configuration file reader modules you can use, but why use one of those if you can just use bare Perl?

This is where do comes in. What do does is very close to what an include would do, but with a very annoying exception: the new file gets its own lexical scope. In other words: a variable declared with my is not accessible externally. This follows all logical rules attached to lexical variables, but can be very annoying. Fortunately, this does not have to be a problem. do returns whatever the included script returned, and if you make that script just the contents of a hash, here's my favourite way to offer configurability:

# This is config.pl mirror => 'http://www.nl.example.com/mirror', path => '/var/www/example', skip_files => [ 'png', 'gif', 'jpg' ],
(The last , is optional, but it's included to make adding a line easier.)
# This is script.pl use strict; my %config = do 'config.pl'; chdir $config{path}; ...
Error checking is left as an excercise.

Because we used only the return value of the script, and never even touched a variable in config.pl, the inaccessibility of lexical variables is no longer a problem. Besides that, the code looks very clean and we have a very powerful config file format that automatically supports comments and all kinds of useful functions. How about interval => 24 * 60 * 60, for self-documentation? :)

Still not good enough

do updates %INC, which you may or may not want. To avoid this, use eval read_file instead. To find out if you want this, read perlvar.

There is a way to get an include() the way other languages have it. This is a very ugly hack that uses an internal exception made for Perl's debugger, and is possibly not future proof. As said before, you should not want to include a file. Still, because it is possible, I feel I have to tell you how. Just don't actually use it.

If you read the documentation for eval (which you of course should (don't use an operator without having read its documentation first)), you see that if it is called from within the DB package, it is executed in the caller's scope. This means that lexical values are made visible and the file behaves as a code block.

Here is an example to get an include() function that actually works the way most people expect:

use strict; package Acme::Include; use base 'Exporter'; use File::Slurp (); our @EXPORT = 'include'; { package DB; # The sub's name is fully qualified to avoid getting a B::Include sub Acme::Include::include ($) { my ($filename) = @_; my $code = qq[#line 1 "$filename"\n] . File::Slurp::read_file($filename); eval $code; } } 1;
Documentation for the #line directive is in perlsyn.

To test this new module, save it as Acme/Include.pm and create:

# This is foo.pl use strict; use Acme::Include; my $lexical = 'set in foo.pl'; include 'bar.pl'; print $lexical; # Should print: set in bar.pl
and:
# This is bar.pl use strict; $lexical = 'set in bar.pl'; # There is no "my" here, because that would create a *new* lexical # variable, hiding the existing one.
and then run perl foo.pl.

This example Acme::Include does not have any error checking. In practice, you will want to check $@ somewhere (but you also want to retain the value returned by the included file, and context to propagate properly. Good luck!).

Learning more

I wrote this tutorial to have an answer ready for the nth time someone in EFnet's #perlhelp asks why require works only once, or asks how to really include a file. Explaining the same thing over and over gets annoying over time. This is not a good guide to writing modules. For that, read chapter 10 of Beginning Perl and perlmod and perlnewmod. Of course, good code always comes with good documentation; so learn POD in 5 minutes.

One last thing

If you name your module Test, don't be surprised if it doesn't work. The current working directory comes last in @INC, so the Test module that is in the Perl distribution is probably loaded instead. This bites me at least once per year, this time while writing this tutorial :).


In reply to Including files by Juerd

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others browsing the Monastery: (10)
    As of 2014-10-01 09:29 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      How do you remember the number of days in each month?











      Results (392 votes), past polls