6

Let's say we have two resources:

template 'template1' do
  owner 'root'
  group 'root'
end

template 'template2' do
  owner 'root'
  group 'root'
end

I'd like to reuse code inside resources. However, if I define a proc in the recipe, you get a NoMethodError for owner, group etc. Why does it happen? Lexical scope isn't different, is it? As a result I have to use self.instance_eval &common_cfg.

common_cfg = Proc.new {
  owner 'root'
  group 'root'
}

template 'template1' do
  common_cfg.call
end

template 'template2' do
  common_cfg.call
end
m33lky
  • 7,055
  • 9
  • 41
  • 48
  • Does the error occur if you make it a global (`$common_cfg`)? – Dave Newton May 13 '12 at 20:29
  • The proc variable is evaluated fine, because the NoMethodError occurs in the context of the proc (owner, group etc.) – m33lky May 13 '12 at 20:31
  • Oh; gotcha--will delete comment. – Dave Newton May 13 '12 at 20:43
  • Your proc remembers the value of self at the point where the proc was defined, ie the top level object. Seems likely that chef uses instance_eval to execute the block so self inside the block isn't the same as self in your proc – Frederick Cheung May 13 '12 at 20:58
  • That's probably exactly what's happening. I'll take this as an answer if no one else has something to share. I'm still thinking about why instance_eval is important in Ruby: http://rubylearning.com/blog/2010/11/30/how-do-i-build-dsls-with-yield-and-instance_eval/ – m33lky May 13 '12 at 21:07

1 Answers1

2

because of how chef is implemented (with lots of reflection) you need to put it in a library or ruby block resource to protect it. I think think a ruby block resource will work because it will be outside of scope.

http://wiki.opscode.com/display/chef/Libraries

usually for this reason the idiom is

["file_one","file_two"].each do |file|
  template file do
    owner "root"
    group "root"
  end
end
EnabrenTane
  • 7,428
  • 2
  • 26
  • 44