Question

Je commence juste à comprendre la métaprogrammation de Ruby. Les mixin / modules parviennent toujours à m'embrouiller.

  • include : mélange dans les méthodes de module spécifiées en tant que méthodes d'instance dans la classe cible
  • étendre : mélange les méthodes de module spécifiées en tant que méthodes de classe dans la classe cible

Alors, est-ce que la principale différence est-ce juste ou est-ce qu'un plus grand dragon se cache? par exemple

module ReusableModule
  def module_method
    puts "Module Method: Hi there!"
  end
end

class ClassThatIncludes
  include ReusableModule
end
class ClassThatExtends
  extend ReusableModule
end

puts "Include"
ClassThatIncludes.new.module_method       # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method            # "Module Method: Hi there!"
Était-ce utile?

La solution

Ce que vous avez dit est correct. Cependant, il y a plus que cela.

Si vous avez une classe Klazz et un module Mod , y compris Mod dans Klazz donne des instances de Klazz accès aux méthodes de Mod . Ou vous pouvez étendre Klazz avec Mod en donnant à la classe Klazz l'accès à Mod ' s méthodes. Mais vous pouvez aussi étendre un objet arbitraire avec o.extend Mod . Dans ce cas, l'objet individuel obtient les méthodes de Mod même si tous les autres objets ayant la même classe que o ne le font pas.

Autres conseils

extend : ajoute les méthodes et les constantes du module spécifié à la métaclasse de la cible (c'est-à-dire la classe singleton).   par exemple.

  • si vous appelez Klazz.extend (Mod) , maintenant Klazz utilise les méthodes de Mod (méthodes de classe)
  • si vous appelez obj.extend (Mod) , obj a maintenant les méthodes de Mod (comme méthodes d'instance), mais aucune autre instance de obj.class n'a ces méthodes ajouté.
  • extend est une méthode publique

include : par défaut, il mélange les méthodes du module spécifié en tant que méthodes d'instance dans le module / la classe cible.   par exemple

  • si vous appelez class Klazz; inclure Mod; fin; , toutes les instances de Klazz ont maintenant accès aux méthodes de Mod (comme méthodes d’instance)
  • include est une méthode privée, car elle est destinée à être appelée depuis le conteneur / la classe de conteneur.

Cependant, , les modules remplacent très souvent le comportement de include en masquant la méthode avec . Ceci est très important dans le code Rails hérité. plus de détails de Yehuda Katz .

Plus de détails sur include , avec son comportement par défaut, en supposant que vous ayez exécuté le code suivant

class Klazz
  include Mod
end
  • Si Mod est déjà inclus dans Klazz ou l'un de ses ancêtres, l'instruction include n'a aucun effet
  • Cela inclut également les constantes de Mod dans Klazz, tant qu'elles ne se contredisent pas
  • Cela donne à Klazz l’accès aux variables de module de Mod, par exemple. @@ foo ou @@ bar
  • déclenche ArgumentError s'il existe des inclusions cycliques
  • Associe le module en tant qu’ancêtre immédiat de l’appelant (c’est-à-dire qu’il ajoute Mod à Klazz.ancestors, mais Mod n’est pas ajouté à la chaîne de Klazz.superclass.superclass.superclass. Donc, appeler super dans Klazz # foo va vérifier Mod # foo avant de vérifier la méthode foo de la super classe de Klazz (voir la RubySpec pour plus de détails).

Bien entendu, la la documentation Ruby Core est toujours le meilleur endroit pour aller pour ces choses. Le le projet RubySpec était également une ressource fantastique, car il documentait les fonctionnalités avec précision.

C'est correct.

Dans les coulisses, include est en fait un alias pour append_features , qui (d'après la documentation):

  

L'implémentation par défaut de Ruby est de   ajouter les constantes, les méthodes et le module   les variables de ce module à aModule si   ce module n'a pas encore été ajouté   à un module ou à l'un de ses ancêtres.

Toutes les autres réponses sont bonnes, y compris le conseil pour explorer RubySpecs:

https://github.com/rubyspec/rubyspec/ blob / master / core / module / include_spec.rb

https://github.com/rubyspec/rubyspec/ blob / master / core / module / extend_object_spec.rb

Comme pour les cas d'utilisation:

Si vous incluez le module ReusableModule dans la classe ClassThatIncludes, les méthodes, les constantes, les classes, les sous-modules et les autres déclarations sont référencés.

Si vous étendez la classe ClassThatExtends avec le module ReusableModule, les méthodes et les constantes sont alors copiées . Évidemment, si vous ne faites pas attention, vous pouvez gaspiller beaucoup de mémoire en dupliquant de manière dynamique les définitions.

Si vous utilisez ActiveSupport :: Concern, la fonctionnalité .included () vous permet de réécrire directement la classe incluse. module ClassMethods à l'intérieur d'une préoccupation est étendu (copié) dans la classe incluse.

Je voudrais aussi expliquer le mécanisme tel qu'il fonctionne. Si je ne me trompe pas, corrigez.

Lorsque nous utilisons include , nous ajoutons un lien de notre classe à un module contenant des méthodes.

class A
include MyMOd
end

a = A.new
a.some_method

Les objets n'ont pas de méthodes, mais seulement des classes et des modules. Ainsi, lorsque a reçoit le message some_method , il commence la méthode de recherche some_method dans une classe propre , puis dans Une classe puis en liaison avec les modules de classe A s'il y en a (dans l'ordre inverse, les dernières victoires incluses).

Lorsque nous utilisons extend , nous ajoutons un lien à un module de la classe propre de l'objet. Donc, si nous utilisons A.new.extend (MyMod), nous ajoutons un lien vers notre module à la classe propre de l'instance de A ou à la classe a '. Et si nous utilisons A.extend (MyMod), nous ajoutons des liens à A (les objets, les classes sont aussi des objets) eigenclass A '.

so chemin de recherche de méthode pour a est le suivant: a = > a '= > modules liés à un 'class = > A.

Il existe également une méthode de préposition qui modifie le chemin de recherche:

a = > a '= > modules préfabriqués A = > A = > module inclus à A

désolé pour mon mauvais anglais.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top