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
endpathは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を分けた方がいいと思う。