Nesta aula iremos aprender como programar orientado a objetos por comportamento, iremos ver os estados de nossas instâncias e iremos injetar módulos em nossas classes.
Para te explicar os módulos, precisamos entender o que é que POO por comportamento, vimos na aula anterior que podemos atribuir o valor "Danilo" numa variável, como exemplo abaixo:
a = "Danilo"
Quando fazemos isso criamos uma nova instância de String
, então ela é armazenada na variável
a
, vimos que podemos adicionar métodos em tempo de execução como:
a = "Danilo"
def a.teste
1
end
a.teste
Desta forma podemos utilizar a variável a
, como uma classe, para utilizarmos herança com essa
instância a
utilizamos o clone
.
Com o método clone
, conseguimos clonar o comportamento/estado da variável a
para
b
.
Para comparação o código abaixo resultaria no mesmo efeito
class << a
def teste2
2
end
end
a.teste2
Para utilizar os accessors
, você poderia fazer
class << a
def teste2
2
end
attr_accessor :nome, :tel
end
a.teste2
a.nome = "Danilo"
puts a.nome
class Carro
def initialize
@nome = "teste"
end
def show
@nome
end
end
a = "Danilo"
def a.mostrar
"#{self}---"
end
Também temos o método dup
, parecido com o clone ele não carrega o comportamento apenas o estado é
herdado,
duplicando a instância.
Como de praxe copie os arquivos das aulas anteriores para seguir conforme o padrão.
Para o arquivo aula.rb
faça:
require 'byebug'
debugger
a = "Danilo"
def a.mostrar
"#{self}---"
end
Podemos utilizar o módulo para várias coisas, com
Para utilizarmos vários métodos pra string
Danilo, fazemos:
danilo = "teste"
def danilo.olha1
"teste danilo"
end
def danilo.olha2
"teste danilo"
end
def danilo.olha3
"teste danilo"
end
debugger
Contudo torna-se repetitivo, observe quantas vezes utilizamos danilo.alguma_coisa
, para nos
auxiliar temos o Operador
com desvio a esquerda(<<), então podemos fazer:
danilo = "teste"
class << danilo
def olha1
"teste danilo"
end
def olha2
"teste danilo"
end
def olha3
"teste danilo"
end
end
debugger
Com esse método alteramos dentro da classe o método sem ter que replicado.
Exemplo de definição de método
class Danilo
def self.ola
"olha danilo"
end
end
debugger
Danilo.ola
E abaixo fazemos a inclusão de métodos para a classe.
class Danilo
class << self
def ola1
"olha danilo"
end
def ola2
"olha danilo"
end
def ola3
"olha danilo"
end
end
end
debugger
Danilo.ola
Também podemos utilizar accessors pra nossa classe.
class Danilo
class << self
attr_accessors :nome
end
end
debugger
Danilo.nome
Desta forma em tempo de execução você consegue manipular os getters e setters da sua aplicação, uma vez que elas já foram atribuídas.
Danilo.nome = "Danilo"
Danilo.nome
Módulos como namespace
Nós utilizamos ::
, para acessar os namespaces.
module Utilidades
class Cpf
def validar
end
end
class Cnpj
def validar
end
end
end
debugger
Utilidades::Cpf
Incluindo módulos em outras classes
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
module Mostrar
def ola
puts "dados"
end
def ola2
puts "dados2"
end
end
class Cliente
include Validacoes
include Mostrar
end
class Fornecedor
include Validacoes
end
debugger
Cliente.new.validar_cpf
Isso permite que uma injeção de alguns métodos específicos numa determinada classe melhor do que a herança genérica que pode trazer algumas coisas desnecessárias.
Uma forma de adicionar métodos em tempo de execução é o extend
, incluindo os métodos na classe da
mesma forma.
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
a = "ss"
a.extend Validacoes
debugger
Com o código abaixo incluímos um método que retorna olá
, em cada objeto do tipo
String
.
module Teste
def oi
"ola"
end
end
String.include Teste
debugger
Com o código abaixo incluímos um método que troca os espaços por traços.
module Teste
def tirar_spacos
self.gsub(" ", "-")
end
end
module Teste2
def metodo_de_classe
"teste"
end
end
String.include Teste
String.extend Teste2
debugger
Obs.: o include
, incluí o método na instancia, já o extend
irá extender a classe,
assim toda classe terá o método incluído por ele.
Com o código abaixo incluímos um método que tem o mesmo resultado do extend
, isso por causa do
self
feito na classe na hora de incluir.
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
class Teste
class << self
include Validacoes
end
end
class Teste2
extend Validacoes
end
debugger
Aqui neste módulo estamos trabalhando com inclusão tanto na classe quanto na instância, neste caso faremos um módulo dentro de outro módulo.
module InstanciaEClasse
def instancia
"metodo de instancia"
end
module Classe
def de_classe
"metodo de classe"
end
end
end
class Teste
include InstanciaEClasse
extend InstanciaEClasse::Classe
end
Teste.new.instancia
Teste.de_classe
debugger
Agora vamos ver sobre o included
, com esse método conseguimos fazer a inclusão e extensão ao mesmo
tempo, testando com o debugger
você pode ver melhor como funciona
module InstanciaEClasse
def instancia
"metodo de instancia"
end
def instancia2
"metodo de instancia"
end
def self.included(cls)
puts "-----#{cls} ----"
cls.extend Classe
end
module Classe
def de_classe
"metodo de classe"
end
end
end
class Teste
include InstanciaEClasse
end
debugger
Teste.new.instancia
Teste.de_classe
No código abaixo vemos um exemplo de implementação errada, onde o self
se refere ao módulo e não a
classe em si.
module InstanciaEClasse
def instancia
"metodo de instancia"
end
def self.de_classe
"metodo de classe"
end
end
class Teste
include InstanciaEClasse
end
debugger
Teste.new.instancia
Teste.de_classe
require 'byebug'
#################################
danilo = "teste"
def danilo.olha
"teste danilo"
end
a = danilo.clone
a.olha
b = danilo.dup
b.olha
cc = a.dup
debugger
def cc.novo
2
end
clone = copia variáveis e metodos
dup = publica sem a cópia da metaprogramacao
#################################
danilo = "teste"
def danilo.olha1
"teste danilo"
end
def danilo.olha2
"teste danilo"
end
def danilo.olha3
"teste danilo"
end
cleber = "teste"
class << cleber
def olha1
"teste danilo"
end
def olha2
"teste danilo"
end
def olha3
"teste danilo"
end
end
#################################
class Danilo
class << self
def ola1
"olha danilo"
end
def ola2
"olha danilo"
end
def ola3
"olha danilo"
end
end
end
debugger
Danilo.ola
#################################
class Danilo
def self.nome=(value)
@nome = value
end
def self.nome
@nome
end
def self.endereco=(value)
@endereco = value
end
def self.endereco
@endereco
end
def self.telefone=(value)
@telefone = value
end
def self.telefone
@telefone
end
end
class Danilo
class << self
attr_accessor :nome, :endereco, :telefone
end
end
debugger
Danilo.nome
#################################
module Utilidades
class Cpf
def validar
end
end
class Cnpj
def validar
end
end
end
debugger
Utilidades::Cpf
#################################
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
module Mostrar
def ola
puts "dados"
end
def ola2
puts "dados2"
end
end
class Cliente
include Validacoes
include Mostrar
end
class Fornecedor
include Validacoes
end
debugger
Cliente.new.validar_cpf
#################################
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
a = "ss"
a.extend Validacoes
debugger
#################################
module Teste
def tirar_spacos
self.gsub(" ", "-")
end
end
module Teste2
def metodo_de_classe
"teste"
end
end
String.include Teste
String.extend Teste2
debugger
#################################
module Validacoes
def validar_cpf
true
end
def validar_cnpj
false
end
end
class Teste
class << self
include Validacoes
end
end
class Teste2
extend Validacoes
end
debugger
#################################
module InstanciaEClasse
def instancia
"metodo de instancia"
end
module Classe
def de_classe
"metodo de classe"
end
end
end
class Teste
include InstanciaEClasse
extend InstanciaEClasse::Classe
end
Teste.new.instancia
Teste.de_classe
debugger
#################################
module InstanciaEClasse
def instancia
"metodo de instancia"
end
def instancia2
"metodo de instancia"
end
def self.included(cls)
puts "-----#{cls} ----"
cls.extend Classe
end
module Classe
def de_classe
"metodo de classe"
end
end
end
class Teste
include InstanciaEClasse
end
debugger
Teste.new.instancia
Teste.de_classe
#==================== Errado ====================
module InstanciaEClasse
def instancia
"metodo de instancia"
end
def self.de_classe
"metodo de classe"
end
end
class Teste
include InstanciaEClasse
end
debugger
Teste.new.instancia
Teste.de_classe
#==================== Errado ====================
Nesta aula iremos aprender como criar métodos de forma dinâmica, iremo...
Nesta aula iremos aprender como abrir uma classe, com os comandos inst...
Nesta aula iremos aprender como definir classes e métodos em runtime, ...
Nesta aula iremos aprender a renomear ou duplicar métodos de forma din...
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.