Beim lesen von Ruby-Sourcecode stolpert man laufend über Sprachkonstrukte von Ruby die trotz Beschreibung in der Rails API nicht sofort einleuchtend sind. Hier habe ich mal zwei zusammengefasst:
ActiveSupport::Concern
Es gibt offensichtlich Situationen, in denen Erben von ActiveRecord::Base Instanz- und Klassenmethoden gleichzeitig hinzugefügt werden sollen, etwa wenn man eine Bibliothek schreibt, die allen Models bestimmte Eigenschaften geben soll die sie vorher nicht hatten. Dafür gibt es das ActiveSupport::Concern-Modul. Angenommen, ich habe mir eine Webanwendung zur Verwaltung all meiner Literatur geschrieben. Und jetzt will ich auch Magazine verwalten und die Funktionalität nachziehen, die Magazine nach Themen sortieren zu können. Mit ActiveSupport::Concern kann ich folgendes machen:
In meinem neuen Modul wird ActiveSupport::Concern extended, und die neuen Klassenmethoden kommen in ein eigenes Modul. Es ist inzwischen deprecated, ein eigenes Untermodul für Instanzmethoden zu schreiben. Stattdessen werden Methoden die einfach im Body deklariert sind automatisch Instanzmethoden.
module ThemeLibrary
extend ActiveSupport::Concern
module ClassMethods
def find_by_theme(theme_name)
puts theme_name
end
end
def themes
puts "Android, Windows8"
end
end
Dann wird mein neues Modul in ActiveRecord::Base included, so dass mit etwas Ruby-Magie die Instanz- und Klassenmethoden zu meinen Models hinzugefügt werden:
class ActiveRecord::Base
include ThemeLibrary
end
class Magazine < ActiveRecord::Base
end
Magazine.find_by_theme("Android")
m = Magazine.new
m.themes # => "Android, Windows8"
Durch ActiveSupport::Concern sind Dinge möglich wie:
module A
extend ActiveSupport::Concern
# definiere Klassen- und Instanzmethoden
end
module B
extend ActiveSupport::Concern
include A
included do
# Klassenmethoden aus Modul A
end
# definiere Klassen- und Instanzmethoden
end
class C
include B
end
In Klasse C ist jetzt auch Modul A included.
Module die sich selbst extenden
Der Unterschied zwischen include und extend ist der, dass include die Modulmethden im Body eines Moduls zu Instanzmethoden macht. extend macht die Modulmethoden dagegen zu Klassenmethoden. Außerdem kann extend dazu benutzt werden, Singletonmethoden auf einem Objekt zu definieren. Dabei ist zu beachten, dass jedes Objekt extenden kann, auch self:
module Greeter
extend self
def hello
"hi"
end
end
puts Greeter.hello
Dies wird als ein Ersatz für das Singleton-Pattern benutzt, mit dem zusätzlichen Vorteil, dass hello immer noch von einer Klasse eingemixt werden kann.