File.expand_path(__FILE__)

J

John Platte

I'm having a problem with File.expand_path(__FILE__) after a chdir.
Looks like a bug in Ruby to me. If someone can tell me what I'm doing
wrong, I'd be grateful.

Here's the reduction:

[ryan@kursk 15:26:38 ~]$ cat tmp/demo-problem.rb
puts "starting working directory: " + Dir.getwd
puts "expand_path: " + File.expand_path(__FILE__)
puts "about to change to dirname of __FILE__: " + __FILE__
Dir.chdir(File.dirname(__FILE__))
puts "new working directory: " + Dir.getwd
puts "expand_path: " + File.expand_path(__FILE__)

[ryan@kursk 15:26:40 ~]$ cd tmp

[ryan@kursk 15:26:44 ~/tmp]$ ruby demo-problem.rb
starting working directory: /Users/ryan/tmp
expand_path: /Users/ryan/tmp/demo-problem.rb
about to change to dirname of __FILE__: demo-problem.rb
new working directory: /Users/ryan/tmp
expand_path: /Users/ryan/tmp/demo-problem.rb

[ryan@kursk 15:26:45 ~/tmp]$ cd ..

[ryan@kursk 15:26:50 ~]$ ruby tmp/demo-problem.rb
starting working directory: /Users/ryan
expand_path: /Users/ryan/tmp/demo-problem.rb
about to change to dirname of __FILE__: tmp/demo-problem.rb
new working directory: /Users/ryan/tmp
expand_path: /Users/ryan/tmp/tmp/demo-problem.rb

[ryan@kursk 15:26:56 ~]$
 
S

Simon Strandgaard

I'm having a problem with File.expand_path(__FILE__) after a chdir.
Looks like a bug in Ruby to me. If someone can tell me what I'm doing
wrong, I'd be grateful.

Here's the reduction:

[ryan@kursk 15:26:38 ~]$ cat tmp/demo-problem.rb
puts "starting working directory: " + Dir.getwd
puts "expand_path: " + File.expand_path(__FILE__)
puts "about to change to dirname of __FILE__: " + __FILE__
Dir.chdir(File.dirname(__FILE__))
puts "new working directory: " + Dir.getwd
puts "expand_path: " + File.expand_path(__FILE__)

^^^^^^^^
BOOM

I guess you assume that __FILE__ change when doing chdir.
But it doesn't



server> ruby a.rb
"a.rb"
"/tmp"
"a.rb"
"/"
"a.rb"
"/tmp"
server> expand -t2 a.rb
p __FILE__, Dir.pwd
Dir.chdir("..") do
p __FILE__, Dir.pwd
end
p __FILE__, Dir.pwd
server>


As you can see, filenames doesn't change during chdir.


HTH,
 
H

Hal Fulton

Simon said:
I guess you assume that __FILE__ change when doing chdir.
But it doesn't

I think you've analyzed this incorrectly.

The value of __FILE__ doesn't change, nor did he expect it to.
But expand_path is giving him an erroneous result, is it not?

"/Users/ryan/tmp/tmp/demo-problem.rb" -- there is no tmp/tmp
directory if I understand correctly.

It does look like a bug to me.


Hal
 
S

Simon Strandgaard

Hal Fulton said:
I think you've analyzed this incorrectly.

The value of __FILE__ doesn't change, nor did he expect it to.
But expand_path is giving him an erroneous result, is it not?

"/Users/ryan/tmp/tmp/demo-problem.rb" -- there is no tmp/tmp
directory if I understand correctly.

It does look like a bug to me.

No bug.


At the last line "File.expand_path(__FILE__)" is being invoked.
Currend dir = "/Users/ryan/tmp/"
File name = "tmp/demo-problem.rb"

When these are being concatenated it outputs
absolut path = "/Users/ryan/tmp/tmp/demo-problem.rb"


concat is working ok.
 
H

Hal Fulton

Simon said:
No bug.


At the last line "File.expand_path(__FILE__)" is being invoked.
Currend dir = "/Users/ryan/tmp/"
File name = "tmp/demo-problem.rb"

When these are being concatenated it outputs
absolut path = "/Users/ryan/tmp/tmp/demo-problem.rb"


concat is working ok.

expand_path doesn't simply concatenate. If it did, we could
simply do dir + name.

Taking a valid relative pathname and returning an invalid
absolute pathname is not useful, certainly not a feature.

If not a bug, at least an anomaly.


Hal
 
S

Simon Strandgaard

Hal Fulton said:
expand_path doesn't simply concatenate. If it did, we could
simply do dir + name.


server> ruby -e 'p File.expand_path("a/b")'
"/tmp/a/b"
server> ls a
ls: a: No such file or directory
server>


Taking a valid relative pathname and returning an invalid
absolute pathname is not useful, certainly not a feature.

If not a bug, at least an anomaly.

I think concat are the desired behavier of expand_path.
For instance if you want to create a directory, you first
have to make the path, before you make it. I don't have
better evidence.
 
H

Hal Fulton

Simon said:
I think concat are the desired behavier of expand_path.
For instance if you want to create a directory, you first
have to make the path, before you make it. I don't have
better evidence.

I see your point, and I don't have a counterexample.

And I guess there is a problem with what the OP wanted --
if the original name is relative to the original current
directory, then the interpreter would have to keep track
of where we were relative to our original dir.

It is doable, but is it worth it? And is there a real
purpose to expand_path besides tilde substitution and
simple concatenation?

Matz??


Hal
 
S

Simon Strandgaard

Hal Fulton said:
I see your point, and I don't have a counterexample.

And I guess there is a problem with what the OP wanted --
if the original name is relative to the original current
directory, then the interpreter would have to keep track
of where we were relative to our original dir.

It is doable, but is it worth it? And is there a real
purpose to expand_path besides tilde substitution and
simple concatenation?


Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?
 
M

Mauricio Fernández

And I guess there is a problem with what the OP wanted --
if the original name is relative to the original current
directory, then the interpreter would have to keep track
of where we were relative to our original dir.

It is doable, but is it worth it? And is there a real
purpose to expand_path besides tilde substitution and
simple concatenation?

It does more than simple concatenation + ~ subst., it concatenates &
normalizes:

Dir.pwd
# =>"/tmp"
File.expand_path "../bin/sh"
# =>"/bin/sh"
# not => "/tmp/../bin/sh"

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

"You, sir, are nothing but a pathetically lame salesdroid!
I fart in your general direction!"
-- Randseed on #Linux
 
R

Robert Klemme

Simon Strandgaard said:
Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?

This is easily fixed:

09:58:20 [ruby]: /cygdrive/c/temp/ruby/pfile.rb
["/cygdrive/c/temp/ruby/pfile.rb", "/cygdrive/c/temp/ruby/pfile.rb"]
09:58:31 [ruby]: ./pfile.rb
["./pfile.rb", "/cygdrive/c/temp/ruby/pfile.rb"]
09:58:38 [ruby]: ruby pfile.rb
["pfile.rb", "/cygdrive/c/temp/ruby/pfile.rb"]
09:58:40 [ruby]: cat pfile.rb
#!/usr/bin/ruby

FILE = File.expand_path __FILE__

p [__FILE__, FILE]

Regards

robert
 
S

Simon Strandgaard

Robert Klemme said:
Simon Strandgaard said:
Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?

This is easily fixed:

FILE = File.expand_path __FILE__
p [__FILE__, FILE]

Not if the person has done a chdir just before expand_path.
I wonder why __FILE__ isn't an absolute path. Relative paths is
just too fragile.


Proposal: make __FILE__ an absolute path.
That would make __FILE__ robust to Dir.chdir.


Any thoughts on this proposal? fore or against
 
R

Robert Klemme

Simon Strandgaard said:
Robert Klemme said:
Simon Strandgaard said:
Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?

This is easily fixed:

FILE = File.expand_path __FILE__
p [__FILE__, FILE]

Not if the person has done a chdir just before expand_path.

Well, I should've written "first line in script".
I wonder why __FILE__ isn't an absolute path. Relative paths is
just too fragile.


Proposal: make __FILE__ an absolute path.
That would make __FILE__ robust to Dir.chdir.


Any thoughts on this proposal? fore or against

Slightly against, because

- it's easily fixed

- you loose information: there might be situations where the script wants
to know the exact path it was invoked with.

- most of the time (when invoked from the shell via path expansion)
scripts are invoked with an absolute path anyway.

Kind regards

robert
 
S

Simon Strandgaard

Robert Klemme said:
Simon Strandgaard said:
Robert Klemme said:
Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?

This is easily fixed:

FILE = File.expand_path __FILE__
p [__FILE__, FILE]

Not if the person has done a chdir just before expand_path.

Well, I should've written "first line in script".

ok ;-)

Slightly against, because

- it's easily fixed

Agree.. however see below

- you loose information: there might be situations where the script wants
to know the exact path it was invoked with.

I think its the wrong place to retrive this kind of information.
Broken metaphor... I have used it myself, but without thinking about it.

- most of the time (when invoked from the shell via path expansion)
scripts are invoked with an absolute path anyway.

Please elaborate.. I don't understand.

:)
 
R

Robert Klemme

Simon Strandgaard said:
Robert Klemme said:
Simon Strandgaard said:
Maybe extend __FILE__ with a #absolute method,
in order to make __FILE__ immune against chdir ?

This is easily fixed:

FILE = File.expand_path __FILE__
p [__FILE__, FILE]

Not if the person has done a chdir just before expand_path.

Well, I should've written "first line in script".

ok ;-)

Slightly against, because

- it's easily fixed

Agree.. however see below

- you loose information: there might be situations where the script wants
to know the exact path it was invoked with.

I think its the wrong place to retrive this kind of information.
Broken metaphor... I have used it myself, but without thinking about it.

Where would you expect it to reside? Maybe the best solution is

$0 : path as used for invocation
__FILE__: abs path to current file

Then I agree. :) Any objections? Does this break existing code?
Please elaborate.. I don't understand.

:)

15:35:31 [ContentReporter_BRANCH]: PATH="${PATH}:/c/temp/ruby" bash -c
'echo $PATH; dollar0.rb'
<privacy>:/c/temp/ruby
__FILE=/c/temp/ruby/dollar0.rb
$0=/c/temp/ruby/dollar0.rb
15:35:51 [ContentReporter_BRANCH]: cat /c/temp/ruby/dollar0.rb
#!/usr/bin/ruby

puts "__FILE=#{__FILE__}"
puts "$0=#{$0}"

The invocation (-c 'dollar0.rb') does not use a path but rather the shell
finds the executable based on its $PATH.

Regards

robert
 
K

Kent Dahl

Robert said:
Where would you expect it to reside? Maybe the best solution is

$0 : path as used for invocation
__FILE__: abs path to current file

Then I agree. :) Any objections? Does this break existing code?

Wouldn't this break the idiom of using

if __FILE__ == $0 then
#...
end

to make a file both require-able and executable?
I know I use it frequently.
 
R

Robert Klemme

Kent Dahl said:
Wouldn't this break the idiom of using

if __FILE__ == $0 then
#...
end

to make a file both require-able and executable?
I know I use it frequently.

Yeah, I think it is used quite frequently. Darn. The only ad hoc
sulution to this that occurs to me is to override __FILE__#== and $0#== to
repair this. Now this starts getting ugly... Simon?

robert
 
J

John Platte

The OP yawns and wakes up to a big thread that has sprouted up where he
posted his little codeling...


That was my expectation. I really don't understand why __FILE__ would
be relative. I did a lot of work in PHP before coming to Ruby, and PHP
uses an absolute path in its __FILE__, which is a wonderful thing when
trying to create programs that are robust against odd web server
configurations.

I see Perl uses relative paths for both __FILE__ and $0...and since a
lot of Ruby scripts use "if __FILE__ == $0", those two should keep
following the same policy. So I don't expect that behavior to change
for my odd little case.

Might there be another place to put this absolute path? (Or might one
exist already?) PHP defines a global $SCRIPT_FILENAME...
Slightly against, because

- it's easily fixed

but obviously from the head-scratching on this thread, the current
behavior at least threatens POLS.
- you loose information: there might be situations where the script
wants
to know the exact path it was invoked with.

That seems like more of a special case to me than knowing exactly where
we live in the filesystem, but I'll admit that if Ruby got this far
with this behavior, maybe I'm not in the majority.
- most of the time (when invoked from the shell via path expansion)
scripts are invoked with an absolute path anyway.

My situation: I was invoking a utility script from Vim's shell, and it
had a bug that dumped output in the wrong directory. As I hacked a fix,
somehow I wound up with code that triggered the unexpected behavior I
posted about (I apologize for not pointing out which part was
unexpected).

Whatever the solution, I want it to be easy to get an authoritative
absolute path for the current file from Ruby; I'd strongly prefer that
it not be fragile to chdirs, since that's a side effect that reduces
flexibility.

Surely there's an existing solution to this within Ruby or Perl or some
other language?

Thanks to the other posters for the workaround(s) and explanation.
 
R

Robert Klemme

John Platte said:
The OP yawns and wakes up to a big thread that has sprouted up where he
posted his little codeling...



That was my expectation. I really don't understand why __FILE__ would
be relative. I did a lot of work in PHP before coming to Ruby, and PHP
uses an absolute path in its __FILE__, which is a wonderful thing when
trying to create programs that are robust against odd web server
configurations.

I see Perl uses relative paths for both __FILE__ and $0...and since a
lot of Ruby scripts use "if __FILE__ == $0", those two should keep
following the same policy. So I don't expect that behavior to change
for my odd little case.

.... or operators are overloaded to ensure proper behavior.
Might there be another place to put this absolute path? (Or might one
exist already?) PHP defines a global $SCRIPT_FILENAME...


but obviously from the head-scratching on this thread, the current
behavior at least threatens POLS.


That seems like more of a special case to me than knowing exactly where
we live in the filesystem, but I'll admit that if Ruby got this far
with this behavior, maybe I'm not in the majority.

Both may be true. :)
My situation: I was invoking a utility script from Vim's shell, and it
had a bug that dumped output in the wrong directory. As I hacked a fix,
somehow I wound up with code that triggered the unexpected behavior I
posted about (I apologize for not pointing out which part was
unexpected).

Whatever the solution, I want it to be easy to get an authoritative
absolute path for the current file from Ruby; I'd strongly prefer that
it not be fragile to chdirs, since that's a side effect that reduces
flexibility.

Surely there's an existing solution to this within Ruby or Perl or some
other language?

See my other post:

# at the top of script
FILE = File.expand_path( __FILE __ )
Thanks to the other posters for the workaround(s) and explanation.

We love to bang our heads on simple looking but difficult to solve
problems. :)

robert
 
J

John Platte

.... or operators are overloaded to ensure proper behavior.

I can't imagine that would lead to increased predictability!

On this topic, however, it'd be nice to have a method like
this_file_invoked? that encapsulated the $0 == __FILE__ idiom.
See my other post:

# at the top of script
FILE = File.expand_path( __FILE __ )

Yes, that snippet was a workaround I was thanking you for, but I don't
consider it a solution to the problem:

it seems we can't determine the absolute path of __FILE__ correctly
after a chdir without having planned for that eventuality before the
chdir.

Can someone solve that one?
 
A

Ara.T.Howard

I can't imagine that would lead to increased predictability!

On this topic, however, it'd be nice to have a method like
this_file_invoked? that encapsulated the $0 == __FILE__ idiom.


Yes, that snippet was a workaround I was thanking you for, but I don't
consider it a solution to the problem:

it seems we can't determine the absolute path of __FILE__ correctly
after a chdir without having planned for that eventuality before the
chdir.

Can someone solve that one?

what's wrong with this, i do it in all my programs:

require 'pathname'

class Main
...
FILE = Pathname.new(__FILE__).realpath.to_s
...
end

what's wrong with solving it by planning for it?

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
===============================================================================
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top