与 method_missing 一起实施 '=' 方法

Implement '=' method together with method_missing

我有一个模块 Settings 如下所示:

module Settings
  extend self

  @_settings = {user: "user1"} #@_seetings would normally be filled with different (dynamic) options
  attr_reader :_settings

  def method_missing(name, *args, &block)
    @_settings.has_key?(name.to_sym) ? @_settings[name.to_sym] :
      raise(NoMethodError, "unknown configuration root #{name}", caller)
  end
end

在我的应用程序中,我可以使用 Settings.user 访问选项 user

现在我想做这样的事情Settings.user = "some_user"

我试过添加这个:

def method_missing=(name, *args, &block)
  #some code to assign the value
end

不幸的是,这不起作用。 (unknown configuration root user= (NoMethodError))。 'right' 的方法是什么?

简短的回答是您不能在 Ruby 中覆盖 =,覆盖这些类型的运算符被认为是危险的。有关详细信息,请参阅 this answer

但是,ruby 很好地处理了这个确切的用例。您有两个选择:

def user= (some_object)
   @_settings = {user: some_object}
end

或者使用户成为 Setting 的属性并使用 attr_accessor

module Settings
  attr_accessor :user
  def new(user)
    @user = user
  end
end

你快到了 attr_reader 它是 attr_accessor 的一半,另一半是 attr_writer。查看其他 SO thread

something= 的方法名称引用一个不存在的方法仍然会被 method_missing 捕获。

您可能想要修改 method_missing 以查看名称是否以“=”结尾并相应地进行操作。

就是说,如果您说 Settings.method_name,那么您是在 Settings 模块 上调用方法,而不是包含该模块的实例.

此外,模块不包含状态;这是它们与 classes 的区别之一。此外,您确定要覆盖包含 class 的 method_missing 方法(或者如果 class' 方法盛行则忽略它吗?)。

您能解释一下为什么为此使用模块吗?也许相反,您想要定义一个 class 并在使用它的 class 中只包含它的一个实例(组合而不是继承)?