ruby cross-platform File.basename

B

bwv549

What is the best idiom for generating a cross-platform basename?
(i.e., one that will still give the basename of a windows file on
linux and the basename of a linux file on windows).

filenames = ["C:\\path\\to\\file.txt", "/path/to/file.txt"]
filenames.all? {|fn| <some_xpltfrm_basename_idiom>(fn) ==
"file.txt" } # should be true

As I play around with this, it seems that on windows (ruby 1.8.7
(2010-01-10 patchlevel 249) [i386-mingw32]), File.basename will
generate the basename on either of the above examples, but on linux
(ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]) the windows
basename is not found. Based on this, I think this may be a fool-
proof cross-platform idiom for generating the basename:

File.basename( filename.gsub("\\","/") )

This works on windows and linux, at least the versions I'm running.

Any other/better ideas? Are there any gotchas with the one I'm using
above?
 
R

Robert Klemme

What is the best idiom for generating a cross-platform basename?
(i.e., one that will still give the basename of a windows file on
linux and the basename of a linux file on windows).

filenames = ["C:\\path\\to\\file.txt", "/path/to/file.txt"]
filenames.all? {|fn| <some_xpltfrm_basename_idiom>(fn) ==
"file.txt" } # should be true

As I play around with this, it seems that on windows (ruby 1.8.7
(2010-01-10 patchlevel 249) [i386-mingw32]), File.basename will
generate the basename on either of the above examples, but on linux
(ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]) the windows
basename is not found. Based on this, I think this may be a fool-
proof cross-platform idiom for generating the basename:

File.basename( filename.gsub("\\","/") )

This works on windows and linux, at least the versions I'm running.

Any other/better ideas? Are there any gotchas with the one I'm using
above?

What's wrong with using File.basename?

Kind regards

robert
 
B

bwv549

What's wrong with using File.basename?

On linux, you cannot get the basename of windows-ish files:

# on linux:
File.basename("C:\\path\\to\\file.txt") # -> gives: "C:\\path\\to\
\file.txt"

Heaven knows I would like to avoid all windows path names, but just
after you write something worthwhile you are told it needs to be able
to run on windows, too. The point is that it would be nice to know
how to *always* get the basename on any system for any kind of
filename.
 
M

Marnen Laibow-Koser

bwv549 said:
What is the best idiom for generating a cross-platform basename?
(i.e., one that will still give the basename of a windows file on
linux and the basename of a linux file on windows).

filenames = ["C:\\path\\to\\file.txt", "/path/to/file.txt"]
filenames.all? {|fn| <some_xpltfrm_basename_idiom>(fn) ==
"file.txt" } # should be true

As I play around with this, it seems that on windows (ruby 1.8.7
(2010-01-10 patchlevel 249) [i386-mingw32]), File.basename will
generate the basename on either of the above examples, but on linux
(ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]) the windows
basename is not found. Based on this, I think this may be a fool-
proof cross-platform idiom for generating the basename:

File.basename( filename.gsub("\\","/") )

This works on windows and linux, at least the versions I'm running.

No it doesn't. The problem is that there is no easy way to tell what OS
a pathname came from, and each OS's directory separator is a valid
filename character on the other OS. So you could have a Windows file
called c:\documents\usr/bin/ruby , where usr/bin/ruby is the actual
correct basename. Your method would fail in this case.

The best advice I can give is this: in your Ruby programs, always use /
as your directory separator internally. That will work on Windows: the
Ruby interpreter takes care of converting directory separators as
appropriate for the host OS.
Any other/better ideas? Are there any gotchas with the one I'm using
above?

Best,
-- 
Marnen Laibow-Koser
http://www.marnen.org
(e-mail address removed)
 
S

Siep Korteling

Marnen said:
No it doesn't. The problem is that there is no easy way to tell what OS
a pathname came from, and each OS's directory separator is a valid
filename character on the other OS. So you could have a Windows file
called c:\documents\usr/bin/ruby , where usr/bin/ruby is the actual
correct basename. Your method would fail in this case.(...)

No, a / is not a valid filename character. None of these characters are
allowed : ><:"/\|?*
(http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#file_and_directory_names
)
If you try it anyway you'll get an error. So OP's solution could work.

hth,

Siep
 
M

Marnen Laibow-Koser

Siep said:
No, a / is not a valid filename character. None of these characters are
allowed : ><:"/\|?*
(http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#file_and_directory_names
)
If you try it anyway you'll get an error. So OP's solution could work.

Thanks for the correction. However, \ *is* a valid filename character
on *nix, so the problem still exists.
hth,

Siep

Best,
-- 
Marnen Laibow-Koser
http://www.marnen.org
(e-mail address removed)
 
R

Robert Klemme

2010/2/10 bwv549 said:
On linux, you cannot get the basename of windows-ish files:

# on linux:
File.basename("C:\\path\\to\\file.txt") =A0# -> gives: "C:\\path\\to\
\file.txt"

Heaven knows I would like to avoid all windows path names, but just
after you write something worthwhile you are told it needs to be able
to run on windows, too.

Well, File.basename will work properly on a Windows system. Do you
need to process windows path names on a *nix system? If not, then you
should be fine just using File.basename. There is a reason why the
standard library provides this method...
=A0The point is that it would be nice to know
how to *always* get the basename on any system for any kind of
filename.

That might be difficult without context information. IMHO that
information about the platform is encoded in File.basename's
implementation on your platform of choice.

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

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

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top