扩展self的ruby实用模块中的示例变量?

332nm8kg  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(86)

我做了一个实用程序模块,有一些简单的功能-我希望模块扩展自我,所以它不需要被示例化。我和一位同事讨论了在这些类型的模块中存储数据的各种方法,他提供的一个例子是这样的,使用示例变量:

module ExampleModule
  extend self

  @my_instance_variable = "Hello from module"

  def do_thing
    puts "**** #{@my_instance_variable}"
    @my_instance_variable
  end
end

这不是我们决定使用的方法,但我想更好地了解为什么它有效/最佳替代方案。所以,有几个问题:
为什么这样做?没有示例的模块方法如何访问示例变量?你能给我指出任何讨论这种行为的ruby文档/文章吗?
如果/当这是一个适当的模式的想法?(我不是一个粉丝,因为像这样的模块拥有示例变量似乎是违反直觉的)
这里应该使用类变量吗?我们的rubocop flags @@foo class variables as a code smell

ih99xse1

ih99xse11#

Ruby中的类和模块都可以有示例变量。这是因为它们分别是Class和Module的示例。如果使用Module.new方法而不是关键字,这一点会变得更加明显:

module Foo
  @bar = "Hello World"
  def self.bar
    @bar
  end
end

# is pretty much equivilent to
Foo = Module.new do
  @bar = "Hello World"
  def self.bar
    @bar
  end
end

上面的例子和你的代码之间唯一的真实的区别是你使用的是extend self--这使得do_thing可以在模块上调用,而不仅仅是模块扩展的类。
我不是一个超级粉丝,恕我直言,最好只使用def self.method_name显式定义方法,这对意图更清楚,可以通过静态分析来获取。
如果/当这是一个适当的模式的想法?(我不是一个粉丝,因为像这样的模块拥有示例变量似乎是违反直觉的)
模块示例变量的一个非常常见的用法是the configuration pattern

module MyGem
  class << self
    attr_accessor :configuration
  end

  def self.configure
    self.configuration ||= Configuration.new
    yield(configuration)
  end

  class Configuration
    attr_accessor :mailer_sender

    def initialize
      @mailer_sender = '[email protected]'
    end
  end
end

这里,一组gem特定的设置存储在@configuration中。然后在启动应用程序时加载的初始化器文件中设置此参数:

MyGem.configure do |config|
  config.mailer_sender = '[email protected]'
end

这允许应用程序范围的设置,而不依赖于全局。
如果你是Ruby新手,模块/类示例变量可能会让你感到困惑,但请记住,在Ruby中,一切都是对象,示例变量不是类的定义属性。它们只是在词法上作用域为 * 某个对象的示例 * 的变量,该对象可以是模块、类或类的示例。
这里应该使用类变量吗?我们的Rubocop将@@foo类变量标记为代码气味
Ruby中的类变量有很多意想不到的行为,因此通常最好避免。例如,它们在一个类和它的所有子类之间共享。

相关问题