Qu’est-ce que mattr_accessor dans un module Rails?

Je ne pouvais pas vraiment trouver cela dans la documentation de Rails, mais il semble que «mattr_accessor» soit le corollaire du module pour «attr_accessor» (getter & setter) dans une classe Ruby normale.

Par exemple. dans une classe

class User attr_accessor :name def set_fullname @name = "#{self.first_name} #{self.last_name}" end end 

Par exemple. dans un module

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

Cette méthode d’assistance est fournie par ActiveSupport .

Rails étend Ruby à la fois avec mattr_accessor (accesseur de module) et cattr_accessor (ainsi que les versions _ reader / _writer ). Comme attr_accessor de Ruby génère des méthodes de cattr/mattr_accessor pour les instances , cattr/mattr_accessor fournit des méthodes de cattr/mattr_accessor au niveau de la classe ou du module . Ainsi:

 module Config mattr_accessor :hostname mattr_accessor :admin_email end 

est l’abréviation de:

 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 

Les deux versions vous permettent d’accéder aux variables de niveau module comme suit:

 >> Config.hostname = "example.com" >> Config.admin_email = "admin@example.com" >> Config.hostname # => "example.com" >> Config.admin_email # => "admin@example.com" 

Voici la source de cattr_accessor

Et

Voici la source de mattr_accessor

Comme vous pouvez le voir, ils sont pratiquement identiques.

Pourquoi y a-t-il deux versions différentes? Parfois, vous voulez écrire cattr_accessor dans un module, vous pouvez donc l’utiliser pour des informations de configuration comme celles d’Avdi .
Cependant, cattr_accessor ne fonctionne pas dans un module, ils ont donc plus ou moins copié le code pour travailler également pour les modules.

De plus, il peut arriver que vous souhaitiez écrire une méthode de classe dans un module, de sorte que chaque fois qu’une classe inclut le module, elle obtienne cette méthode de classe ainsi que toutes les méthodes d’instance. mattr_accessor vous permet également de le faire.

Cependant, dans le deuxième scénario, son comportement est assez étrange. Observez le code suivant, notez en particulier les bits @@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"