Capistrano で名前空間内に変数を設定する。
Capistrano の名前空間を使うと、同じ名前のタスクを複数定義できる。だが、setメソッドで設定する変数は、名前空間で装飾されない。setで設定された変数はCapfile内でグローバルになる。
namespace :aaa do set :path, "A" # 名前空間 aaa に入っている path に見える。 desc "task aaa" task :x do puts path end end namespace :bbb do set :path, "B" # 名前空間 bbb に入っている path に見える。 desc "task bbb" task :x do puts path end end
これは以下のようになってしまう。ヒドイ。
$ cap aaa:x bbb:x * executing `aaa:x' B * executing `bbb:x' B
ブロックローカル変数を使うことならできる。ただし、遅延初期化ができない。
namespace :aaa do path = "A" # 普通に変数に設定する。 desc "task aaa" task :x do puts path end end namespace :bbb do path = "B" # 普通に変数に設定する。 desc "task bbb" task :x do puts path end end
pathはnamespaceブロック内でローカルになっている。
$ cap aaa:x bbb:x * executing `aaa:x' A * executing `bbb:x' B $ cap bbb:x aaa:x * executing `bbb:x' B * executing `aaa:x' A
以下のようにして、自分でset,fetchを名前空間で装飾すれば、遅延初期化できる。が、鬱陶しい。
def setv(symbol, namespace = nil, value = nil, &block) s = namespace ? :"#{namespace}_#{symbol}" : symbol if block_given? set(s, &block) else set(s, value) end end def v(symbol, namespace = nil, default = nil, &block) s = namespace ? :"#{namespace}_#{symbol}" : symbol if block_given? return fetch(s, &block) else return fetch(s, default) end end namespace :aaa do setv :path, name, "A" # 現在のnamespaceをnameで参照できる。 desc "task aaa" task :x do puts v(:path, name) end end namespace :bbb do setv :path, name, "B" # 現在のnamespaceをnameで参照できる。 desc "task bbb" task :x do puts v(:path, name) end end
デフォルトのレシピを複数の名前空間で使いたかったが、あきらめた。:aaaと:bbbでCapfileを分けた方がいいと思う。