ruby - 在没有 `autoload` 的情况下在 Ruby 中自动加载类

标签 ruby lazy-loading autoload

我爱the autoload functionality of Ruby ;然而,它是 going away in future versions of Ruby因为它从来都不是线程安全的。

所以现在我想假装它已经消失并在没有它的情况下编写我的代码,方法是自己实现延迟加载机制。我想以最简单的方式实现它(我现在不关心线程安全)。 Ruby 应该允许我们这样做。

让我们从扩充一个类开始const_missing:

class Dummy
  def self.const_missing(const)
    puts "const_missing(#{const.inspect})"
    super(const)
  end
end

当我们尝试引用“Dummy”下缺少的常量时,Ruby 将调用此特殊方法,例如,如果我们尝试引用“Dummy::Hello”,它将调用 const_missing符号:你好。这正是我们所需要的,所以让我们更进一步:

class Dummy
  def self.const_missing(const)
    if :OAuth == const
      require 'dummy/oauth'
      const_get(const)      # warning: possible endless loop!
    else
      super(const)
    end
  end
end

现在如果我们引用“Dummy::OAuth”,它将需要“dummy/oauth.rb”文件,该文件应该定义“Dummy::OAuth”常量。当我们调用 const_get 时可能会出现无限循环(因为它可以在内部调用 const_missing),但防止这种情况超出了这个问题的范围。

最大的问题是,如果在顶级命名空间中存在名为“OAuth”的模块,整个解决方案就会崩溃。引用“Dummy::OAuth”将跳过其 const_missing 并从顶层返回“OAuth”。大多数 Ruby 实现也会对此发出警告:

warning: toplevel constant OAuth referenced by Dummy::OAuth

This was reported as a problem way back in 2003但我找不到证据表明 Ruby 核心团队曾经关注过这个问题。今天,大多数流行的 Ruby 实现都具有相同的行为。

问题是 const_missing 被悄悄跳过,取而代之的是顶级命名空间中的常量。如果使用 Ruby 的 autoload 功能声明“Dummy::OAuth”,则不会发生这种情况。有什么想法可以解决这个问题吗?

最佳答案

这是前段时间在 Rails 票证中提出的,当我调查它时,似乎没有办法绕过它。问题在于 Ruby 会在调用 const_missing 之前搜索祖先,并且由于所有类都以 Object 作为祖先,因此总会找到任何顶级常量。如果您可以将自己限制为仅使用模块进行命名空间,那么它将起作用,因为它们没有 Object 作为祖先,例如:

>> class A; end
>> class B; end
>> B::A
(irb):3: warning: toplevel constant A referenced by B::A

>> B.ancestors
=> [B, Object, Kernel, BasicObject]

>> module C; end
>> module D; end
>> D::C
NameError: uninitialized constant D::C

>> D.ancestors
=> [D]

关于ruby - 在没有 `autoload` 的情况下在 Ruby 中自动加载类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9053720/

相关文章:

ruby-on-rails - 如何在 Rails 4 的 Controller 中的方法之间共享变量?

php - 具有许多路径的 PSR-0 SplClassLoader

php - 具有大小写类名的自动装带器

javascript - 延迟加载图像 - noscript 后备代码

java - Spring和Hibernate,懒启动问题

angular - 为什么 forRoot() 从 Material2 中删除?对于延迟加载的功能模块我能做些什么?

php - 位于 ./foo/bar/utility/baz.php 的 Foo\Bar\Baz 类不符合 psr-4 自动加载标准。跳绳

ruby - MinitTest Spec 对第二个参数的混淆

ruby-on-rails - 在 postgresql 应用程序的 rails 中运行迁移后的序列通知

ruby - 在 ruby 中四舍五入到 0.5 或 1