Domanda

Mi sto solo concentrando sulla metaprogrammazione di Ruby. I mixin / moduli riescono sempre a confondermi.

  • includi : mescola i metodi del modulo specificati come metodi di istanza nella classe target
  • estende : mescola i metodi del modulo specificato come metodi della classe nella classe target

Quindi la differenza principale è solo questo o è in agguato un drago più grande? per es.

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!"
È stato utile?

Soluzione

Quello che hai detto è corretto. Tuttavia, c'è di più.

Se hai una classe Klazz e il modulo Mod , incluso Mod in Klazz , fornisce istanze di Klazz accesso ai metodi di Mod . Oppure puoi estendere Klazz con Mod dando alla classe Klazz l'accesso a Mod ' metodi di s. Ma puoi anche estendere un oggetto arbitrario con o.eendend Mod . In questo caso il singolo oggetto ottiene i metodi di Mod anche se non tutti gli altri oggetti con la stessa classe di o .

Altri suggerimenti

estende : aggiunge i metodi e le costanti del modulo specificato alla metaclasse del target (ovvero la classe singleton)   per esempio.

  • se chiami Klazz.extend (Mod) , ora Klazz ha i metodi Mod (come metodi di classe)
  • se chiami obj.extend (Mod) , ora obj ha i metodi di Mod (come metodi di istanza), ma nessun'altra istanza di obj.class ha questi metodi aggiunto.
  • estende è un metodo pubblico

include : per impostazione predefinita, mescola i metodi del modulo specificato come metodi di istanza nel modulo / classe di destinazione.   per es.

  • se chiami classe Klazz; include Mod; end; , ora tutte le istanze di Klazz hanno accesso ai metodi di Mod (come metodi di istanza)
  • include è un metodo privato, poiché deve essere chiamato dall'interno della classe / modulo contenitore.

Tuttavia , i moduli molto spesso sovrascrivono includono il comportamento di correggendo le scimmie con il metodo incluso . Questo è molto importante nel codice Rails legacy. maggiori dettagli da Yehuda Katz .

Ulteriori dettagli su includono , con il suo comportamento predefinito, supponendo che tu abbia eseguito il seguente codice

class Klazz
  include Mod
end
  • Se Mod è già inclusa in Klazz o in uno dei suoi antenati, la dichiarazione include non ha alcun effetto
  • Include anche le costanti di Mod in Klazz, purché non si scontrino
  • Dà a Klazz l'accesso alle variabili del modulo Mod, ad es. @@ foo o @@bar
  • genera ArgumentError se ci sono inclusioni cicliche
  • Collega il modulo come antenato immediato del chiamante (ovvero aggiunge Mod a Klazz.ancestors, ma Mod non viene aggiunto alla catena di Klazz.superclass.superclass.superclass. Quindi, chiamando super in Klazz # foo controllerà Mod # foo prima di verificare il vero metodo foo della superclasse di Klazz. Vedi RubySpec per i dettagli.).

Naturalmente, la documentazione di base su ruby ?? è sempre il posto migliore dove andare per queste cose. Anche il Il progetto RubySpec era anche una risorsa fantastica, perché documentavano con precisione la funzionalità.

È corretto.

Dietro le quinte, include è in realtà un alias per append_features , che (dai documenti):

  

L'implementazione predefinita di Ruby è   aggiungere costanti, metodi e modulo   variabili di questo modulo in aModule if   questo modulo non è già stato aggiunto   a un modulo o uno dei suoi antenati.

Tutte le altre risposte sono buone, incluso il suggerimento per scavare in RubySpecs:

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

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

Per quanto riguarda i casi d'uso:

Se includi il modulo ReusableModule nella classe ClassThatIncludes, vengono referenziati i metodi, le costanti, le classi, i sottomoduli e altre dichiarazioni.

Se estendi la classe ClassThatExtends con il modulo ReusableModule, i metodi e le costanti vengono copiati . Ovviamente, se non stai attento, puoi sprecare molta memoria duplicando dinamicamente le definizioni.

Se si utilizza ActiveSupport :: Concern, la funzionalità .included () consente di riscrivere direttamente la classe inclusa. Il modulo ClassMethods all'interno di una preoccupazione viene esteso (copiato) nella classe inclusa.

Vorrei anche spiegare il meccanismo in cui funziona. Se non ho ragione, correggi.

Quando usiamo include stiamo aggiungendo un collegamento dalla nostra classe a un modulo che contiene alcuni metodi.

class A
include MyMOd
end

a = A.new
a.some_method

Gli oggetti non hanno metodi, ma solo i clasi e i moduli. Quindi quando a riceve il messaggio some_method inizia il metodo di ricerca some_method nella classe eigen di a , quindi in Una classe e quindi collegata ai moduli della classe A se ce ne sono (in ordine inverso, le ultime vittorie incluse).

Quando usiamo estende stiamo aggiungendo il collegamento a un modulo nella classe eigen dell'oggetto. Quindi se usiamo A.new.extend (MyMod) stiamo aggiungendo il collegamento al nostro modulo alla classe eigen dell'istanza di A o a '. E se usiamo A.extend (MyMod) stiamo aggiungendo il collegamento ad A (oggetto, le classi sono anche oggetti) eigenclass A '.

quindi il percorso di ricerca del metodo per a è il seguente: a = > a '= > moduli collegati a un 'class = > A.

inoltre esiste un metodo prepend che modifica il percorso di ricerca:

a = > a '= > modulo anteposto A = > A = > modulo incluso in A

scusate il mio cattivo inglese.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top