Nesta aula iremos aprender como definir classes e métodos em runtime, veremos onde podemos utilizar esta técnica para automatizar mais ainda o trabalho de um programador.
Hoje falaremos sobre:
Nós já falamos sobre em Ruby ser um objeto, e sobre utilizarmos o PascalCase.
Primeiro vamos aprender como criar uma classe dinâmica, para isso criaremos um arquivo
classe_dinamica.rb
, escreva o código abaixo dentro deste arquivo.
require 'byebug'
debugger
# Definir Classe em runtime
classe = "danilo"
classe = classe.capitalize
eval("class #{classe} end")
classe = Object.const_get(classe)
puts classe
No exemplo acima vimos como utilizar o método .capitalize
necessário para atribuirmos as classes
dinamicamente com o nome certo. Ao invés de classe = classe.capitalize
você pode fazer
classe.capitalize!
onde o !
já executa na referência da classe.
Na linha com eval
é onde criamos a nossa classe dinamicamente, abaixo disso temos agora a
variável classe
que recebe um objeto criado, todas classes são constantes, por causa da letra
maiúscula
no começo.
Crie um arquivo metodo_dimamica.rb
, já vimos este assunto em aulas anteriores, mas vamos rever
sobre runtime,
aqui definimos uma classe e um método estático, que dentro dele está definindo um método em tempo de execução
que será recebido como parâmetro do método estático.
require 'byebug'
# Definir Metodo em runtime
class Teste
def self.definir(nome_metodo)
define_method(nome_metodo) do
puts "metodo em runtime"
end
end
end
Teste.definir("teste")
Teste.new.teste
debugger
x = ""
Agora veremos a definição de várias classes em runtime, crie um arquivo classes_dimamica.rb
,
escreva o código abaixo e
execute.
require 'byebug'
def definir_classe(classe)
classe = classe.capitalize
eval("class #{classe} end")
classe = Object.const_get(classe)
end
["Classe1", "Classe2", "Classe3"].each do |classe|
definir_classe(classe)
end
debugger
x = ""
Conseguimos também definir métodos em lote, através de um array por exemplo, em cada loop será definido um método novo.
require 'byebug'
# Definir Vários métodos em runtime
class Teste
def self.definir(*metodos)
metodos.each do |metodo|
define_method(metodo) do
puts "metodo em runtime"
end
end
end
end
Teste.definir("metodo1", "metodo2", "metodo3")
a = Teste.new
puts a.methods - Class.methods
Juntando tudo que aprendemos até agora podemos ver como fica a definição de classes e métodos em runtime.
Note que temos um método definir_classe
que recebe como parâmetro um nome de classe e um método
require 'byebug'
#definir classe e metodos em runtime
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
classe = classe.capitalize
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
# debugger
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe("danilo2", metodo)
end
["mostrar", "exibir", "visualizar"].each do |metodo|
Danilo2.new.send(metodo, 1,2,3)
end
# chamando todos dinamicos
["Danilo", "Sheila", "Lana"].each do |classe|
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe(classe, metodo)
Object.const_get(classe).new.send(metodo, 1,2,3)
end
end
Observe que quando for testar usando o debugger é necessário criar uma instância com o
new
.
Definindo classes classes e métodos para essas classes dinamicamente
require 'byebug'
#definir classe e metodos em runtime
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
classe = classe.capitalize
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe("danilo2", metodo)
end
["mostrar", "exibir", "visualizar"].each do |metodo|
Danilo2.new.send(metodo, 1,2,3)
end
# chamando todos dinamicos
["Danilo", "Sheila", "Lana"].each do |classe|
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe(classe, metodo)
Object.const_get(classe).new.send(metodo, 1,2,3)
end
end
Agora vamos aprender como definir várias classes e metodos em runtime utilizando hash, pode criar um arquivo novo para testar o código abaixo.
require 'byebug'
#definir várias classes e metodos em runtime utilizando hash
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
{
"Danilo" => ["mostrar", "exibir", "visualizar"],
"Sheila" => ["mostrar", "exibir", "visualizar"],
"Lana" => ["mostrar", "exibir", "visualizar"]
}.each do |classe, metodos|
metodos.each do |metodo|
definir_classe(classe, metodo)
end
end
puts Danilo.new.methods - Class.methods
puts Sheila.new.methods - Class.methods
puts Lana.new.methods - Class.methods
# Danilo.new.mostrar 1,2,3
# Danilo.new.exibir 1,2,3
# Danilo.new.visualizar 1,2,3
debugger
x = ""
Como visto nessa série de metaprogramação conseguimos gerar código facilmente com o Ruby, todas estratégias aqui visam otimizar o tempo e aumentar a nossa produtividade enquanto programadores.
Arquivo aula.rb
final:
require 'byebug'
#==================================
# Definir Classe em runtime
classe = "danilo"
classe = classe.capitalize
eval("class #{classe} end")
classe = Object.const_get(classe)
puts classe
#==================================
# Definir Metodo em runtime
class Teste
def self.definir(nome_metodo)
define_method(nome_metodo) do
puts "metodo em runtime"
end
end
end
Teste.definir("teste")
Teste.new.teste
#==================================
# Definir Várias classes em runtime
def definir_classe(classe)
classe = classe.capitalize
eval("class #{classe} end")
classe = Object.const_get(classe)
end
["Classe1", "Classe2", "Classe3"].each do |classe|
definir_classe(classe)
end
#==================================
# Definir Vários metodos em runtime
class Teste
def self.definir(*metodos)
metodos.each do |metodo|
define_method(metodo) do
puts "metodo em runtime"
end
end
end
end
Teste.definir("metodo1", "metodo2", "metodo3")
a = Teste.new
puts a.methods - Class.methods
#==================================
#definir classe e metodos em runtime
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
classe = classe.capitalize
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe("danilo2", metodo)
end
["mostrar", "exibir", "visualizar"].each do |metodo|
Danilo2.new.send(metodo, 1,2,3)
end
# chamando todos dinamicos
["Danilo", "Sheila", "Lana"].each do |classe|
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe(classe, metodo)
Object.const_get(classe).new.send(metodo, 1,2,3)
end
end
#==================================
#definir várias classes e metodos em runtime utilizando hash
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
{
"Danilo" => ["mostrar", "exibir", "visualizar"],
"Sheila" => ["mostrar", "exibir", "visualizar"],
"Lana" => ["mostrar", "exibir", "visualizar"]
}.each do |classe, metodos|
metodos.each do |metodo|
definir_classe(classe, metodo)
end
end
puts Danilo.new.methods - Class.methods
puts Sheila.new.methods - Class.methods
puts Lana.new.methods - Class.methods
# Danilo.new.mostrar 1,2,3
# Danilo.new.exibir 1,2,3
# Danilo.new.visualizar 1,2,3
# debugger
x = ""
Arquivo classe_dimamica.rb
final:
require 'byebug'
#==================================
# Definir Classe em runtime
classe = "danilo"
debugger
classe.capitalize!
eval("class #{classe} end")
classe = Object.const_get(classe)
puts classe
Arquivo classes_dimamica.rb
final:
require 'byebug'
# Definir Várias classes em runtime
def definir_classe(classe)
classe = classe.capitalize
eval("class #{classe} end")
end
["Classe1", "classe2", "Classe3"].each do |classe|
definir_classe(classe)
end
debugger
x = ""
Arquivo classes_e_metodos_dinamicos.rb
final:
require 'byebug'
#definir classe e metodos em runtime
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
classe = classe.capitalize
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe("danilo2", metodo)
end
["mostrar", "exibir", "visualizar"].each do |metodo|
Danilo2.new.send(metodo, 1,2,3)
end
# chamando todos dinamicos
["Danilo", "Sheila", "Lana"].each do |classe|
["mostrar", "exibir", "visualizar"].each do |metodo|
definir_classe(classe, metodo)
Object.const_get(classe).new.send(metodo, 1,2,3)
end
end
debugger
x = ""
Arquivo classes_e_metodos_dinamicos_com_hash.rb
final:
require 'byebug'
#definir várias classes e metodos em runtime utilizando hash
def definir_classe(classe, nome_metodo)
if(classe.is_a?(String))
eval("class #{classe} end");
classe = Object.const_get(classe)
end
classe.class_eval do
define_method(nome_metodo) do |*params|
puts "o valor dos parametros é: #{params.join(", ")}"
end
end
end
{
"Danilo" => ["show1", "show2", "show3"],
"Sheila" => ["print1", "print2", "print3"],
"Lana" => ["puts1", "puts2", "puts3"]
}.each do |classe, metodos|
metodos.each do |metodo|
definir_classe(classe, metodo)
end
end
puts Danilo.new.methods - Class.methods
puts Sheila.new.methods - Class.methods
puts Lana.new.methods - Class.methods
debugger
x = ""
Arquivo metodo_dimamica.rb
final:
require 'byebug'
# Definir Metodo em runtime
class Teste
def self.definir(nome_metodo)
define_method(nome_metodo) do
puts "metodo em runtime"
end
end
end
Teste.definir("teste")
Teste.new.teste
debugger
x = ""
Arquivo metodos_dimamica.rb
final:
require 'byebug'
# Definir Vários metodos em runtime
class Teste
def self.definir(*metodos)
metodos.each do |metodo|
define_method(metodo) do
puts "metodo em runtime"
end
end
end
end
Teste.definir("metodo1", "metodo2", "metodo3")
a = Teste.new
puts a.methods - Class.methods
debugger
x = ""
Arquiteto de software, analista, programador, professor. Danilo criou o projeto torne-se um programador, para passar o seu conhecimento para a nova geração. Com o intuito de ser um bom pai, Danilo trabalha muito motivado para garantir o futuro de sua filha.