ActiveSupport mette a disposizione numerose estensioni interessanti volte ad ampliare le funzioni delle librerie Class
e Module
. Conoscerle è molto utile poiché queste due librerie sono alla base di tutti gli oggetti Ruby. Una qualsiasi classe Ruby, infatti, è a sua volta un oggetto discendente dalla classe Class
. Gli oggetti di tipo Module
invece sono spesso usati come Mixin
e possono influenzare, direttamente o indirettamente, il comportamento di un qualsiasi oggetti in Ruby.
class Foo end module Bar end f = Foo.new f.class# => Foo Foo.class # => Class Bar.class # => Module
Ruby fornisce tre metodi per generare rapidamente i metodi setter e getter per una variabile d'istanza di una classe. Questi metodi si chiamano attr_reader
, attr_writer
e attr_accessor
. ActiveSupport
mette a disposizione altrettanti metodi per generare metodi accessori per accedere alle variabili d'istanza di una classe e di un modulo.
require '../helper' class MyClass @@foo = 'my foo' @@bar = 'my var' end begin puts MyClass.foo rescue NoMethodError => e puts 'Error: ' + e.message end begin MyClass.foo = 'new value' rescue NoMethodError => e puts 'Error: ' + e.message end class MyClass cattr_accessor :foo cattr_accessor :qui, :quo, :qua cattr_reader:bar end MyClass.bar # => 'bar' MyClass.foo = 'new value' MyClass.foo # => 'new value' module MyModule mattr_accessor :foo end MyModule.foo = ['foo', 'bar', 'bar'] MyModule.foo.inspect # => ["foo", "bar", "bar"]
Inoltre, in Module
è dichiarato anche uno speciale metodo attr_accessor_with_default
. Poiché Class
è una speciale variante di Module
, entrambi dispongono del metodo così come ogni classe in Ruby e le rispettive istanze.
require '../helper' class MyClass attr_accessor_with_default :color, 'red' end instance = MyClass.new instance.color # => 'red' instance.color = 'blue' instance.color # => 'blue'
Come noto, in Ruby il valore di una variabile di classe è automaticamente propagato a tutte le classi che la estendono. Se il valore varia in una qualsiasi delle classi, la modifica è propagata a tutto il ramo della gerarchia. ActiveSupport
introduce la possibilità di definire variabili di classe il cui valore è copiato nelle classi figlie e non condiviso.
require '../helper' class Polygon cattr_accessor :angles self.angles = 0 def self.count_angles puts "#{self.name} has #{self.angles} angles." end end puts Polygon.count_angles # => Polygon has 0 angles. class Triangle < Polygon self.angles = 3 end Polygon.count_angles # => Polygon has 3 angles. Triangle.count_angles # => Triangle has 3 angles. class SafePolygon class_inheritable_accessor :angles self.angles = 0 def self.count_angles puts "#{self.name} has #{self.angles} angles." end end SafePolygon.count_angles # => SafePolygon has 0 angles. class SafeTriangle < SafePolygon self.angles = 3 end SafePolygon.count_angles # => SafePolygon has 0 angles. SafeTriangle.count_angles # => SafeTriangle has 3 angles.
Ci sono numerose altre chicche interessanti nascoste nelle estensioni per Module
e Class
, specialmente legate a caratteristiche e funzioni della programmazione ad oggetti come Delegazione, Inclusione, Introspezione e Metaprogrammazione. È interessante aprire il sorgente e curiosare all'interno delle varie implementazioni.