tags:

views:

193

answers:

5

I don't understand what happens here :

use PAR { file => 'foo.par', fallback => 1 };

I think that's an anonymous hash. How is a module using it from the use line? Can you shed some light?

EDIT: I'm not interested in the PAR module. I'm just interested in how that works behind the curtain. How can I configure my modules like that?

A: 

PAR is the CPAN module Perl Archive Toolkit. The hashref is configuration parameters being passed to PAR.

The code:

use PAR { file => 'foo.par, fallback => 1 };
use Foo::Bar;

means to use Foo::Bar if it is available, but otherwise fall back to using the archive "foo.par" (which presumably holds an archived version of Foo::Bar).

Ether
Oh. Sorry. I don't understand what allows that syntax to work. I'm not interested in the PAR module per-se, just how the author made that possible.
Geo
A ha! In that case, I've just provided the real answer to your question. :)
Ether
+7  A: 

More basically, this is what the funny hashref syntax does (using perldoc -f use as a reference):

Say we have this basic module (put it in Foo.pm in your current directory):

package Foo;

use Data::Dumper;
sub import
{
    print "import was passed these arguments: ". Dumper(\@_);
}

1;

when we call perl -I. -wle'use Foo { a => 1, b => 2}', the code Foo->import({a=>1, b=>2}) is executed. So this is what we get as output:

import was passed these arguments: $VAR1 = [
          'Foo',
          {
            'a' => 1,
            'b' => 2
          }
        ];

Basically, this syntax lets us do magic with the Exporter, but in truth you can make import() do anything you like (just be sure to document heavily so as to not cause confusion!)

Ether
+7  A: 

When you use a module, you can pass a list of arguments to it. In your example (which seems to have a typo, missing a closing quote), a list with one element (a hash reference) is passed.

More generally:

use Module LIST

Becomes this:

BEGIN {
    require Module;
    Module->import( LIST );
}

The BEGIN block ensures that all of the stuff happens at compile time. The require loads the module into memory, if it's not there already. And then the module's import() method is called with whatever arguments were passed (as LIST) in the original use statement.

In order for your own modules to do something with such a LIST of arguments, your module would need to define an import() method. Many modules don't do that; rather, they inherit import() from the Exporter class. See perldoc -f use for more details.

If your module defines its own import() method, you will either need to export symbols into the client code yourself or, more commonly, use the export_to_level() method provided by Exporter. The first argument to this method is a positive integer specifying the level in the call stack to which to export symbols. The most common value of 1 means to export symbols one level above the current package -- that is, to the client code that is using your module. Here is an outline of what your import() method would need to do.

sub import {
    my ($class, @args) = @_;

    # Do whatever you need to do with the LIST of arguments
    # supplied by the client code using your module.


    # Let Exporter do its normal work of exporting symbols
    # into the client code using your module.
    $class->export_to_level(1, @_);
}
FM
+2  A: 

Yes, that's an anonymous hash. It's passed as an argument to the modules import method.

Michael Carman
A: 

Direct answer to your question: PAR does this (line 340):

# called on "use PAR"
sub import {
    my $class = shift;
    [...]
    my @args = @_;
    [...]
    # process args to use PAR 'foo.par', { opts }, ...;
    foreach my $par (@args) {
        if (ref($par) eq 'HASH') { # <---- This is what handle's your case!
            # we have been passed a hash reference
            _import_hash_ref($par);
        }
        elsif ($par =~ /[?*{}\[\]]/) {
           # implement globbing for PAR archives
           [...]
        }
        else {
            # ordinary string argument => file
            [...]
        }
    }

Now, unfortunately, once you drill down into what's really happening there, you'll realize you've picked one of most complicated modules on CPAN as an example to learn from, so I'd suggest you have a look at the fine documentation on modules instead. To give you a guide what to look for: When you "use" a module and provide arguments to the use statement, perl will load the module and call its "import" method with the list of arguments.

In your example case, there's simply one argument: A reference to a hash. The {key=>"value",key2=>"value2",...} syntax is the constructor for anonymous hashes. These are documented in the perlref manual page, but explained in more friendly terms in the perlreftut tutorial.

tsee