Ruby provides a construct called a Module
which is sort of like a thin Class. No início, Ruby devs pode olhar para módulos como uma “gaveta de lixo” de código que é apenas jogado em torno e usado para organizar arquivos, mas há um método para esta loucura. A classe Ruby Class
herda de Module
e adiciona coisas como instanciação, propriedades, etc. – todas as coisas que você normalmente teria de pensar uma classe teria. Porque Module
é, literalmente, um ancestral de Class
, isto significa que os Módulos podem ser tratados como classes em alguns aspectos.
o mais importante para entender é como a cadeia ancestral Ruby funciona. Como todas as línguas OOP, Ruby suporta herança. Quando você herda de uma classe, a superclasse é adicionada à sua cadeia ancestral. Você pode exibir os antepassados de qualquer classe, chamando ancestors
em que:
class Foo < BarendFoo.ancestors#=>
Como mencionado, você pode encontrar Module
na matriz Class.ancestors
.
Quando você include
um módulo em sua classe, o módulo é adicionado à cadeia ancestral da sua classe – assim como uma classe. Isto faz com que include
apenas uma forma de herança, não há nada de especial sobre ele.
module Barendclass Foo include BarendFoo.ancestors#=>
Todos os métodos de Bar
são adicionados Foo
como métodos de instância. Como a barra está na cadeia, você pode até mesmo chamar super
a partir dela para chamar métodos acima dela na cadeia, se eles são definidos em módulos ou Classes.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
Mesmo que Bar
é um módulo, super
ainda chama até a cadeia e, portanto, Baz#hello
também é chamado. Vale a pena notar que Bar
é adicionado à cadeia ancestral na frente de Baz. Quando um módulo é incluído, ele é sempre adicionado diretamente em cima dele está incluindo Classe. Isto pode ficar confuso ao adicionar vários módulos, uma vez que eles estão incluídos na ordem “reversa” :
class Foo include A include BendFoo.ancestors#=>
Quando A
é incluído, ele é inserido diretamente acima de Foo
. Mas quando B
está incluído, também é inserido diretamente acima de Foo
, de modo que ele acaba de destino antes de A
.
include vs extend
include
is easy enough to understand, it adds the module’s methods as instance methods to it’s including class. Você pode pensar em extend
fazendo a mesma coisa, mas em vez disso adicionando os métodos como métodos de classe.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
In addition to include/extend, Ruby 2.0+ adds theprepend
method. prepend
é semelhante ainclude
, mas em vez disso insere o módulo antes da classe including na cadeia hereditária.
class Foo include Bar prepend BazendFoo.ancestors#=>
Em Ruby você pode re-abrir qualquer classe e redefinir os métodos – não parece útil para substituir os métodos em uma classe usando um módulo anexado como oposição a redefinindo-os. Onde prepend
vem a calhar é quando você ainda terá a implementação original do método, porque precedido de módulos que podem substituir os métodos, mas ainda usar super
para chamar a implementação original.