2016-11-23 2 views
1

ich das vorhandene Modul A aus einer Bibliothek ändern möchten:Überschreiben Klassenmethode von einem anderen Modul

module A 
    class << self 
    def foo 
     bar('Baz') 
    end 

    private 

    def bar(val) 
     val.upcase 
    end 
    end 
end 

A.foo 
=> "BAZ" 

module B 
    extend A 

    def self.bar(val) 
    val.downcase 
    end 
end 

B.foo   # hoping for 'baz', but instead: 
NoMethodError: undefined method `foo' for B:Module 

Gibt es eine Möglichkeit Verfahren zur Wiederverwendung .foo von A und einzige Methode .bar ändern?

+0

Wenn Sie neugierig sind, ist dies das Modul, das ich wiederverwenden möchte: https://github.com/ruby-grape/grape/blob/v0.18.0/lib/grape/error_formatter/json.rb –

+0

Macht ein Duplikat sein von: http://stackoverflow.com/questions/4662722/extending-a-ruby-module-in-an-other-module- including-the-module-methods? – Deradon

+0

Sehr interessante Frage! –

Antwort

2

Angenommen, Sie haben A wie oben erklärt, würde der folgende Code tun:

▶ B = A.clone 
#⇒ B 
▶ (class << B; self; end).send :define_method, :bar do |val| 
    val.downcase 
end 
▶ A.foo 
#⇒ "BAZ" 
▶ B.foo 
#⇒ "baz" 

Es gibt wohl weniger komplizierte Weise sein sollte, aber ich kann es noch nicht herausfinden.

4

extend A nicht funktioniert, weil foo und bar keine Instanzmethoden A sind, aber von A ‚s Singletonklasse. Um diese Methoden wieder verwenden, müssen Sie entweder eine Kopie A erstellen, wie mudasobwa beschrieben, oder Sie können eine Verfeinerung der A ‚s Singletonklasse wie folgt aus:

module B 
    extend(refine(A.singleton_class) do 
    def bar(val) 
     val.downcase 
    end 
    end) 
end 

B.foo # => "baz" 

Sie können nicht extend A.singleton_class als extend doesn verwenden‘ verwenden t akzeptiere eine Klasse als Argument. refine gibt ein Modul zurück, das genau das ist, was benötigt wird.

+0

Ich habe nie über [Modul # verfeinern] (http://ruby-doc.org/core-2.3.0/Module.html#method-i-refine) für diesen Zweck verwendet. Gute Antwort! –

+0

Das ist großartig, upvoted. Erste Anwendung von 'verfeinern' Ich sah, dass es wirklich sinnvoll ist. – mudasobwa

+0

Beachten Sie, dass Refinements Teil von Ruby sind, jedoch nicht in allen Ruby-Implementierungen implementiert sind. Vor allem die Rubinius-Entwickler sind philosophisch gegen die Idee der Verfeinerungen und werden sie daher niemals umsetzen. (Man könnte argumentieren, ob eine Implementierung, die eine Funktion von Ruby vorsätzlich ignoriert, überhaupt als "Ruby-Implementierung" bezeichnet werden kann.) –

Verwandte Themen