Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Export from module in subdirectory

by SuicideJunkie (Vicar)
on Oct 09, 2012 at 18:25 UTC ( [id://998052]=perlquestion: print w/replies, xml ) Need Help??

SuicideJunkie has asked for the wisdom of the Perl Monks concerning the following question:

I have a module which was working great when it was in the same directory as my script. Recently I tried to organize things and put the module in a subdirectory, but the functions are no longer being exported to main::

Originally, I could use test; and then just call min().

After moving the file to lib/test.pm, I use lib::test, and min(); no longer works; I had to say test::min();

What have I done wrong here, and how can I get my functions exported while the module is in a subdirectory?

test.pl
use strict; use warnings; #use test; use lib::test; #print min(5, undef, 10, 3); print test::min(5, undef, 10, 3);
#test.pm
lib/test.pm
package test; use Exporter 'import'; our @EXPORT = qw (min); sub min { my $best; foreach my $item ( @_ ) { $best = $item if not defined ($best) or (defined($item) and $i +tem < $best); } return $best; }

(Treating undef as zero wasn't convenient. This ignores undefs and returns the smallest defined value)

Replies are listed 'Best First'.
Re: Export from module in subdirectory
by tobyink (Canon) on Oct 09, 2012 at 19:16 UTC

    use does three relatively unrelated things. The line use Foo::Bar 1.0 qw(foo); does, in sequence:

    1. Converts Foo::Bar to a filename Foo/Bar.pm locates (in @INC), opens, reads and executes the file.

    2. Calls the method Foo::Bar->VERSION(1.0). VERSION is just a plain old method call, but because most people don't define a function called VERSION they inherit the default implementation from UNIVERSAL. The default implementation checks $Foo::Bar::VERSION is greater than or equal to 1.0 and croaks if it is not.

    3. Calls Foo::Bar->import('foo') if that method exists. Again, this is just a normal method call; nothing magic.

    Now, I say those things are unrelated, but if the file Foo/Bar.pm contains a package definition for Foo::Bar, which defines $VERSION and import then it all comes together beautifully.

    In your situation, lib/test.pm doesn't contain a package definition for lib::test, but contains a package definition for test, so it doesn't all work together.

    That said, it's easy enough to put those three stages together manually, so that it works for your particular situation...

    BEGIN { require lib::test; # test->VERSION(1.0); ## you didn't have a version number test->import(); }
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Export from module in subdirectory
by toolic (Bishop) on Oct 09, 2012 at 18:49 UTC
    Inside test.pm you need to declare the package as:
    package lib::test;

    Then you can use min(); in test.pl.

    That being said, you should eventually select better names than lib and test.

      "you should eventually select better names than lib and test"

      Interestingly, this was uploaded to CPAN just now... Test::Lib 0.001.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      That makes total sense once someone has said it :) Thanks!

      I used lib and test for the cut-down sample rather than the 50k of original code.

Re: Export from module in subdirectory
by jandrew (Chaplain) on Oct 09, 2012 at 19:02 UTC

    You could declare your folder with test.pm in @INC as another alternative

    use strict; use warnings; use lib 'lib'; use test; print min( 5, undef, 10, 3);
Re: Export from module in subdirectory
by Don Coyote (Hermit) on Oct 10, 2012 at 12:37 UTC

    Great thread! Just like to get some clarity on a couple of things.

    If the use lib::test is not defined in test.pm and is therefore not found, how is the programme finding and executing test::min()? As SuicideJunkie has stated, this way works, therefore are the directory and subdirs in which the op is operating not already imported to the @INC?

    Given, the assumption the op is already within an @INC'd directory, at what point, in the package declaration of lib::test do you 'cut-off' the system path, such that you are not declaring the::whole::path::to::lib::test?

    The answers here have shed a lot of light on using modules in different directories which is great, as i am currently getting to grips with similar issues in strawberry perl. Particularly tobyinks' description of the way use functions.

      You're looking at it backwards. Don't decide on the code because of the filenames; decide on the filenames because of the code.

      Choose a meaningful package name, like "Quux::Enhancer", and declare the package name in the module (somewhere near the top - the only things it makes sense to put before the package declaration are lexical pragma like use strict; use warnings; use 5.010;) using:

      package Quux::Enhancer;

      Now decide on which lib dir it's going to live inside. Often this will be a directory which is in perl's default @INC list. Within that directory create a subdirectory called Quux, and within that save your module as Enhancer.pm.

      Then in your script, if that lib dir is not in perl's default @INC, include this:

      use lib '/path/to/lib'; ## not including 'Quux'!!

      And then in the script load the module like this:

      use Quux::Enhancer;

      If you ever need to move the file, then that's fine; no need to change anything within the module; just make sure it's always called Enhancer.pm, and always kept in a directory called Quux. Then use lib to tell your Perl script where to find it.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        Thanks tobyink, this helps explain why I don't need to declare the package all the way back to some random path separator. I shall have to have a bit of a play around with some self constructed modules and directories. This should help me appreciate the way use is working, and some of the other replies in this thread.

        Coyote

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://998052]
Front-paged by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (5)
As of 2024-04-23 20:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found