pathmap

Rake の rule では、

rule '.o' => ['%X.c'] do |t|
  ...
end

のように、依存先のルールに'%' を入れると、pathmapを使って変換されるようです。pathmapについての情報があまりなかったのですが、新しい機能なのか、使う人がいないのか。pathmapについてまとめてみます。と言っても、リファレンスマニュアルほとんどそのままですが。

Rakeでは、 String#pathmap が定義されています。pathmapはprintfのように書式指定子を使うことでパスの変形を行えます。

  • %p -- 完全なパス
  • %f -- パスからディレクトリを取り除いたファイル名
  • %n -- 拡張子を取り除いたファイル名
  • %d -- パスのディレクトリ部
  • %x -- 拡張子(ない場合は空文字列)
  • %X -- 拡張子を取り除いたパス
  • %s -- File::ALT_SEPARATOR(あれば。なければFile::SEPARATOR)
  • %% -- '%'そのもの
'a/b/c/d/file.txt'.pathmap('%p') # => a/b/c/d/file.txt
'a/b/c/d/file.txt'.pathmap('%f') # => file.txt
'a/b/c/d/file.txt'.pathmap('%n') # => file
'a/b/c/d/file.txt'.pathmap('%d') # => a/b/c/d
'a/b/c/d/file.txt'.pathmap('%x') # => .txt
'a/b/c/d/file.txt'.pathmap('%X') # => a/b/c/d/file

%s, %% 以外の6つ(p, f, n, d, x, X)は正規表現による置換を行えます。

  • %{old,new}d のように記述
    • %d の old (正規表現)にマッチする部分が new (文字列)に置換される
  • %{old,*}{...}
    • new の部分を'*'一文字にすると、ブロックを渡せる
  • %{old,new;src,bin}d
    • セミコロンで区切って複数のパターンを記述できる

たとえば、

"src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class") # => bin/org/onestepback/proj/A.class

では、 ^src が正規表現コンパイルされて、%X 中でマッチする部分がbinに置換されます。

"src/org/onestepback/proj/A".sub(/^src/, "bin")

のように動くようです。gsubではなくsubです。

ブロックを渡す場合は、

"/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext| ext.downcase } # => /path/to/file.txt
  • %d は %2d のように数値を指定すると、階層数を指定できる。
'a/b/c/d/file.txt'.pathmap("%2d")  # => 'a/b'
'a/b/c/d/file.txt'.pathmap("%-2d") # => 'c/d'

独自フォーマットでなかなか覚えるのが大変そうなので、正規表現で済ましてしまいそうな予感です。