17

我正在开发一个食谱来部署一个简单的 ROR 应用程序。我编写了一个 app_helper.rb 并将其放入我的食谱的库目录中,这是内容:

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

在 recipes/default.rb 中,我将上述模块混合到 Chef::Recipe 类中

class Chef::Recipe
  include AppHelper
end

如您所知,可以从配方的任何位置调用 find_gem 函数。

当我尝试像这样在我的 ruby​​_block 中使用 find_gem 函数时:

ruby_block "find gem" do
   block do
    gem_bin = Chef::Recipe::find_gem
    # or gem_bin = find_gem
  end
end

我得到了 NoMethodError:未定义的方法“find_gem”。

也尝试将模块混合到 Chef::Resource::RubyBlock 中,它也不起作用。

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

有没有办法从 ruby​​_block 调用模块中的函数?或者是否有一个厨师变量来定位库中的文件,这样我就可以在 ruby​​_block.

谢谢!

4

1 回答 1

20

根据加载顺序,您可能会将模块包含到匿名 Ruby 类中,而不是您想的那样。

如果您想在配方中使用您的方法,请在配方的顶部执行此操作:

include AppHelper

您也可以:send在库的末尾使用:

Chef::Recipe.send(:include, AppHelper)

这是不同的,因为如果未定义它将引发异常Chef::Recipe(而如果它不存在,则您正在创建一个新类)。

这就是你需要做的所有事情,除非你想使用助手not_ifonly_if守卫。然后您需要在资源中包含帮助程序:

Chef::Resource.send(:include, AppHelper)

好吧,既然我解释了所有这些,它实际上对你没有帮助。Ruby 块提供程序只是调用块- 它不会实例化它。因此,在资源中包含帮助器不会做任何事情

因此,您需要在这种情况下使用单例对象(这是我能可靠想到的唯一解决方案)。您定义方法的方式,您可以直接从全局命名空间调用它:

AppHelper.find_gem('...')

所以:

ruby_block "find gem" do
  block do
    gem_bin = AppHelper.find_gem('...')
  end
end
于 2013-12-30T16:43:45.123 回答