Symbole zu Methoden von Objekten

Bei der Programmierung eines Suchalgorithmus in Rails habe ich bei der Methode Enumerable#find einen einfachen Weg gesucht, die optionale Callback-Methode _ifnone_ zu setzen.

Die Intention des Algorithmus ist, falls es kein passendes Element (item) zur gestellten Suchbedingung gibt (item search condition), ein bestimmtes (hier: das letzte) Element zurückzugeben, statt nil.

Dafür bin ich unter Funktionale Programmierung auf den folgenden für mich sehr hilfreichen Code-Snippet gestoßen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Dieser Ausdruck verhindert eine doppelte Definition der Operatoren [] und []=
unless :test.respond_to?(:[])
  #
  # Operatoren [] und []= zur Klasse Symbol hinzufügen, um Singleton-Methoden
  # von Objekten zu lesen und zu setzen. Lies : als "Methode" und [] als "von".
  # Also bedeutet zum Beispiel :m[o] "Methode m von o".
  #
  class Symbol
    # Die durch dieses Symbol benannte Methode von obj zurückgeben. Dies kann
    # eine Singleton-Mehtode von obj (etwa eine Klassenmethode) oder eine Instanz-
    # methode sein, die in obj.class definiert oder von einer Oberklasse übernommen
    # wurde.
    # Beispiele:
    #   creator = :new[Object]  #Klassenmethode Object.new
    #   doubler = :*[2]           # *-Methode der Fixnum 2
    #
    def [](obj)
      obj.method self
    end
 
    # Eine Singleton-Methode für Objekt o definieren und Proc oder Method f
    # als Rumpf verwenden. Dieses Symbol dient als Name der Methode.
    # Beispiele:
    #   :singleton[o] = lamba { puts "Dies ist eine Singleton-Methode von o" }
    #   :class_method[String] = lamba { puts "Dies ist eine Klassenmethode" }
    #
    # Beachten: Sie können so keine Instanzmethoden erzeugen. Siehe Module.[]=
    #
    def []=(o,f)
      # self einer Variablen zuweisen, da der folgende Block einen anderen Kontext
      # haben wird.
      sym = self
      # Dies ist das Objekt, für das wir Singleton-Methoden definieren.
      eigenclass = (class << o; self end)
      # define_method ist privat, so dass wir instance_eval verwenden müssen.
      eigenclass.instance_eval { define_method(sym, f) }
    end
  end
end

Mein Anwendungsfall sieht dann folgendermaßen aus:

34
35
36
 ...
 valuearray.find(:last[valuearray]) {|item| /* item search condition */ }
 ...

Als Fallback für eine nicht erfolgreiche Suche verwende ich :last[valuearray], die last-Methode von dem Array-Objekt valuearray.

Auch wenn dieses Beispiel für den durchschnittlichen Ruby-Entwickler etwas überzogen daherkommt,
soll es die Aufmerksamkeit für diesen Themenkomplex der Programmiersprache anregen und die
Vielseitigkeit und Flexibilität von Ruby zeigen.


Hendrik Lange

Tags: , , ,

  • Share/Bookmark

Hinterlasse eine Antwort