views:

283

answers:

7

Hi Perl programmers,

I have started creating a Perl package that contains a default email template.

The MANIFEST looks something like:

SendMyEmail.pm
SendMyEmail/defualt_email.tt

Currently I know where the module (and the template) are - but does the module itself know where on disk it is? So could the module find the default template without my help?

# This is what I would like to do.
package SendMyEmail;
sub new {
    my ($self, $template) = @_;
    $template ||= $dir_of_SendMyEmail .'/SendMyEmail/default_email.tt'; # ??
}

Is there a better way of including a templates text, or a better place to put the template?

Any references to CPAN modules that do something similar would be welcome.

Thanks in advance.

+2  A: 

Rewritten to reflect what I learned in the comments:

  • Find Module's Path

    package FooBar;

    use File::Spec;
    sub location {
       return File::Spec->rel2abs( FILE);
    }

  • Where to put the template:
    Since the template will most likely be editable, maybe even by someone working over the net, I strongly advise putting it into a directory where the "code" contained in the template cannot be executed.

    Imagine someone calling: http://your.home.net/cgi-bin/default_email.tt

lexu
FindBin will only give you the location of the perl script that was started (the .pl file) not the location of the file invoking FindBin.
potyl
Good point! Obviously I didn't read the question close enough!
lexu
Alas, __FILE__ doesn't return the full path either, 'only' the path relative to the script, it seems. The camel book (ancient copy) isn't specific either.
lexu
Using File::Spec's rel2abs() you can get the full path: File::Spec::rel2abs(__FILE__)
mpeters
thanks potyl and mpeters, I've rewritten my answer according to your input.
lexu
+6  A: 

Each perl file has access to the variable __FILE__ which tells it its full path. Something like this should do the trick:

my $DEFAULT_TEMPLATE;
BEGIN {
 $DEFAULT_TEMPLATE = __FILE__;
 $DEFAULT_TEMPLATE =~ s,\.pm$,/default_email.tt,;
}

Still, if all you want is to bundle 'data' files with your modules then take a look at File::ShareDir which provides a way for doing that.

potyl
__FILE__ is described in perldata.http://perldoc.perl.org/perldata.html
CoffeeMonster
+3  A: 

Perl records the file location in the %INC variable too. You can use that when __FILE__ isn't available. See the documentation in perlvar for the details.

brian d foy
+5  A: 

You can use %INC hash if module is already loaded. For example:

## load the module
use Data::Dumper;

## output full path to Data::Dumper module loaded
print $INC{'Data/Dumper.pm'};

## see which module was loaded (if you have multiple folders with same modules)
print Dumper(\%INC);
Ivan Nevostruev
+2  A: 

You can use the __FILE__ token to get the name (including the path) of the current file. If you want to know the path to a different module (one that's already loaded) check the contents of the %INC hash.

Michael Carman
+7  A: 

Using %INC can be misleading in cases where the file does not exactly match the package name. (This is an anti-pattern, but it does happen, sometimes for justifiable reasons.) If you want to locate files, the handy __FILE__ token is your best bet. Example module that can locate itself:

package Foo::Bar;

use Cwd qw(abs_path);
use File::Basename qw(dirname);

sub module_dir { abs_path(dirname(__FILE__)) }

1;

Usage:

use Foo::Bar;

print Foo::Bar->module_dir, "\n";
John Siracusa
This will not work for the modules you can't control
Ivan Nevostruev
The example sub in the question is named "findmyself" and uses `__PACKAGE__`, so I think control of the module is a safe assumption.
John Siracusa
A: 

I use this bash alias to find the location of a module (e.g. to look at its implementation or to hack in some debugging print statements):

perlwhere() {
    perl -wle'eval "require $ARGV[0]" or die; ($mod = $ARGV[0]) =~ s|::|/|g; print $INC{"${mod}.pm"}' $1
}
$ perlwhere Test::More
/usr/lib/perl5/5.8.8/Test/More.pm
Ether