Re: How to determine absolute path of current Perl file?
by Discipulus (Canon) on Feb 29, 2016 at 09:37 UTC
|
hello hakonhagland and welcome to the monastery,
probably i do not fully understand your question (in case i'm sorry) but is not abs_path from core module Cwd what you need? anyway the last module you cited is fairly simple to understand: it cycles @INC and tries possible instances of file, the same way Perl does when you use a module.
Just a dozen of lines plus an half doze to handle the path separator of different OS.
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
|
Hi Discipulus!
Thanks for your reply. My understanding is that Cwd::abs_path() uses the current directory, but that directory may not be equal to the initial current directory (for example if the user has called chdir). Regarding Module::Path, yes it could work.. but not all perl files are modules, for example the main script ./test/test.pl. Also I think there is no reason to cycle all the @INC directories for the given module, when it always (if the path is relative) will be under (that is, relative to) the initial current directory.
| [reply] [d/l] [select] |
Re: How to determine absolute path of current Perl file?
by Hosen1989 (Scribe) on Feb 29, 2016 at 12:47 UTC
|
Hi
I had faced some issue like yours (I think).
try next lines in your script (It work for me):
use Cwd;
my $this_file_full_path = Cwd::abs_path(__FILE__);
print $this_file_full_path;
BR
Hosen | [reply] [d/l] |
Re: How to determine absolute path of current Perl file?
by 1nickt (Canon) on Feb 29, 2016 at 11:44 UTC
|
use Cwd qw/ realpath /;
my $path = realpath($0);
(note that realpath() is just an alias for abs_path())
Hope this helps!
The way forward always starts with a minimal test.
| [reply] [d/l] [select] |
|
Hi 1nickt! Thanks for your reply. Yes realpath($0) will give me the absolute path of $0 but it will be relative to the current directory, and not the initial current directory. For example, if the user script has changed directory with chdir it will not give a correct path name I think.
| [reply] [d/l] [select] |
|
hello, this i was used to do in the script perspective:
my $origin = File::Spec->file_name_is_absolute($0) ? $0 : File::Spec->
+rel2abs($0) ;
my ($drive,$directories,$file) = File::Spec->splitpath( $origin );
my $path = File::Spec->catdir($drive,$directories);
################ check starting path
my $current = File::Spec->rel2abs('.');
if ($current ne $path) {
(chdir $path and print "OK chdir to $path\n")|| die "FATAL una
+ble to change directory to '$path'.";
}
But if now i understand, you want in a module.pm get the absolute path of the script.pl that used it.
If so you can have in the module a BEGIN block that executes before any attempt for (user's) script to change directory. If in the script there is a chdir in a BEGIN block before loading your module.. you are lost.
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
|
|
|
| [reply] |
|
Re: How to determine absolute path of current Perl file?
by Tanktalus (Canon) on Feb 29, 2016 at 22:27 UTC
|
Avoiding filters: good.
Avoiding PadWalker: mind saying why?
Given my experience with PPI, I'm going to guess that you'll have a larger dependency list and more fragile code than if you used PadWalker.
Having said that, if you want the full path name to the current file, just use __FILE__. And if you want the full path name to the file that just called you, just use (caller)[1]. As a bonus, caller will also give you the line number that you were called from.
I'm not sure what else you're looking for, but I'd like to discourage the use of PPI for this. I do use PPI to parse and rewrite code, and that was marginally painful. This just seems ... well, really painful. The authors of PPI may have differing opinions :)
| [reply] [d/l] [select] |
|
Hi Tanktalus!
Avoiding PadWalker: mind saying why?
The reluctance to use PadWalker was merely based on information I could read about
it in the source and Pod documentation of Data::Dumper::Simple.
It says:
Note that if you strongly object to source filters, I've also released
Data::Dumper::Names. It does what this module does by it uses
PadWalker instead of a source filter. Unfortunately, it has a few
limitations and is not as powerful as this module. Think of
Data::Dumper::Names as a "proof of concept".
Also Data::Dumper::Names
says:
This module is an alternative to Data::Dumper::Simple. Many people
like the aforementioned module but do not like the fact that it uses a
source filter. In order to pull off the trick with this module, we use
PadWalker. This introduces its own set of problems, not the least of
which is that PadWalker uses undocumented features of the Perl
internals and has an annoying tendency to break. Thus, if this module
doesn't work on your machine you may have to go back to
Data::Dumper::Simple.
Now, I tested PadWalker quickly today to check how it works for some
simple cases. And based on these tests I have a gut feeling that it may not be
as general solution as using PPI. Firstly, I noticed that it can only access
lexical variable names in the argument list. This is currently a severe limitation
since very often you want to print out package variables. On the other hand, a good thing about PadWalker
seems to be that it can easily differentiate between calls like p $var and
p func($var). (The p function here is the call to
Data::Printer::p()). So it will understand that in the latter
call $var is not the sought printed variable.
This is more difficult with PPI, but it should be possible.
Having said that, if you want the full path name to the current file,
just use __FILE__. And if you want the full path name to the file that
just called you, just use (caller)1. As a bonus, caller will also
give you the line number that you were called from.
Yes exactly, that linenumber information given by caller() was
what I was trying to exploit! However, the problem of determining
the absolute path of the filename still persists, since
__FILE__ can be a relative pathname.
I am curious why the Perl porters did not make __FILE__ always be an absolute pathname. I cannot see any benefits of populating it with a relative pathname :)
| [reply] [d/l] [select] |
|
> Note that if you strongly object to source filters, I've also released Data::Dumper::Names. It does what this module does by it uses PadWalker instead of a source filter. Unfortunately, it has a few limitations and is not as powerful as this module. Think of Data::Dumper::Names as a "proof of concept".
Ovid didn't update this text for years, but last time I talked to him he was very confident about this being stable.
But please note that PadWalker has still limitations, like when being called from within an eval .
see PadWalker::var_name BUG?
| [reply] |
|
Regarding benefits of non-absolute __FILE__. I suspect it is because the information requires consulting the file system, perhaps at length, to resolve links and such. Often unnecessary and always more expensive.
| [reply] [d/l] |
Re: How to determine absolute path of current Perl file?
by FreeBeerReekingMonk (Deacon) on Feb 29, 2016 at 21:48 UTC
|
So, require your module to be one of the first in the list. This worked for me:
runme.pl
#!/usr/bin/perl
# In order to 'use' a perlmodule in a userspace library you need to ad
+d it to @INC.
# But if you do not want to use an absolute path inside the script, yo
+u need this workaround:
BEGIN{
use Cwd 'abs_path';
my $this = $0; # this script
$this =~ s/[^\/]+$//; # strip the filename, now we have a (rel
+ative) directory
my $path = abs_path($this); # now we have an absolute director
+y
unshift @INC, $path; # which we add to @INC
# chdir('/tmp'); # does seem to confuse abs_path! Uncomment to
+ see
}
use My::Module;
My::Module::print_file_name();
My::Module::print_script_name();
My::Module::print_caller_name();
-*Module.pl*- ./My/Module.pm
#!/usr/bin/perl
package My::Module;
use feature qw(say);
local $_SCRIPT = "";
local $_PATH = "";
BEGIN{
use Cwd 'abs_path';
$_PATH = $0; # this script
$_PATH =~ s/([^\/]+)$//; # strip the filename, now we have a (
+relative) directory
$_SCRIPT = $1; # the stripped part is the filename
$_PATH = abs_path($_PATH); # now we have an absolute directory
+
print "My::Module 0=$0 _PATH=$_PATH _SCRIPT=$_SCRIPT \n";
}
sub print_file_name {
say __FILE__;
}
sub print_script_name {
say "print_script_name: $_PATH/$_SCRIPT";
}
sub print_caller_name {
my @D = caller();
$D[1]= abs_path($_PATH.'/'.$D[1]) unless $D[1]=~m{^/};
say "print_caller_name: @D";
}
1;
If you bet on the fact that if chdir() was done, and that new directory does NOT contain the script that was run, You can add a kill or warning in the BEGIN block of the Module.pm, like:
warn "ALERT ALERT ALERT" unless(-f "$_PATH/$_SCRIPT");
| [reply] [d/l] [select] |
Re: How to determine absolute path of current Perl file? (Data::Dumper::Lazy)
by LanX (Sage) on Mar 01, 2016 at 11:18 UTC
|
use Data::Dumper::Lazy;
@a = 1..5;
dmp {@a};
> without using PadWalker or a source filter
none of this involved, just B::Deparse which is core since the dinos died out ;-)
| [reply] [d/l] |
|
Hi LanX!
I was not aware of Data::Dumper::Lazy, thanks for bringing it to my attention. I looks really interesting to use B::Deparse. But I am not sure it will be compatible with the call syntax for Data::Printer. Currently I am planning to modify Data::Printer directly and propose a pull request to the author of the module. I have not considered building a new module on top of Data::Printer yet.
I also did some quick tests with Data::Dumper::Lazy and the output confused me a little bit. I think the module is still under development, am I right? :)
| [reply] |
|
> think the module is still under development, am I right?
Well unfortunately I tend to be a perfectionist and overload things with features.
I'm not aware of bugs, AFAIK it's stable.
> But I am not sure it will be compatible with the call syntax for Data::Printer .
Well you'd always need an extra surrounding { BLOCK } , any other argument structure will be returned 1to1 from this block
you could publish something like Data::Printer::Lazy.
> and the output confused me a little bit.
Could you please show me an example of this "confusing output"?
update
looked into the (little ;) code and it mentions
# TODO
# * ignore pragmas
Now I remember B::Deparse::coderef2text will list active use pragmas in the first lines, these need to be filtered out.
| [reply] [d/l] [select] |
Re: How to determine absolute path of current Perl file?
by Anonymous Monk on Mar 01, 2016 at 12:41 UTC
|
You have made the (reasonable) assumption that source files do not change during the execution? Why not further assume that the cwd is unchanged during compilation? Otherwise, you'd have to account for the possibility that a chdir occurs anywhere between the use statements...
| [reply] [d/l] |