在模块中创建全局Rails方法?

时间:2015-09-03 00:56:00

标签: ruby-on-rails ruby

我需要创建一个可以在任何情况下使用的方法(MVC,测试等)。而不是将其填充到environments.rb id中,而不是创建模块并将其包含为gem。为了让Rails识别这个模块中的方法,我需要在gem中扩展哪个类?

更新

我正在寻找一种解决方案,允许我在没有模块前缀的情况下调用我的方法。

1 个答案:

答案 0 :(得分:8)

TLDR

你需要"延伸" Kernel模块,将您的方法包含在include中。

全球方法

通常是"全球" Ruby中的方法意味着在KernelObject中创建方法。然后,该方法可用于所有(大多数)类,因为它们继承自Object(包括Kernel)。您的方法可以在大多数地方没有前缀的情况下调用,因为任何给定上下文中的隐式self都是从Object继承的对象,因此包含您定义的方法。

定义此类方法的一种方法是将其定义放在任何类或模块之外的文件中:

def my_method
  # do fancy stuff
end

当然,您必须确保文件在某处加载(即需要)。

模块中的全局方法

如果您希望在一个模块中组织您的方法(这是一个好主意),您需要将该模块包含在Kernel中,如下所示:

module MySpecialMethods
  def my_method
    # do fancy stuff
  end
end

module Kernel
  private
  include MySpecialMethods # This is where the method gets added to Kernel
end

在Rails中,我会将MySpecialMethods模块放在lib/中,将Kernel部分添加到初始化文件config/initializers/extend_kernel.rb中。你还需要帮助Rails"找到"将lib/添加到a​​pplication.rb

config.autoload_paths += %W(#{config.root}/lib)中的模块

考虑避免使用全局方法

在极少数情况下以这种方式扩展Kernel是一个好主意,这一点毫无价值。可能(可能?)对于您的情况,将您的方法放在模块中并使用类似MyModule.my_method的模块名称显式调用它们更好

module MyModule
  def self.my_method
    # do fancy stuff here
  end
end

您可以在许多位置放置此代码。在Rails中,我建议将其放在上面的lib/文件夹中,然后确保Rails可以通过将config.autoload_paths += %W(#{config.root}/lib)添加到a​​pplication.rb来找到它。

来自Gem

创建gem超出了这个问题的范围,但假设您创建了一个gem,只要您在Gemfile中指定gem,通常只需在Rails应用程序中使用该gem中的模块。这是因为Rails应用程序默认调用Bundler.require。只要gem遵循正确的命名约定,主要的gem文件就会自动生成,而主gem文件需要任何其他必要的文件。

如果您想从gem扩展Kernel,只需将Kernel扩展代码(从上面)放入需要(直接或间接)需要gem的文件中。

注释

  1. Rails初始化程序仅在您启动Rails服务器时运行一次,因此对它们的更改不会像开发中的许多其他Rails一样自动加载。

  2. 如果您正在调整Rails' autoload_paths,您可能还想调整eager_load_paths(请参阅this blog post

  3. Ruby中有对象 继承自Object(例如BasicObject ),技术上这些"全球" 无处不在的方法。这不太可能给你带来麻烦。

  4. 在Rails应用中使用Bundler.require可能会引起争议(有关详情,请参阅this blog post