我正在查看 Ransack ruby 的内容。基本上,它调用一个名为 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
将 adapters.rb 的内容复制到 ransack.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
是怎么做到不会导致语法错误的呢?
最佳答案
“复制”在这里用错了。 require
不复制任何内容。它读取给定文件中的源代码并在 Ruby 的全局(“main
”)上下文中执行该代码(除非该文件已经被 require
d;那么它什么都不做并返回 false
)。引用the docs (强调我的):
Any constants or globals within the loaded source file will be available in the calling program’s global namespace.
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
正如您可能已经猜到的那样,该程序的输出将是:
Nobody puts Baby in TheCorner
关于ruby - 在方法中需要一个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39378109/