Ruby-Konstrukte in Rails

Published: Tue 12 February 2013
By ali In Rails.

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.

links