访问模块中的静态变量和方法

时间:2015-09-17 18:37:19

标签: ruby

我在app/presenters/my_namespace/base_presenter.rb

中定义了如下模块
module MyNamespace
  class BasePresenter
  end

  MY_SET = Set.new(['a', 'b', 'c'])

  def self.my_method
    true
  end
end

当我在控制台中运行MyNamespace::MY_SETMyNamespace::my_method时,我得到一个未初始化的常量错误,但我可以执行MyNamespace::BasePresenter.new。我做错了什么?

3 个答案:

答案 0 :(得分:2)

我假设您正在Rails开发模式中尝试这一点。在这种模式下,所有常量(类,模块和常量)都按需加载。

当ruby遇到未定义的常量时,它会抛出一个错误,自动加载器拦截并尝试通过将其名称转换为路径来加载常量。

在您的情况下,自动加载器会尝试查找 MyNamespace::MY_SET app/presenters/my_namespace.rb中的app/presenters/my_namespace/base_presenter.rb(失败)并且不知道您是否在MyNamespace::BasePresenter中实际定义了它。但是,在您加载MyNamespace(顺便说一下,正确的路径)之后,MyNamespace::MY_SETMyNamespace.my_methodMyNamespace已初始化并可用。

您需要做的是

a)正确定义module MyNamespace MY_SET = Set.new(['a', 'b', 'c']) def self.my_method true end end 并将方法和常量移动到其定义:

  

应用程序/主持人/ my_namespace.rb

# note that I don't open module here, 
# but use a constant to enable autoloading of MyNamespace module
class MyNamespace::BasePresenter
end
  

应用程序/主持人/ my_namespace / base_presenter.rb

BasePresenter

b)将所有方法/常量移动到MyNamespace::BasePresenter::MY_SET类。由于它位于正确的路径上,因此常量module MyNamespace class BasePresenter MY_SET = Set.new(['a', 'b', 'c']) def self.my_method true end end end 将起作用。

module MyNamespace
  class BasePresenter
  end
end

奖金部分

之间的区别
class MyNamespace::BasePresenter
end

MyNamespace

是在第一种情况下未定义module MyNamespace时将定义它(MyNamespace打开现有模块或定义新模块),但在第二种情况下,上述机制将尝试在某处加载uninitialized constant error MyNamespace,如果失败,您将获得module MyNamespace

如果您将所有命名空间类定义为第一种情况(在module MyNamespace class BasePresenter end end 内)

,对您来说意味着什么?
  

应用程序/主持人/ my_namespace / base_presenter.rb

MyNamespace

并且module MyNamespace MY_SET = Set.new(['a', 'b', 'c']) end 位于正确的位置,其中包含一些代码

  

应用程序/主持人/ my_namespace.rb

MyNamespace::BasePresenter

如果您的MyNamespace将首先加载,它实际上会定义app/presenters/my_namespace.rb并且您的require将不会被加载(因为自动加载仅加载缺少的常量),您将会必须自己presenter = MyNamespace::BasePresenter.new MyNamespace::MY_SET # boom, uninitialized constant error

class MyNamespace::BasePresenter

这里的解决方案是在1 正确的位置定义模块(自动加载知道如何查找)并使用{{1}}格式在其适当的位置定义命名空间类。

答案 1 :(得分:0)

该代码没有任何问题,这表明问题是加载(或重新加载)问题。如果安装了默认的spring gem,请停止并重新启动控制台和/或spring stop

答案 2 :(得分:0)

可能你没有要求set宝石。类Setset gem中定义。它是标准库的一部分,但不是Ruby核心的一部分。在这种情况下,BasePresenter的创建成功,因为这是在MY_SET = Set.new(['a', 'b', 'c'])之前完成的,这引发了错误。 MY_SETmy_method未定义,因为这些定义出现在违规行上或之后。

你需要这样做:

require "set"