require fails yet module exists in @INC path...?

C

Chris

I am completely stupified at this problem.

Since there is way too much code to post in order to provide a good
picture of the problem, I'll provide some background which I think
accurately frames my environment and what my scripts and modules are
supposed to be doing (and actually ARE doing except for this one very
weird exception):

- Windows 2003 Server
- AS Perl v.5.8.4 Build 810
- Script path: D:\MyApp (this is made up)
- Script: D:\MyApp\myapp.pl (this is made up)

Under D:\MyApp, I have a bunch of modules I am using. A lot of the
modules are in D:\MyApp\Foo\Bar (again, made up). In Foo\Bar, I have
modules A.pm, B.pm, and C.pm. A, B and C have modules A1.pm, A2.pm,
B1.pm, B2.pm, C1.pm and C2.pm which they require on the fly. A, B, and
C are basically "traffic cops" for the A1, A2, B1, B2 modules, etc.

I have a bunch of data that is being read from a database. How the
data is handled is defined in the database and this maps directly to
these A1, A2, B1, B2 modules. So, I have some data, and I also have
"this data should be handled using A's #1 way of doing things" or
"process this using A->A1->method_blah() method" And of course A
requires A1 the first time it is needed and calls this exposed,
predefined method_blah() in A1.pm to handle this data. (Thereafter, if
I have to use A1 through A, A already knows about A1.)

A1, A2, B1, B2, etc. are require'd on the fly as they are needed
because the data in the database may or may not need each of A1, A2,
B1, B2,..., C2, etc. (As you may be able to see, this is "kind" of a
"plugin" architecture. We could have A1 thru A<n> handlers for A, and
the same for B and C, etc. We could even have a D, E, F.pm, etc. with
D1.pm thru D<n>.pm and so on...) Really important here, and this is
why I am totally baffled:

A.pm, B.pm, C.pm, as well as A1.pm, A2.pm... etc. are ALL located in
D:\MyApp\Foo\Bar.

At the beginning of D:\MyApp\myapp.pl, I have:

use strict;
use warnings qw( all );

BEGIN { unshift @INC, $ENV{MYAPP_ROOT} if $ENV{MYAPP_ROOT} }

and in my environment, I have:

D:\MyApp> set MYAPP_ROOT=D:\MyApp

SO.... With all that said, the "require" code in A.pm, B.pm, and C.pm
is really identical and this is the exact code, cut and pasted from one
of A, B or C.pm:

## Private Method: Initialize Accessor
## On demand initialization of an agent accessor.

sub __initialize_accessor {

## Get parameters.

my $self = shift;
my $ctxt = shift;

## Initialize agent accessors from the accessors registry list.

if (exists $AccessorsRegistry->{$ctxt->Accessor}) {
my $accessor = $AccessorsRegistry->{$ctxt->Accessor};
my $class = "${base_class}::$accessor";
eval qq{ require $class };
croak "Failed to initialize C Agent accessor '$accessor'! Either
the accessor hasn't been properly installed or the accessor isn't in
\@INC..." if $@;
$self->__add( $accessor => $class->new( $ctxt ) );
} else {
croak "Invalid accessor /${\ $ctxt->Accessor }/ specified.";
}

}

Essentially the "if exists" just checks to make sure that what the
database said to use is registered in a registry somewhere, and if it
is, then it requires it on the fly and adds a singleton instance of the
"accessor" (A1, A2, B1...etc.) to the class. When the module is added,
then the methods I want exposed be called through A, B or C like:

$self->$accessor->$method( <parameters-here> );

$base_class = "Foo::Bar";
$accessor = like "A1", "A2", "B1", etc.

Which means $class above would be "Foo::Bar::A1", "Foo::Bar::A2",
"Foo::Bar::B1", etc.

Here's the kicker... A.pm successfully requires A1.pm and A2.pm. B.pm
successfully requires B1.pm and B2.pm. C.pm however, does NOT require
C1.pm successfully. It says it can't find it in the @INC path!

Another direct cut and paste (with proper substitution of names):

Can't locate Foo::Bar::C1 in @INC (@INC contains: d:\MyApp C:/Pe
rl/lib C:/Perl/site/lib .) at d:/MyApp/Foo/Bar/C.pm line 152.

Again, ALL these modules are in D:\MyApp\Foo\Bar. C1.pm is DEFINITELY
in the same directory. I've quaduruple checked it. Why in the world I
can require A1.pm, A2.pm, B1 and B2, but not C1.pm I don't know. I've
tried setting MYAPP_ROOT to both D:\MyApp and D:/MyApp, but that
doesn't seem to make a difference. And again, A1, A2, B1, and B2 are
being required properly. Someone would say the __initialize_accessor()
code in C.pm *has* to be different somehow, but this is not the case.
Again I've quadruple checked this and this EXACT code works with
complete success on Perl v5.8.3 on a Windows XP workstation. But on
this Windows 2003 Server with Perl v5.8.4, it doesn't.

Another weird thing: When C.pm tries to require C1.pm and fails, the
program STOPS even though it's wrapped in an eval(). And the croak
"Error blah blah blah" if $@; directly afterwards never fires. The
program just stops right at the eval statement in the C.pm module.
When I take the eval() out and just doing a straight require, I get the
error I cut and pasted above. (It's like the eval() wrap doesn't work
either.)

It's just the craziest thing I've ever seen. The fact that my code
works FLAWLESSLY on my laptop is just stupifiying. I located some
other articles on c.l.p.m regarding require failing, but none really
seem to shed light on my issue.

Sorry for the somewhat lengthy explanation, but if I posted the actual
code it would be 20x longer, and the above accurately represents what I
am doing.

-ceo
 
S

Sisyphus

[snip]
Another direct cut and paste (with proper substitution of names):

Can't locate Foo::Bar::C1 in @INC (@INC contains: d:\MyApp C:/Pe
rl/lib C:/Perl/site/lib .) at d:/MyApp/Foo/Bar/C.pm line 152.

Again, ALL these modules are in D:\MyApp\Foo\Bar. C1.pm is DEFINITELY
in the same directory.

You provided a bit too much for me to wade through, so I'll just address the
above excerpt :)

I've no problem in believing that d:/MyApp/Foo/Bar/C1.pm exists, but if you
look closely at the error message you'll see that there's no complaint about
not being able to find Foo/Bar/C1.pm. The complaint is that Foo::Bar::C1
can't be found. Why is that ?

Try running a script that contains the single line:
require some::rubbish;

Then note that the complaint is not that "some::rubbish" can't be found, but
that "some/rubbish.pm" can't be found.

Then try running a script that contains the single line:
require 'some::rubbish';

Now you get the complaint "some::rubbish" can't be found - and you would get
that complaint even if some/rubbish.pm did exist in one of the @INC
directories.

So, I guess that somewhere in your code (and it might even be in the code
you provided), you have written:
require 'Foo::Bar::C1';

when you should have written:
require Foo::Bar::C1;

Cheers,
Rob
 
C

castillo.bryan

at the beginning of D:\MyApp\myapp.pl, I have:

use strict;
use warnings qw( all );

BEGIN { unshift @INC, $ENV{MYAPP_ROOT} if $ENV{MYAPP_ROOT} }

and in my environment, I have:

D:\MyApp> set MYAPP_ROOT=D:\MyApp

Someone else already pointed out the base problem for you.....
I just wanted to say that you don't have to use an enviroment variable
to get include path you need for your modules if you startup script is
in the same directorty. You can do this:

use File::Basename;
use File::Spec::Functions qw/:ALL/;
BEGIN { unshift(@INC, canonpath(rel2abs(dirname($0)))) }
 
C

Chris

The documentation is clear on the use of "require" in the way that I am
using it. And I'm using it the wrong way. The question now isn't "why
isn't this working for C" but rather now "why did it work for A and B?"
Right? I mean either way, there is a problem here.

BUT... Since I'm not using "require" properly, it totally changes my
view, and I'm sure I'll work it out. Now, I'm just bewildered that
A.pm and B.pm are somehow require'd in properly.

Thanks!
-ceo
 
C

Chris

Actually no, I retract what I earlier commented on. The documentation
states that:

my $class = "Foo::Bar::C1";
eval "require $class";

should work. This IS what I am doing. See the example I posted again
in __initialize_accessor(). I am saying:

$base_class = "Foo::Bar";
$accessor = "C1";
$class = "${base_class}::$accessor";
# Which means $class should equal "Foo::Bar::C1"...
eval qq{ require $class };

This works for A1, A2, B1, and B2, but not for C1. I'm right back
where I started, though I see what you mean by your example now. But
no, I'm NOT doing:

require "Foo::Bar::C1";

somewhere in my code. I'm doing:

eval "require $class";

where $class = "Foo::Bar::C1";

Doesn't work.

-ceo
 
A

Anno Siegel

[How to get the directory of the script onto @INC]
Someone else already pointed out the base problem for you.....
I just wanted to say that you don't have to use an enviroment variable
to get include path you need for your modules if you startup script is
in the same directorty. You can do this:

use File::Basename;
use File::Spec::Functions qw/:ALL/;
BEGIN { unshift(@INC, canonpath(rel2abs(dirname($0)))) }

That is the primary purpose of the standard FindBin module:

use FindBin;
use lib $FindBin::Bin;

Anno
 
C

Chris

Thanks for the tip on that. I'll look into doing this. Seems much
simpler.

But I'm not any further along on the other issue. I maintain that I am
using require that correct way (though at one point I thought maybe I
was not). I continue to be baffled because this isn't like the first
time I've done a:

eval qq{ require $class };

where $class = "Some::Module::Name";

And A1, A2, B1, and B2 work this way. C1 does not.

-ceo
 
X

xhoster

Jim Gibson said:
You are aware, aren't you, that

my $class = "Foo::Bar::C1";
require $class;

is not the same as

require "Foo::Bar::C1";

Actually, it is (effectively) the same as that.

perl -le 'my $x="Tie::File"; require $x'

perl -le 'require "Tie::File"'

Both give the same error.
but is instead equivalent to

require Foo::Bar::C1;

perl -le 'require Tie::File'

Gives no error, so is not equivalent to the preceeding.

The quote characters do not become part of the string stored in $class.

That is correct, but that still doesn't make $class a bareword.

It is the interpolation part of the string-eval that converts the variable
to a bareword, but your examples didn't retain the string-eval.

Xho
 
S

Sisyphus

Chris said:
Thanks for the tip on that. I'll look into doing this. Seems much
simpler.

But I'm not any further along on the other issue. I maintain that I am
using require that correct way (though at one point I thought maybe I
was not). I continue to be baffled because this isn't like the first
time I've done a:

eval qq{ require $class };

where $class = "Some::Module::Name";

And A1, A2, B1, and B2 work this way. C1 does not.

If $class contains a string like "Some::Module::Name" then I'm finding that
it's ok to do:
eval qq{require $class};

but not:
eval {require $class};

and not:
require $class;

The last 2 will inevitably complain that "Some::Module::Name" can't be
found.
The first will function as desired.

If you want to use either of the last 2, then $class needs to be a string
like "Some/Module/Name.pm".

Cheers,
Rob
 

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,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top