ふもさんの「お題:フルパスから相対パスを求める」をF# でやってみた
お題:フルパスから相対パスを求める - No Programming, No Life
なんか盛り上がっているらしいので私も便乗してみた。
追記
2011/9/1追記:コメントでご指摘を受けた部分を修正+実装変更
2011/9/1追記:タプル→カリー化に変更+テストコードもあわせて修正。MaybeBuilder.Bindのリファクタリング。
コード
(* RelativePath.fs *) module RelativePath open System.Text.RegularExpressions type MaybeBuilder() = member this.Bind(x,f) = Option.bind f x member this.Return(x) = Some x let maybe = new MaybeBuilder() let relativizePath fromA toB = let trySplit (path:string) = match Regex.Match(path,"^[^/]|\.$|^$|[\\?*:|\"<>]|//").Success with | true -> None | false -> Some (path.Split([|'/'|]) |> Array.toList) let addPath = function | "" -> "./" | path -> path let rec calc f t path = match f, t with | [x], _ -> t |> List.reduce (fun a b -> a + "/" + b) |> (+) (addPath path) | x::xs, y::ys when x = y -> calc xs ys path | _, _ -> calc (f |> List.tail) t (path+"../") maybe { let! f = fromA |> trySplit let! t = toB |> trySplit return calc f t "" }
(* RelativePathScenario.fs *) module RelativePathScenario open NaturalSpec open RelativePath [<Example("/aaa/bbb/from.txt","/aaa/bbb/to.txt","./to.txt")>] [<Example("/aaa/bbb/from.txt","/aaa/to.txt","../to.txt")>] [<Example("/aaa/bbb/from.txt","/aaa/bbb/ccc/to.txt","./ccc/to.txt")>] [<Example("/aaa/bbb/from.txt","/aaa/ccc/ddd/to.txt","../ccc/ddd/to.txt")>] [<Example("/aaa/bbb/from.txt","/ddd/ccc/to.txt","../../ddd/ccc/to.txt")>] [<Example("/aaa/bbb/","/aaa/ddd/to","../ddd/to")>] [<Example("/aaa/bbb/from","/aaa/ccc/","../ccc/")>] [<Example("/aaa/bbb/","/aaa/ccc/","../ccc/")>] [<Example("/aaa/bbb/ccc.txt","/aaa/bbb/ccc.txt","./ccc.txt")>] let ``二つのフルパスを受け取り一つ目のパスから二つ目のパスへの相対パスを返す`` f t result = Given (f, t) ||> When relativizePath |> It should equal (Some result) |> Verify [<Example("","/bbb/to.txt")>] [<Example("/aaa/g*","/bbb/to.txt")>] [<Example("aaa/bbb/from.txt","./bbb/to.txt")>] [<Example("//aaa////bbb/from.txt","/////aaa//////bbb///////to.txt")>] let ``どちらかのパスが無効値ならNone`` f t = Given (f, t) ||> When relativizePath |> It should equal None |> Verify
ついでにNaturalSpecを使ってTDDで実装してみたものの、例5〜例8まではテスト追加するだけよかっただけど。
正規表現を含め色々とあってる自信がないわけだが…テスト動いてるしいいよね?
あと別の人が書けばもっときれいにかけるのではないかなとも思っている。
Gistにはそのうちあげます*1
*1:文字化け対策してなかった