Feature #6587

proposal: adding new methods File.rootname and Pathname#rootname

Added by Usaku NAKAMURA over 2 years ago. Updated over 2 years ago.

[ruby-dev:45735]
Status:Rejected
Priority:Normal
Assignee:Yukihiro Matsumoto

Description

=begin
みんな大好き Unixen ではパスの先頭は '/' で始まるものという暗黙の前提がありますが、Windows ではドライブレターおよび UNC というものがあるのでその前提が成り立たないことは広く知られていると思います。
Ruby はドライブレターや UNC はそれなりに適切に取り扱うようになっていますが、残念ながらパス名を処理する際には依然としてロジックを自前で用意する必要があります。
例えば ruby 配布物の test/ 以下を見ると、独自にドライブレター周りを扱おうとしているコードが散見されますが、それぞれ異なる処理を書いており、UNC や拡張パス名(という名前でいいかどうかわかりませんが、"//?/" あるいは "//./" で始まるもの)まで含めて適切に取り扱えているコードはほぼありません。

そこで、(({dirname}))、(({basename}))、(({extname})) などから類推して、(({rootname})) というメソッドを (({File})) の特異メソッドおよび (({Pathname})) のメソッドとして追加することを提案します。

--- File.rootname(filename) -> String
filename のうち、ルートディレクトリあるいはそれに相当する部分を文字列として返します。
filename が相対パスなどの場合は ""(空文字列)を返します。
# on Unixen
p File.rootname("/foo/bar.txt") #=> "/" (absolute path)
p File.rootname("bar.txt") #=> "" (relative path)

 # on Windows
 p File.rootname("/foo/bar.txt")         #=> "" (relative path)
 p File.rootname("bar.txt")              #=> "" (relative path)
 p File.rootname("C:/foo/bar.txt")       #=> "C:/" (normal absolute path)
 p File.rootname("C:bar.txt")            #=> "" (relative path)
 p File.rootname("//host/share/baz.txt") #=> "//host/share" (UNC absolute path)
 p File.rootname("//?/C:/foo/bar.txt")   #=> "//?/C:/" (extended form absolute path)

--- Pathname#rootname
Pathname.new(File.rootname(self.to_s)) と同じです。
=end

0001-File.rootname.patch Magnifier (3.39 KB) Nobuyoshi Nakada, 06/14/2012 06:04 PM

History

#1 Updated by Motohiro KOSAKI over 2 years ago

心情的には賛成なんですが。。

例えば ruby 配布物の test/ 以下を見ると、独自にドライブレター周りを扱おうとしているコードが散見されますが、
それぞれ異なる処理を書いており、UNC や拡張パス名(という名前でいいかどうかわかりませんが、"//?/" あるいは
"//./" で始まるもの)まで含めて適切に取り扱えているコードはほぼありません。

このパッチによってこのあたりがどこくらい綺麗に書けるようになるのかが、分かると積極的に賛成しやすいなあ、とか
思います。なにを心配してるかというと正規表現で書いた方が短くかけるなら、意識の高い人以外は誰も移行してくれなくて
賽の河原になるんじゃないかという不安がじゃっかんあったりなかったり

#2 Updated by Nobuyoshi Nakada over 2 years ago

  • Description updated (diff)

=begin
: usa (Usaku NAKAMURA) wrote:
そこで、dirname、basename、extname などから類推して、rootname というメソッドを File の特異メソッドおよび Pathname のメソッドとして追加することを提案します。

--- File.rootname(filename) -> String
# on Windows
p File.rootname("/foo/bar.txt") #=> "" (relative path)
p File.rootname("C:bar.txt") #=> "" (relative path)

この2つの例だけ違和感があるのですが、それぞれ "/" と "C:" ではないかという気がしました。

具体的には、現在どういうコードが使われていて、それをどう置き換えることを想定しているのでしょうか。
=end

#3 Updated by Usaku NAKAMURA over 2 years ago

こさきさんとなかださんにまとめて回答。

このパッチによってこのあたりがどこくらい綺麗に書けるようになるのかが、分かると積極的に賛成しやすいなあ、とか

具体的には、現在どういうコードが使われていて、それをどう置き換えることを想定しているのでしょうか。

そうですね、例えばtest/rake/test_rake_directory_task.rbの30~34行目に

drive = Dir.pwd
while drive != File.dirname(drive)
drive = File.dirname(drive)
end
drive = drive[0...-1] if drive[-1] == ?/

というコードがありますが、これは File.rootname(Dir.pwd) の一行で書けます。
また、test/fileutils/test_fileutils.rbの177~180行目に

root = have_drive_letter? ? 'C:/' : '/'

というコードがありますが、root = File.rootname(Dir.pwd) と書けさえすればCドライブが存在するという仮定が不要になります。

思います。なにを心配してるかというと正規表現で書いた方が短くかけるなら、意識の高い人以外は誰も移行してくれなくて 賽の河原になるんじゃないかという不安がじゃっかんあったりなかったり

少なくとも、私には正規表現であろうがなんだろうが短く正確に書ける自信はないです。
上のrakeのtestの例のようなものが最も確実ではないかと思っていますが、こう書くことを啓蒙して回る気はしないですね。します?

この2つの例だけ違和感があるのですが、それぞれ "/" と "C:" ではないかという気がしました。

rootじゃないものが取れてもしゃーないと思うので素直に諦めました。

あと、今見直して気付きましたが、

p File.rootname("//host/share/baz.txt") #=> "//host/share" (UNC absolute path)
は"//host/share/"になるべきでした。

#4 Updated by Motohiro KOSAKI over 2 years ago

具体的には、現在どういうコードが使われていて、それをどう置き換えることを想定しているのでしょうか。

そうですね、例えばtest/rake/test_rake_directory_task.rbの30~34行目に

drive = Dir.pwd
while drive != File.dirname(drive)
drive = File.dirname(drive)
end
drive = drive[0...-1] if drive[-1] == ?/

というコードがありますが、これは File.rootname(Dir.pwd) の一行で書けます。
また、test/fileutils/test_fileutils.rbの177~180行目に

root = have_drive_letter? ? 'C:/' : '/'

というコードがありますが、root = File.rootname(Dir.pwd) と書けさえすればCドライブが存在するという仮定が不要になります。

わたしは、これで説得されました。名前が rootname()がベストなのか自信がないので(他でroot nameという単語を見たことがないという
意味で)、ruby-coreで他にいい名前のアイデアないー?的なメールを出してくれるなら積極的賛成

#5 Updated by Nobuyoshi Nakada over 2 years ago

とりあえずパッチ置いときます。

#6 Updated by Nobuyoshi Nakada over 2 years ago

  • Category set to core
  • Assignee set to Usaku NAKAMURA

古いパッチを貼ってしまったので、最新版はこちらに置きました。
https://github.com/ruby/ruby/pull/130

#7 Updated by Usaku NAKAMURA over 2 years ago

  • Status changed from Open to Assigned
  • Assignee changed from Usaku NAKAMURA to Yukihiro Matsumoto

なぜか私が担当になってましたが、それが通るなら勝手に入れるよ!

というわけでまつもとさんよろしくおねがいします。

#8 Updated by Yukihiro Matsumoto over 2 years ago

WIndowsって /foo/bar,txt は絶対パスじゃないんですね。
となると、rootnameを作ってもUNIXとWindowsでの互換性の向上にはつながりませんよね。
例としてあげられたコードもWindows専用みたいだし。
では、UNIXでは変な値を返すよりもNotImplementedErrorの方がよかったりしません?

後は、名前は本当に適切なのかという点ですね。
個人的にはWindows専用にdriveなんとかって名前にしたほうが良いように思えますが。

#9 Updated by Motohiro KOSAKI over 2 years ago

2012/7/13 matz (Yukihiro Matsumoto) matz@ruby-lang.org:

Issue #6587 has been updated by matz (Yukihiro Matsumoto).

WIndowsって /foo/bar,txt は絶対パスじゃないんですね。

カレントディレクトリが d:/hoge だと d:/foo/bar,txt に展開されてしまいますからね。
(いや、まともとさんも絶対知ってるはずだと思うんだけど・・・)

となると、rootnameを作ってもUNIXとWindowsでの互換性の向上にはつながりませんよね。
例としてあげられたコードもWindows専用みたいだし。
では、UNIXでは変な値を返すよりもNotImplementedErrorの方がよかったりしません?

後は、名前は本当に適切なのかという点ですね。
個人的にはWindows専用にdriveなんとかって名前にしたほうが良いように思えますが。

Windows専用にしたほうがいいかどうかは門外漢なのでコメントしませんが、
UNC absolute path とかも統一的に扱えているのが元プロポーサルの利点だと思っているので
driveなんとかという名前は一般化がワンランク落ちてしまった印象を受けます

#10 Updated by Motohiro KOSAKI over 2 years ago

WIndowsって /foo/bar,txt は絶対パスじゃないんですね。

カレントディレクトリが d:/hoge だと d:/foo/bar,txt に展開されてしまいますからね。
(いや、まともとさんも絶対知ってるはずだと思うんだけど・・・)

うーん、うそを言った気がする。

http://msdn.microsoft.com/ja-jp/library/system.io.path.getpathroot(v=vs.71)

あたりを見るとMicrosoftの用語ではこれは「現在のドライブに対する絶対パス」というらしい。(なんじゃそりゃ)

たぶん、rootが複数あるんだから絶対パスはパスのユニーク性を保証しなくてあたりまえという哲学なんでしょう。推測ですが。で、なんとなく用語をwin
portではMSと合わせたほうがいいような気がしてちょっとぐぐってたんですが

http://hp.vector.co.jp/authors/VA022575/c/path.html

とかを見るとMSの用語もデタラメとか書いてあって悩みは増すばかり・・・・

#11 Updated by Usaku NAKAMURA over 2 years ago

こんにちは、なかむら(う)です。

In message " [ruby-trunk - Feature #6587] proposal: adding new methods File.rootname and Pathname#rootname"
on Jul.14,2012 00:16:18, matz@ruby-lang.org wrote:

となると、rootnameを作ってもUNIXとWindowsでの互換性の向上にはつながりませんよね。
例としてあげられたコードもWindows専用みたいだし。
では、UNIXでは変な値を返すよりもNotImplementedErrorの方がよかったりしません?

"/" が変な値かどうかよくわかりませんが(変なの?)、確かに互換性
の向上に繋がるようなユースケースは思いつきませんねえ。
UNIX側にあって困ることがあるのかどうかはよくわかりません。

後は、名前は本当に適切なのかという点ですね。
個人的にはWindows専用にdriveなんとかって名前にしたほうが良いように思えますが。

これは小崎さんが言っておられるようにドライブのみを扱うわけじ
ゃないのでdriveなんとかはあまりよくないと思っています。
UNIXで絶対に不要なら、windows_rootnameとかにしますか?

それでは。
--
U.Nakamura usa@garbagecollect.jp

#12 Updated by Yukihiro Matsumoto over 2 years ago

  • Status changed from Assigned to Rejected

#13 Updated by Anonymous over 2 years ago

まつもと ゆきひろです

In message "Re: Re: [ruby-trunk - Feature #6587] proposal: adding new methods File.rootname and Pathname#rootname"
on Tue, 17 Jul 2012 10:37:18 +0900, "U.Nakamura" usa@garbagecollect.jp writes:

|> 例としてあげられたコードもWindows専用みたいだし。
|> では、UNIXでは変な値を返すよりもNotImplementedErrorの方がよかったりしません?
|
|"/" が変な値かどうかよくわかりませんが(変なの?)、確かに互換性
|の向上に繋がるようなユースケースは思いつきませんねえ。
|UNIX側にあって困ることがあるのかどうかはよくわかりません。

困ることはないでしょうけど、意味不明ですよね。

|これは小崎さんが言っておられるようにドライブのみを扱うわけじ
|ゃないのでdriveなんとかはあまりよくないと思っています。
|UNIXで絶対に不要なら、windows_rootnameとかにしますか?

UNCなんちゃらを扱うUNIXでも意味のある拡張というのはありえる
のかもしれません。知らんけど。

いずれにしても現在の提案は、名前・挙動ともに完全には賛成でき
ないので、一度リジェクトします。もうしちゃったけど。

Windows専用にするか、汎用のユースケースをあげるか、どちらでも
いいけど、必要なら再提案してください。

                             まつもと ゆきひろ /:|)

Also available in: Atom PDF