Ruby cross-platform File.basename

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?

bwv549 wrote:

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
[email protected]

On 02/10/2010 10:44 PM, bwv549 wrote:

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

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.

Marnen Laibow-Koser wrote:

bwv549 wrote:

What is the best idiom for generating a cross-platform basename?
(…)
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.(…)

No, a / is not a valid filename character. None of these characters are
allowed : ><:"/|?*
(Naming Files, Paths, and Namespaces - Win32 apps | Microsoft Learn
)
If you try it anyway you’ll get an error. So OP’s solution could work.

hth,

Siep

2010/2/10 bwv549 [email protected]:

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…

The 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

Siep K. wrote:

Marnen Laibow-Koser wrote:

bwv549 wrote:

What is the best idiom for generating a cross-platform basename?
(…)
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.(…)

No, a / is not a valid filename character. None of these characters are
allowed : ><:"/|?*
(Naming Files, Paths, and Namespaces - Win32 apps | Microsoft Learn
)
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
[email protected]