I'm developing a cookbook to deploy a simple ROR application. I write an app_helper.rb and put it into the libraries directory of my cookbook, here is the content:
module AppHelper
def self.find_gem
if File.exists?("/usr/local/rvm/bin/rvm")
return `/usr/local/rvm/bin/rvm default exec which gem`.chomp
else
return "/usr/bin/gem"
end
end
end
In the recipes/default.rb, I mix in the above module into Chef::Recipe class
class Chef::Recipe
include AppHelper
end
As you know, the find_gem function can be called from anywhere of the recipe.
when I'm trying to use the find_gem function in my ruby_block like this:
ruby_block "find gem" do
block do
gem_bin = Chef::Recipe::find_gem
# or gem_bin = find_gem
end
end
I got a NoMethodError: undefined method 'find_gem'.
Also try to mix in the module into Chef::Resource::RubyBlock, it doesn't work neither.
class Chef::Resource::RubyBlock
include AppHelper
end
ruby_block "find gem" do
block do
gem_bin = Chef::Resource::RubyBlock::find_gem
# or gem_bin = find_gem
end
end
Is there any way to call the function in the module from the ruby_block? Or Is there an variable of chef to location the files in the libraries, so that I can be able to require the module in the ruby_block.
Thanks!
Depending on load order, you might be including your module into an anonymous Ruby class instead of what you think.
If you want to use your method in a recipe, do this at the top of your recipe:
include AppHelper
You could alternatively use :send
at the end of your library:
Chef::Recipe.send(:include, AppHelper)
This is different because it will raise an exception if Chef::Recipe
is not defined (whereas you are creating a new class if it doesn't exist).
That's all you should need to do unless you want to use the helper in not_if
and only_if
guards. Then you need to include the helper in the resource:
Chef::Resource.send(:include, AppHelper)
Okay, now that I explained all of that, it won't actually help you. The Ruby Block provider simply calls the block - it doesn't instance eval it. So including the helper in the resource doesn't do anything.
So, you'll need to use a singleton object in this instance (it's the only solution I can reliably think of). The way you've defined your method, you can call it directly from the global namespace:
AppHelper.find_gem('...')
So:
ruby_block "find gem" do
block do
gem_bin = AppHelper.find_gem('...')
end
end