需要方法

时间:2016-09-07 20:00:43

标签: ruby

我正在查看Ransack红宝石宝石的内容。基本上,它调用一个名为require_constants的方法。而且该方法本身需要一个文件:

# ransack.rb
require 'ransack/adapters'
Ransack::Adapters.object_mapper.require_constants

# adapters.rb
module Ransack
  module Adapters

    def self.object_mapper
      @object_mapper ||= instantiate_object_mapper
    end

    def self.instantiate_object_mapper
      if defined?(::ActiveRecord::Base)
        ActiveRecordAdapter.new
      elsif defined?(::Mongoid)
        MongoidAdapter.new
      end
    end

    class ActiveRecordAdapter
      def require_constants
        require 'ransack/adapters/active_record/ransack/constants'
      end
      ...

# constants.rb
module Ransack
  module Constants

我相信第一个require复制了ransack.rb中的adapters.rb的内容。因此,我们可以在没有未定义错误的情况下引用Ransack::Adapters

但是,当我们致电require_constants时,它似乎会将Ransack::Constants的内容复制到require_constants的方法定义中。

我觉得那种混乱。我们正在复制一个方法内的模块。我们在方法中复制模块有什么好处,而不是像其他require那样做?其次,我知道模块不是局部变量,但在我尝试时,我甚至无法在控制台中定义模块:

class A
  def a
    module B end
  end
end
SyntaxError: (irb):14: module definition in method body

那么require做什么不会导致语法错误?

2 个答案:

答案 0 :(得分:4)

"复印"这里说错了。 require不会复制任何内容。它读取给定文件中的源代码,并在Ruby的全局(" main")上下文中执行该代码(除非文件已经require d;然后它什么也不做,返回false)。引用the docs(强调我的):

  

加载的源文件中的任何常量或全局变量将在调用程序的全局命名空间中可用

require在方法调用内部或模块内部或其他任何位置的行为不同于文件顶部的行为。

当您在方法调用中看到require时,原因通常是模块仅在特定场景中需要,并且在该场景发生之前加载它将是浪费的(因为,例如,模块需要在加载期间加载或访问的时间很长,只有在该场景中可用的资源 - 考虑不同的数据库驱动程序或操作系统。这并不意味着模块正在被加载到"方法或周围的代码,因为它不是require所做的。

为了演示,假设我们有一个这样的模块:

# baby_module.rb
module BabyModule
  NAME = "Baby"
end

假设我们运行以下程序:

module TheCorner
  def self.load_baby_module
    require File.expand_path("baby_module", __dir__)
  end
end

TheCorner.load_baby_module

if defined?(TheCorner::BabyModule)
  puts "#{TheCorner::BabyModule::NAME} is in TheCorner"
elsif defined?(BabyModule)
  puts "Nobody puts #{BabyModule::NAME} in TheCorner"
end

正如您可能已经猜到的,该程序的输出将是:

  

没人把宝贝放在TheCorner中

答案 1 :(得分:0)

  

那么@import 'file-that-has-been-removed-but-still-referenced';做什么不会导致语法错误?

简单:它运行文件。