Include,require,load e extend em Ruby
Ao começar com Ruby várias coisas podem te deixar confuso. Como módulos, blocos, yield, proc, lambda e também a diferença entre load e require, include e extend. Então resolvi fazer essa pequena explicação para sanar a dúvida de quem estiver iniciando em Ruby atualmente, pode ser que já exista um tutorial parecido por aí mas não me lembro de ter visto.
Require e Load
Em nosso exemplo, temos dois arquivos (primeiro require_exemplo1.rb):
require 'require_exemplo2'
puts "meu nome é #{@name}"
puts "seu nome é #{SEUNOME}"
em require_exemplo2.rb
@name = "Daniel"
SEUNOME = "fulano"
Meu arq1.rb irá imprimir os valores de variável de instância (@name) e também a constante SEUNOME, pois basicamente o que o require faz é adicionar o código do arquivo requerido fazendo com que o arquivo que fez o require tenha acesso a este código após o require.
Agora vamos fazer o mesmo exemplo com load, criamos dois arquivos um chamado load_exemplo1 e outro load_exemplo2. Em load_exemplo1.rb
load 'load_exemplo2.rb'
puts "meu nome é #{@name}"
puts "seu nome é #{SEUNOME}"
em load_exemplo2.rb
@name = "Daniel"
SEUNOME = "fulano"
Primeiro, ao usar o load precisamos especificar a extensão do arquivo. Fazendo isso o resultado será o mesmo que o com require. Mas a diferença não é só isso. Não vemos diferença pois este exemplo não é adequado.
Partindo para outro exemplo temos exemplo1.rb:
puts "Passo 1"
require 'exemplo2'
puts "Passo 3"
require 'exemplo2'
exemplo2.rb
puts "Passo 2"
Ao executar teremos, impresso Passo 1 , Passo 2 e Passo 3 …. Passo 2 foi impresso pelo puts do meu arquivo exemplo2.rb mas mesmo eu requerendo ele novamente no final do exemplo1.rb ele não foi impresso novamente, pois require apenas requer o arquivo uma vez e não chama o código duas vezes. Mas se trocarmos o exemplo com abaixo:
exemplo1.rb
puts "Passo 1"
load 'exemplo2.rb'
puts "Passo 3"
load 'exemplo2.rb'
exemplo2.rb
puts "Passo 2"
Agora o resultado será Passo 1 Passo 2 Passo 3 Passo 2 …. o load irá chamar o código quantas vezes ele for carregado. Basicamente a diferença é esta. Require vai incluir o arquivo apenas uma vez enquanto o load irá incluir o arquivo quantos vezes ele for executado. O load é muito bom para arquivos que mudam em runtime enquanto o require será útil para arquivos que não serão alterados.
Include e Extend
E para que serve include e extend ?
Eles nada tem a ver com arquivos. Mas sim em como adicionar código em suas classes. Vejamos o exemplo abaixo:
Classe ruby.rb
module Ruby
def shine
"and shine"
end
end
Classe stone.rb
class Stone
include Ruby
def i_am
"I am a rock"
end
end
Então temos um modulo chamado Ruby, e uma classe chamada Stone… No arquivo da minha classe Stone(stone.rb) estou requerendo o arquivo ruby.rb que contém o módulo, então meu módulo passa a fazer parte do arquivo stone.rb mas ainda não faz parte da classe Stone. Então utilizo o include para embutir o módulo Ruby na classe Stone (esta ação é chamada de mixin)
Seu eu criar um instância de stone… terei acesso aos métodos do módulo e aos métodos da classe, veja abaixo:
my_stone = Stone.new
puts "#{my_stone.i_am} and #{my_stone.shine}" # =>I am a rock and shine
Agora já sabemos o que são requires, load, modules, mixin e include. Onde entra o extend? Vejamos o exemplo anterior com algumas alterações.
Classe ruby.rb
module Ruby
def shine
"and shine"
end
end
Classe stone.rb
class Stone
def i_am
"I am a rock"
end
end
Continuo requerendo o arquivo ruby mas não faço mais o include, então minha classe ainda não tem o método shine. Mas depois de instaciar a classe Stone vou utilizar o extend, como abaixo:
stone = Stone.new
stone.extend Ruby
puts stone.shine
Desta forma estou adicinando o método shine apenas a instância stone mas se eu tivesse stone2 ela não teria acesso ao método shine.
Basicamente acho que estes exemplos ilustram bem as diferenças e quando usar, se eu tiver esquecido de alguma coisas por favor comentem abaixo. No próximo post sobre ruby vou tentar falar de yield, blocos, lambda e proc.