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

问题描述 投票:0回答:1

我正在制作一个具有一些简单功能的实用程序模块 - 我希望该模块能够扩展自身,因此不需要实例化。我和一位同事正在讨论在这些类型的模块中存储数据的各种方法,他提供的一个例子是使用实例变量:

module ExampleModule
  extend self

  @my_instance_variable = "Hello from module"

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

这不是我们决定使用的方法,但我想更好地了解它为何有效/最佳替代方案。那么,有几个问题:

为什么这有效?在没有实例的情况下调用的模块方法如何访问实例变量?您能给我指出任何讨论此行为的 ruby 文档/文章吗?

思考这是否/何时是合适的模式? (我不是粉丝,因为像这样的模块拥有实例变量似乎违反直觉)

这里应该使用类变量吗?我们的 rubocop 将 @@foo 类变量标记为代码味道

ruby-on-rails ruby module instance-variables
1个回答
0
投票

Ruby 中的类和模块都可以有实例变量。那是因为它们分别是类和模块的实例。如果您使用 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
显式定义方法,这样可以更清楚地了解意图,并且可以通过静态分析来获取。

思考这是否/何时是合适的模式? (我不是粉丝,因为像这样的模块拥有实例变量似乎违反直觉)

模块实例变量的一个非常常见的用途配置模式

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
MyGem.configure do |config|
  config.mailer_sender = '[email protected]'
end

如果您是 Ruby 新手,这可能会令人困惑,但请记住,在 Ruby 中,一切都是对象,并且实例变量不是类的已定义属性。它们只是词法作用域到某事物的实例的变量,可以是模块、类或类的实例。

© www.soinside.com 2019 - 2024. All rights reserved.