114

我在 Rails 文档中找不到这个,但似乎'mattr_accessor'是普通 Ruby类中'attr_accessor' (getter & setter) 的模块推论。

例如。在课堂上

class User
  attr_accessor :name

  def set_fullname
    @name = "#{self.first_name} #{self.last_name}"
  end
end

例如。在一个模块中

module Authentication
  mattr_accessor :current_user

  def login
    @current_user = session[:user_id] || nil
  end
end

此辅助方法由ActiveSupport提供。

4

2 回答 2

189

mattr_accessorRails 使用(Module accessor) 和cattr_accessor(以及 _ reader/_writer版本)扩展了 Ruby 。由于 Ruby为实例attr_accessor生成 getter/setter方法,因此在模块级别提供 getter/setter 方法。因此:cattr/mattr_accessor

module Config
  mattr_accessor :hostname
  mattr_accessor :admin_email
end

简称:

module Config
  def self.hostname
    @hostname
  end
  def self.hostname=(hostname)
    @hostname = hostname
  end
  def self.admin_email
    @admin_email
  end
  def self.admin_email=(admin_email)
    @admin_email = admin_email
  end
end

这两个版本都允许您访问模块级变量,如下所示:

>> Config.hostname = "example.com"
>> Config.admin_email = "admin@example.com"
>> Config.hostname # => "example.com"
>> Config.admin_email # => "admin@example.com"
于 2008-10-09T01:49:21.817 回答
40

这是来源cattr_accessor

这是来源mattr_accessor

如您所见,它们几乎相同。

至于为什么会有两个不同的版本?有时你想写cattr_accessor在一个模块中,所以你可以将它用于配置信息,比如 Avdi 提到的。
但是,cattr_accessor在模块中不起作用,因此他们或多或少地将代码复制到模块中。

此外,有时您可能希望在模块中编写类方法,这样每当任何类包含该模块时,它都会获取该类方法以及所有实例方法。mattr_accessor也可以让你这样做。

但是,在第二种情况下,它的行为很奇怪。观察以下代码,特别注意@@mattr_in_module

module MyModule
  mattr_accessor :mattr_in_module
end

class MyClass
  include MyModule
  def self.get_mattr; @@mattr_in_module; end # directly access the class variable
end

MyModule.mattr_in_module = 'foo' # set it on the module
=> "foo"

MyClass.get_mattr # get it out of the class
=> "foo"

class SecondClass
  include MyModule
  def self.get_mattr; @@mattr_in_module; end # again directly access the class variable in a different class
end

SecondClass.get_mattr # get it out of the OTHER class
=> "foo"
于 2008-10-09T19:51:35.923 回答