2012-04-13 8 views
3

Ich fing an, in Ruby zu suchen, da ich eine dynamischere Alternative zu Java suche. Ich mag, wie Sie eine Klasse in Ruby, nachdem es die Definition ändern können, zum Beispiel wie folgt aus:Wie verwende ich Ruby Mixins als Patches für Klassen?

class A 
    def print 
    "A" 
    end 
end 

class B < A 
    def print 
    super + "B" 
    end 
end 

class A 
    alias_method :print_orig, :print 
    def print 
    print_orig + "+" 
    end 
end 

puts B.new.print # A+B 

Jetzt versuche ich das gleiche mit Mixins zu tun:

class A 
    def print 
    "A" 
    end 
end 

class B < A 
    def print 
    super + "B" 
    end 
end 

module Plus 
    alias_method :print_orig, :print 
    def print 
    print_orig + "+" 
    end 
end 

A.extend(Plus) # variant 1 
B.extend(Plus) # variant 2 
class A # variant 3 
    include Plus 
end 
class B # variant 4 
    include Plus 
end 
puts B.new.print 

jedoch keine der Varianten produzieren das erwartete Ergebnis. Übrigens, das erwartete Ergebnis ist das Folgende: Ich möchte in der Lage sein, die Klasse A mit einem Mixin zu "patchen", um ihr Verhalten zu modifizieren. Ich möchte Mixins verwenden, da ich mehrere Klassen mit demselben Verhalten "patchen" möchte.

Ist es möglich zu tun, was ich will? Wenn ja, wie?

Antwort

5

Ihr Modulcode funktioniert nicht, da er im falschen Kontext ausgeführt wird. Sie müssen es im Kontext von A ausführen, aber es wird stattdessen im Kontext von Plus ausgewertet. Dies bedeutet, dass Sie self von Plus zu A ändern müssen.

beachten:

class A 
    def print 
    "A" 
    end 
end 

class B < A 
    def print 
    super + "B" 
    end 
end 

module Plus 
    self # => Plus 
    def self.included base 
    self # => Plus 
    base # => A 
    base.class_eval do 
     self # => A 
     alias_method :print_orig, :print 
     def print 
     print_orig + "+" 
     end 
    end 
    end 
end 

A.send :include, Plus 
B.new.print # => "A+B" 
+0

Schönes Beispiel, +1. – Ernest

1

Sie nicht wirklich Mixins auf diese Weise nutzen können. Sie erzeugen einen Konflikt zwischen der Klasse und ihrer Mischung. Mixins implicitly resolve the conflict by linearization. Fazit ist: Im Falle eines Konflikts ist die Methode der Klasse gegenüber dem Mixin bevorzugt. Um das zu beheben, können Sie Sergio' Tulentsev's approach and have the mixin change its base class aggressively verwenden.

Oder Sie können Methoden reflektiv hinzufügen. Betrachten Sie dieses Beispiel, das ich von Mark's blog gestohlen habe.

class Talker 

    [:hello, :good_bye].each do |arg| 
    method_name = ("say_" + arg.to_s).to_sym 
    send :define_method, method_name do 
     puts arg 
    end 
    end 

end 


t = Talker.new 
t.say_hello 
t.say_good_bye