fileリソースでのcontentに対するlazy指定
個人的には、その前のリソースで既に編集されている可能性があるファイルを編集する際には、fileリソースでcontent lazy { } をよく使う。
(lazy指定が無いと、編集対象が、他リソース未適用のファイル内容となってしまう。)
recipes/default.rb
file '/tmp/test.txt' do
content lazy {
# 何らかの文字列を返す処理
`cat #{path} | sed -e 's/^AAA=.*$/AAA=true/'`
}
end
この例では、ファイルの内容に対して、sedにて編集を行なっている
Ruby実行時とリソース実行時のズレによる問題の例
ここで、このcontent lazy { } の中に値を渡す時には、Ruby実行時とリソース実行時のズレを考慮しないと問題となりうる。
recipes/default.rb
val = 'true'
file '/tmp/test.txt' do
content lazy {
# 何らかの文字列を返す処理
`cat #{path} | sed -e 's/^AAA=.*$/AAA=#{val}/'` # この#{val}の値は?
}
end
...
val = 'false' # 別の処理でvalに'false'を設定して使用
...
適用時には、どの様にリソースを実行するのかを決める為にまずRubyのプログラムとして実行され、その後、その結果に基づいてリソースの反映が行われる。
しかし、lazy指定箇所はリソース反映時に処理される。その為、この例の場合、#{val}にはRuby実行終了時点で設定されている値、つまり'false'が使用されてしまう。
簡単な対応方法
イテレータでブロックに渡される変数を使う
recipes/default.rb
node.default['file_edit']['AAA'] = 'true'
node['file_edit'].each do |key, val|
file '/tmp/test.txt' do
content lazy {
# 何らかの文字列を返す処理
`cat #{path} | sed -e 's/^#{key}=.*$/#{key}=#{val}/'`
}
end
end
...
val = 'false' # 別の処理でvalに'false'を設定して使用
...
これなら、最初のvalは.eachのブロック内でのみ有効なので、#{val}には'true'が設定される。
(ついでにkey部分も汎用化)
蛇足 : 汎用的な対応???
イテレーターへの値渡し以外では、
# NG
begin
...
end
# NG
1.times {
...
}
# OK イテレータへの値渡しそのもの
[val].each do |val|
...
end
# OK やりすぎ感
def file_tmp_test_txt(val)
...
end
file_tmp_test_txt(val)
予想外にも、あまり綺麗な方法は見つかっていない。