import fails if package namespace != module path

N

neurocline

I'm struggling with something. If I have a module, but the package
namespace inside the module doesn't match the path passed to use, then
import (with @EXPORT or @EXPORT_OK) doesn't work. There's something I
don't understand, obviously, but I don't know where the fault is.

If I do

use Extra::Bits::Name qw(func);

and my package is just in "package Name", then I get "Undefined
subroutine &main::fucn" when I try to access just "func" ("Name::func"
works fine). But if I rearranged paths so I can do "use Name
qw(func)", then everything works.

For example, I have a package contained in goober.pm that looks like
this

package goober;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(gooberme);
our $VERSION = '1.00';

sub gooberme
{
print STDERR "yeppers\n";
}

and I have a main program that looks like this

#!/usr/bin/perl
use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../../CorePerl";

use Blizzard::goober qw(gooberme);
gooberme();

then I get "Undefined subroutine &main::gooberme called at ...".
There's a reason why I can't just completely rearrange my library
paths to make the includes come out matching the package names. Or
rather - I can do that, it will be painful, and I didn't think it
would be necessary.

What am I missing? Obviously I don't understand something about use/
require and how package namespaces work.
 
X

xhoster

I'm struggling with something. If I have a module, but the package
namespace inside the module doesn't match the path passed to use, then
import (with @EXPORT or @EXPORT_OK) doesn't work. There's something I
don't understand, obviously, but I don't know where the fault is.

If I do

use Extra::Bits::Name qw(func);

and my package is just in "package Name", then I get "Undefined
subroutine &main::fucn" when I try to access just "func" ("Name::func"
works fine). But if I rearranged paths so I can do "use Name
qw(func)", then everything works.

Your use statement tries to call:
Extra::Bits::Name->import(qw(func))

Since there is presumably no subroutine named Extra::Bits::Name::import and
no array named @Extra::Bits::Name::ISA, then nothing happens. "use"
doesn't look into the used file to see what package it should call import
on, it bases that decision on the filename/module name indicated in the
"use" statement itself.

In this case, I don't see a work around that would be easier or work better
than just rearranging your code to conform to Perl's expectations regarding
module names and package names.

In another context, I'm contemplating of violating that expectation myself,
so that I can change "configuration" simply by changing a use, without
changing anything else.

#use Foo_config1;
use Foo_config2;

my $dir = $Foo::data_dir;
my $dbh = Foo::get_database_handle();

I'm thinking that if I do go this route, I should avoid using import at
all, or at least avoid optional imports, to avoid the problem you see.


Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 
B

Ben Morrow

Quoth (e-mail address removed):
I'm struggling with something. If I have a module, but the package
namespace inside the module doesn't match the path passed to use, then
import (with @EXPORT or @EXPORT_OK) doesn't work.

Don't do that then. :)
There's something I don't understand, obviously, but I don't know
where the fault is.

use Module ARGS;

is exactly equivalent to

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

except that the ->import step is omitted if Module doesn't have an
import method. If you really really want to do this, you can have a
module called Foo/Bar.pm which defines a package Baz by using

BEGIN {
require Foo::Bar;
Baz->import(ARGS);
}

instead of use Foo::Bar... however, I can't help thinking you're going
about this the wrong way. What are you trying to achieve? If you just
want to put the module somewhere else, you can ask perl to search that
somewhere else with

use lib 'somewhere/else';
If I do

use Extra::Bits::Name qw(func);

and my package is just in "package Name", then I get "Undefined
subroutine &main::fucn" when I try to access just "func" ("Name::func"
works fine). But if I rearranged paths so I can do "use Name
qw(func)", then everything works.

Yes. This is how the Perl module system works. The argument to use is
supposed to be a module name, not a strange way of writing a path; how
that name is resolved to a path is governed by @INC (manipulated with
lib.pm).
For example, I have a package contained in goober.pm that looks like
this

package goober;

Don't use lowercase package names. They are reserved for pragmas:
modules that affect how perl parses your program. In general it's best
to name your packages after something reasonably unique, so you don't
get conflicts later; I have a convention of using BMORROW::Blarg::* for
modules used by the Blarg project, where BMORROW is my CPAN id.
and I have a main program that looks like this

#!/usr/bin/perl
use strict;
use warnings;

use FindBin;
use lib "$FindBin::Bin/../../CorePerl";

Since you already know about lib.pm, what stopped you trying

use lib "$FindBin::Bin/../../CorePerl/Blizzard";

? You can keep both 'use lib' lines, if you have some modules in the
CorePerl directory and some in CorePerl/Blizzard (though that seems like
a bad idea). In general it would be better to use File::Spec to create
that path; however, that may not be important in your case.

Ben
 
B

Ben Morrow

Quoth (e-mail address removed):
In this case, I don't see a work around that would be easier or work better
than just rearranging your code to conform to Perl's expectations regarding
module names and package names.

In another context, I'm contemplating of violating that expectation myself,
so that I can change "configuration" simply by changing a use, without
changing anything else.

#use Foo_config1;
use Foo_config2;

my $dir = $Foo::data_dir;
my $dbh = Foo::get_database_handle();

I'm thinking that if I do go this route, I should avoid using import at
all, or at least avoid optional imports, to avoid the problem you see.

Would it not be better to do something like

package Foo;

use warnings;
use strict;
use Carp;

sub import {
shift eq '-config' or croak 'must supply a config!';
my $config = 'Foo::' . shift;

# the 1 works around a bug in some versions of 5.8 :(
eval "require $config; 1" or croak $@;

$config->export_to_level(1, @_);
}

1;

package main;

use Foo -config => 'config1', qw/$data_dir get_database_handle/;

my $dir = $data_dir;
my $dbh = get_database_handle();

__END__

This assumes Foo::* inherits Exporter::import, of course, though that
can be worked around if necessary (it's harder than you might think,
because you have to get caller() right).

Or you could do the thing properly and use OO :). Note that you don't
*have* to have Foo::config1 inherit from Foo: you can have the reverse,
and you can decide what to inherit from at runtime. File::Spec does
this, for example.

package Foo;

use warnings;
use strict;

use Carp;

our @ISA;

sub import {
my $config = "Foo::$_[0]";
eval "require $config; 1" or croak $@;
@ISA = $config;
}

1;

package main;

use Foo config1;

my $dir = Foo->data_dir;
my $dbh = Foo->get_database_handle();

__END__

Ben
 
N

neurocline

Your use statement tries to call:
Extra::Bits::Name->import(qw(func))
and

use Module ARGS;

is exactly equivalent to

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

Thanks. I knew that at one level, but I wasn't thinking it through.
Xho called it out clearly enough that it penetrated my skull. I wonder
if I can make extra import routines above and beyond the one Exporter
makes.

One reason I was playing with use vs package names is that I'm trying
to make self-installing modules (through a code reference pushed into
@INC that's just a few lines of HTTP fetch), and so I want my modules
to have a unique namespace so I can distinguish them from internal
ones. And I don't want to through all the code and edit their uses of
names.

Thanks for the help, I'm going to try a few things out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top