99 votes

Héritage des méthodes de classe de mixins

Il est connu qu'en Ruby, les méthodes de la classe avoir hérité:

class P
  def self.mm; puts 'abc' end
end
class Q < P; end
Q.mm # works

Cependant, il vient comme une surprise pour moi que ça ne fonctionne pas avec mixin:

module M
  def self.mm; puts 'mixin' end
end
class N; include M end
M.mm # works
N.mm # does not work!

Je sais que #étendre la méthode à suivre:

module X; def mm; puts 'extender' end end
Y = Class.new.extend X
X.mm # works

Mais je suis en train d'écrire un mixin (ou, plutôt, voudrais écrire) contenant à la fois des méthodes d'instance et les méthodes de la classe:

module Common
  def self.class_method; puts "class method here" end
  def instance_method; puts "instance method here" end
end

Maintenant ce que j'aimerais faire, c'est ceci:

class A; include Common
  # custom part for A
end
class B; include Common
  # custom part for B
end

Je tiens A, B hériter à la fois de l'instance et les méthodes de la classe de module Commun. Mais, bien sûr, cela ne fonctionne pas. Alors, n'est-ce pas là un secret de faire de cet héritage de travail à partir d'un seul module?

Il semble peu élégante pour moi de diviser cela en deux modules différents, l'un pour comprendre l'autre pour étendre. Une autre solution possible serait d'utiliser une classe Commune à la place d'un module. Mais c'est juste une solution de contournement. (Si il y a deux ensembles de fonctionnalités communes Common1 et Common2 et nous avons vraiment besoin de ma mixin?) Est-il une profonde raison de la méthode de classe de l'héritage ne fonctionne pas à partir de mixin?

173voto

Sergio Tulentsev Points 82783

Un idiome courant est d'utiliser included hook et injecter des méthodes de classe à partir de là.

 module Foo
  def self.included base
    base.send :include, InstanceMethods
    base.extend ClassMethods
  end

  module InstanceMethods
    def bar1
      'bar1'
    end
  end

  module ClassMethods
    def bar2
      'bar2'
    end
  end
end

class Test
  include Foo
end

Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X