Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Finding files relative to a module

by hsmyers (Canon)
on May 15, 2011 at 04:01 UTC ( [id://904908]=perlquestion: print w/replies, xml ) Need Help??

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

In a module that has worked without error for a very long time, under Linux/Perl 5.8.1 I now get a warning about the following code:

package Chess::PGN::EPD; use strict; use warnings; use Chess::PGN::Moves; use File::Spec::Functions; use Storable qw( retrieve ); use Cwd qw( realpath ); use Try::Tiny qw( try catch ); require Exporter; my ( $hECO, $hNIC, $hOpening ); my %hash = ( ECO => \$hECO, NIC => \$hNIC, Opening => \$hOpening ); my $db_dir_qfn = realpath( catfile( __PACKAGE__, updir(), 'db' ) ); unless (-d $db_dir_qfn) { $db_dir_qfn = realpath('db'); }
The quote from the PAUSE report is:
Use of uninitialized value in -d at /home/sand/.cpan/build/Chess-PGN-E +PD-0.28-WRroyj/blib/lib/Chess/PGN/EPD.pm line 22. t/01_epdcode.t ...... ok t/02_Storable.t ..... ok Use of uninitialized value in -d at /home/sand/.cpan/build/Chess-PGN-EPD-0.28-WRroyj/blib/lib/Chess/PG +N/EPD.pm line 22 (#1) (W uninitialized) An undefined value was used as if it were alread +y defined. It was interpreted as a "" or a 0, but maybe it was a mi +stake. To suppress this warning assign a defined value to your variables. To help you figure out what was undefined, perl tells you what ope +ration you used the undefined value in. Note, however, that perl optimiz +es your program and the operation displayed in the warning may not necessa +rily appear literally in your program. For example, "that $foo" is usually optimized into "that " . $foo, and the warning will refer +to the concatenation (.) operator, even though there is no . in your program.
Line 22 is the unless (-d $db_dir_qfn) { line. I'd check to see just what is going on, but I'm flying blind until I replicate the test environment---in other words it works fine on all other Perls and under Windows of any type since 2K.

I've been pointed towards File::ShareDir and its associated modules but I found the documentation pretty much opaque (at least to me) leaving me hoping for a 'relative files for dummies' how-to. I'd certainly settle for an example based on the code fragment shown above :)

Note: I should point out that I realize that this is a warning, not an error. In addition, the code still manages to work in that all of the tests that depend on the presence of the data base files all work as designed. (Yes, I'm puzzled myself as to why it works given the warning...)

Update: A large single thanks to your collective wisdom. I am handicapped by the lack (for now) of a Linux box to test on. Had I one, I would have hit this with the appropriate size stick until the problem was solved. That said, I would have missed your observations and probably not have produced as accurate a solution. The observation about undef and that __PACKAGE__ was a wash point me in the correct direction. We'll see---again thanks much!

--hsm

"Never try to teach a pig to sing...it wastes your time and it annoys the pig."

Replies are listed 'Best First'.
Re: Finding files relative to a module
by GrandFather (Saint) on May 15, 2011 at 05:38 UTC

    Looks like you are hoping that catfile( __PACKAGE__, updir(), 'db' ) will find the folder 'db' relative to the folder containg the .pm file. However __PACKAGE__ is Chess::PGN::EPD which is unlikely to be what you mean and updir() removes it in any case so the catfile call is effectively catfile('db') which returns 'db' without the context you seem to be hoping for.

    A technique that may help is to look up %INC for the module entry:

    my $modulePath = $INC{'Chess/PGN/EPD.pm'};

    which will give a relative or absolute path (depending on where the module is) ending in 'Chess/PGN/Moves.pm'. That is, the file name will need to be stripped off the end of the path. Something like the following may work:

    ... use File::Spec::Functions qw(rel2abs splitpath updir catdir); use Cwd qw(realpath); my $loadPath = rel2abs ($INC{'Chess/PGN/EPD.pm'}); my @parts = splitpath ($loadPath); my $db_dir_qfn = realpath (catdir (@parts[0, 1], updir(), 'db'));
    True laziness is hard work
Re: Finding files relative to a module
by John M. Dlugosz (Monsignor) on May 15, 2011 at 04:26 UTC
    Apparently, realpath( catfile( __PACKAGE__, updir(), 'db' ) ) is producing undef.

    Look up and see under what conditions realpath will be undef. Maybe it's being fed undef as one of its arguments?

    In any case, what do you really want to do if that value is undef? I'm guessing your logic is that if the directory by that name exists use it, or else use realpath('db'). If it has trouble even figureing out the proposed directory, that is in the same boat, right?

    So make it:

    unless (defined $db_dir_qfn && -d $db_dir_qfn) {
    In any case, perhaps the problem isn't that the code finding the directory behaves any differently, but that -d used to not warn and now it does? It might has simply said "no, that's not a valid directory" when fed undef before. You can look that up in perldelta or just try it on your existing Perl installation.

    Note that you can write it more concisely as:

    $db_dir_qfn = realpath('db') unless defined $db_dir_qfn && -d $db_dir_ +qfn;
    but then again, the test is the important part and maybe it should still go up front:
    defined $db_dir_qfn && -d $db_dir_qfn or $db_dir_qfn = realpath('db');
    saves the excess bracing.
Re: Finding files relative to a module
by Khen1950fx (Canon) on May 15, 2011 at 04:33 UTC
    I tried it with if ! instead of unless. Worked.
    package Chess::PGN::EPD; use strict; use warnings; use Chess::PGN::Moves; use File::Spec::Functions; use Storable qw( retrieve ); use Cwd qw( realpath ); use Try::Tiny qw( try catch ); require Exporter; my ( $hECO, $hNIC, $hOpening ); my (%hash) = ( ECO => \$hECO, NIC => \$hNIC, Opening => \$hOpening ); my $db_dir_qfn = realpath( catfile( __PACKAGE__, updir(), 'db' )); if ( -d !$db_dir_qfn ) { $db_dir_qfn = realpath('db'); }
Re: Finding files relative to a module
by wind (Priest) on May 16, 2011 at 20:30 UTC

    GrandFather already explained why your code was not doing what you thought it was.

    Here's an additional solution for achieving what you want though:

    use Cwd qw(abs_path); use File::Basename qw(dirname); my $dirname = dirname(__FILE__); my $db_dir_qfn = abs_path("$dirname/../db"); print "$db_dir_qfn\n";
Re: Finding files relative to a module
by Anonymous Monk on May 17, 2011 at 06:36 UTC
    "Never try to teach a pig to sing...it wastes your time and it annoys the pig."

    When monks take the time to write, give you code and documentation links, read them ... *****insert something clever about singing pigs here*****

      After more than 10 years, you are just now getting annoyed by my sig? Gee, don't quite know what to say except thanks for the advice---I'll take it in the same spirit it was given :) Oh, enjoy the sig one more time...

      --hsm

      "Never try to teach a pig to sing...it wastes your time and it annoys the pig."

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (9)
As of 2024-04-19 09:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found