なんで FilePath がエクスポートされてないんじゃあああああああああああ! 存在するのに使えないってメチャクチャ腹立つよ!
しょうがないので必要なやつだけ適当に書いといた (かなり用途特化ぎみ)。
module PathUtils
(concatPath, joinPath, basename, dirname, components, ancestors)
where
import Data.List (intersperse)
concatPath :: [String] -> String
concatPath [] = "/"
concatPath [""] = "/"
concatPath cs = join "/" cs
joinPath :: String -> String -> String
joinPath a b
| null a = '/' : b
| last a == '/' = a ++ b
| otherwise = a ++ "/" ++ b
basename :: String -> String
basename "/" = "/"
basename path = last (components path)
ancestors :: String -> [String]
ancestors path = case scanl1 (joinPath) $ components path of
("":xs) -> reverse ("/":xs)
xs -> reverse xs
components :: String -> [String]
components = split '/'
dirname :: String -> String
dirname "/" = "/"
dirname path = case components path of
[] -> ""
[_] -> "."
cs -> concatPath (init cs)
split :: Char -> String -> [String]
split _ [] = []
split sep str = word : split sep cont
where
(word, cont') = break (==sep) str
cont = case cont' of
[] -> ""
(c:cs) -> cs
join :: String -> [String] -> String
join sep = concat . intersperse sep
ところで、この日記の記法だと Haskell のコメントが pre に入れられないことが判明した。 BitChannel と同じく {{{ ... }}} 記法を実装するべきか。
HUnit、記述がめちゃうざったい……。 関数名を三回書かないといけないのもさることながら、 頭の runTestTT なんたらもさることながら、 assert のメッセージ書くのがあまりにめんどい。 あまりにめんどくさいので番号にしてしまった。 やっぱりこういうとこは Ruby のほうが圧倒的に気楽でいいなあ。
import Test.HUnit
import PathUtils
main = runTestTT $ test $
[ "test_ancestors" ~: test_ancestors,
"test_components" ~: test_components,
"test_concatPath" ~: test_concatPath,
"test_joinPath" ~: test_joinPath,
"test_basename" ~: test_basename,
"test_dirname" ~: test_dirname ]
test_ancestors =
do assertEqual "1" ["/"] (ancestors "/")
assertEqual "2" ["/a", "/"] (ancestors "/a")
assertEqual "3" ["/a/b", "/a", "/"] (ancestors "/a/b")
assertEqual "4" ["/a/b", "/a", "/"] (ancestors "/a/b/")
assertEqual "5" ["a/b", "a"] (ancestors "a/b")
assertEqual "6" ["a/b", "a"] (ancestors "a/b/")
assertEqual "7" ["a"] (ancestors "a")
test_components =
do assertEqual "1" [""] (components "/")
assertEqual "2" ["", "a"] (components "/a")
assertEqual "3" ["", "a", "b"] (components "/a/b")
assertEqual "4" ["", "a", "b"] (components "/a/b/")
assertEqual "5" ["a", "b"] (components "a/b")
assertEqual "6" ["a", "b"] (components "a/b/")
test_concatPath =
do assertEqual "1" "/" (concatPath [])
assertEqual "2" "/" (concatPath [""])
assertEqual "3" "/" (concatPath ["/"])
assertEqual "4" "/a" (concatPath ["", "a"])
assertEqual "5" "/a/b" (concatPath ["", "a", "b"])
test_joinPath =
do assertEqual "1" "/a" (joinPath "/" "a")
assertEqual "2" "/a/b" (joinPath "/a" "b")
assertEqual "3" "a/b" (joinPath "a" "b")
test_basename =
do assertEqual "1" "/" (basename "/")
assertEqual "2" "a" (basename "/a")
assertEqual "3" "b" (basename "/a/b")
assertEqual "4" "a" (basename "a")
assertEqual "5" "b" (basename "a/b")
assertEqual "6" "." (basename ".")
assertEqual "7" ".." (basename "..")
test_dirname =
do assertEqual "1" "/" (dirname "/")
assertEqual "2" "/" (dirname "/a")
assertEqual "3" "/a" (dirname "/a/b")
assertEqual "4" "/a/b" (dirname "/a/b/c")
assertEqual "5" "a" (dirname "a/b")
assertEqual "6" "." (dirname "a")
assertEqual "7" "." (dirname ".")
assertEqual "8" "." (dirname "..")
(02:50)
Haskell リファレンスマニュアル検索ツール href の 0.3 をリリースしました。
おかしい……原稿を書いていたところから転じて Wash のチュートリアルをやっていたはずが なぜ href をアップデートしているんだろう。
(02:51)
あー、そうだ、href の変更はこんなとこです。
あとは外に変化の出ないリファクタリングとか。
それとビルドに GHC 6.4 が必要です。 うちのメインは Debian なので GHC 6.2 なんですが、 そっちだと URI の関数が足りなくてエラーになります。 (まあたいしたエラーじゃないのでそこだけ変えりゃ通ります)
……なんて書いているあいだに直したほうが早いなーと思いいたったので対応しておきました。
リリースから 3 時間もたってないよ……。 まあダウンロードした人はまだいないみたいだからいいか。
(04:04)
darcs get http://www.scannedinavian.org/~lemmih/FilePath/
あっ、後 patch です。入れてくれてないので、適当にファイル名つけて darcs apply して下さい。
New patches:
[fixed joinFileName bug for "../" prefixed fileName and directoryName that endend non pathSeparator.
shelarcy@capella.freemail.ne.jp**20050907143754] {
hunk ./System/FilePath.hs 146
- | chr == '.' && isPathSeparator (head fname) = joinFileName (reverse $ dropWhile (not . isPathSeparator) $ reverse dir) (tail fname)
+ | chr == '.' && isPathSeparator (head fname) =
+ joinFileName (reverse $ dropWhile (not . isPathSeparator) $ dropWhile isPathSeparator $ reverse dir) (tail fname)
}
Context:
[change joinFilePath works well for file name that use "../" or "./" prefix. And added basename, dirname, dropFileExt (dropSuffix) functions that inspired by hs-plugins' function.
shelarcy@capella.freemail.ne.jp**20050907123002]
[CPP fixes from CosmicRay.
lemmih@gmail.com**20050721174613]
[Set me (lemmih) as the maintainer.
lemmih@gmail.com**20050721173849]
[Added LICENSE
lemmih@gmail.com**20050721173422]
[Initial record.
lemmih@gmail.com**20050426222116]
Patch bundle hash:
65a356504e79c8a892b310e80f1bcb1c4b0eb59d
む、なるほど、別配布になっているのですか。
ありがとうございます。
GHC に添付してほしいっすね……。