Pergunta

Apenas começando minha cabeça em torno de Ruby metaprogramming. Os mixin / módulos sempre conseguem me confundir.

  • incluem : misturas em métodos módulo especificado como métodos instância na classe alvo
  • estender : misturas em métodos módulo especificado como métodos classe na classe alvo

Então é a principal diferença apenas isso ou é um dragão maior à espreita? por exemplo.

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!"
Foi útil?

Solução

O que você disse é correto. No entanto, há mais do que isso.

Se você tem um Klazz classe e Mod módulo, incluindo Mod em Klazz dá exemplos de acesso Klazz aos métodos de Mod. Ou você pode estender Klazz com Mod dando a classe acesso Klazz aos métodos de Mod. Mas também é possível estender um objeto arbitrário com o.extend Mod. Neste caso, o objeto individual fica métodos de Mod mesmo que todos os outros objetos com a mesma classe que o não.

Outras dicas

estender - adiciona métodos e constantes do módulo especificado para metaclass do alvo (isto é, a única classe) por exemplo.

  • se você chamar Klazz.extend(Mod), agora Klazz tem métodos de modificação (como métodos de classe)
  • se você chamar obj.extend(Mod), agora obj tem métodos de modificação (como métodos de instância), mas nenhuma outra instância de obj.class tem esses métodos adicionais.
  • extend é um método público

incluir - Por padrão, ele mistura em métodos do módulo especificado como métodos de instância do módulo de destino / aula. por exemplo.

  • se você chamar class Klazz; include Mod; end;, agora todas as instâncias do Klazz têm acesso a métodos de modificação (como métodos de instância)
  • include é um método particular, porque está destinado a ser chamado de dentro da classe container / módulo.

No entanto , módulos muitas vezes substituir o comportamento de include by-remendar macaco o método included. Isto é muito proeminente no código Rails legados. mais detalhes Yehuda Katz .

Mais detalhes sobre include, com seu comportamento padrão, assumindo que você execute o seguinte código

class Klazz
  include Mod
end
  • Se Mod já está incluído no Klazz, ou um de seus antepassados, a incluir declaração não tem efeito
  • Ele também inclui constantes da modificação em Klazz, contanto que eles não colidir
  • Ela dá acesso Klazz a variáveis ??módulo de modificação, por exemplo, @@foo ou @@bar
  • levanta ArgumentError se houver cíclica inclui
  • Anexa o módulo como ancestral imediato do chamador (ou seja Acrescenta Mod para Klazz.ancestors, mas Mod não é adicionado à cadeia de Klazz.superclass.superclass.superclass. Então, chamando super em Klazz # foo irá verificar se há Mod #foo antes de verificar para o método foo verdadeiro de superclasse de Klazz. Veja a RubySpec para mais detalhes.).

Claro, a documentação núcleo rubi é sempre o melhor lugar para ir para essas coisas. O projeto RubySpec também foi um recurso fantástico, porque eles documentaram a funcionalidade precisão.

Isso é correto.

Nos bastidores, incluem é realmente um alias para append_features , que (a partir dos docs):

implementação padrão do Ruby é adicione a constantes, métodos e módulo variáveis ??deste módulo para aModule se este módulo já não foi adicionado para aModule ou um de seus antepassados.

Todas as outras respostas são bons, incluindo a ponta que cavar através RubySpecs:

https://github.com/rubyspec/rubyspec/ blob / master / core / módulo / include_spec.rb

https://github.com/rubyspec/rubyspec/ blob / master / core / módulo / extend_object_spec.rb

Como para casos de uso:

Se você incluir módulo ReusableModule em ClassThatIncludes classe, os métodos, constantes, aulas, submódulos e outras declarações fica referenciado.

Se você estender ClassThatExtends classe com o módulo ReusableModule, em seguida, os métodos e constantes recebe Copiado . Obviamente, se você não for cuidadoso, você pode perder uma grande quantidade de memória por definições duplicação dinamicamente.

Se você usar ActiveSupport :: Concern, a funcionalidade .included () permite reescrever a classe, incluindo diretamente. módulo ClassMethods dentro de uma preocupação fica estendido (copiados) para a classe incluindo.

Eu também gostaria de explicar o mecanismo de como ele funciona. Se eu não estou certo agradar correta.

Quando usamos include estamos adicionando uma ligação da nossa classe para um módulo que contém alguns métodos.

class A
include MyMOd
end

a = A.new
a.some_method

Objetos não têm métodos, apenas clases e módulos de fazer. Então, quando a recebe some_method mesage que começar procurar método some_method na classe de a Eigen, em seguida, na classe A e, em seguida, ligado a módulos de classe A se houver algum (em ordem inversa, últimas vitórias incluídas).

Quando usamos extend estamos adicionando ligação a um módulo na classe eigen do objeto. Então, se nós usamos A.new.extend (MyMod) estamos adicionando ligação com o nosso módulo de classe ou a' classe instância Eigen da A. E se usarmos A.extend (MyMod) estamos adicionando ligação com A (objeto de, classes também são objetos) eigenclass A'.

Assim o método de pesquisa caminho para a é a seguinte: a => a '=> módulos ligados a um' class => A.

Também existe um método prepend que muda caminho de pesquisa:

a => a'=> prepended modulesto A => A => módulo incluído a A

desculpe pelo meu mau Inglês.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top