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.

Metaprogramming - Módulo


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.

Aula Prática

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

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
      
    

Arquivo final:
    
    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 ====================


  



Próximas Aulas


Metaprogramming - Dinâmicos

Nesta aula iremos aprender como criar métodos de forma dinâmica, iremo...

Metaprogramming - Eval para Classes e instâncias

Nesta aula iremos aprender como abrir uma classe, com os comandos inst...

Metaprogramming - Classes e métodos dinâmicos

Nesta aula iremos aprender como definir classes e métodos em runtime, ...

Metaprogramming - Alias para métodos e atributos

Nesta aula iremos aprender a renomear ou duplicar métodos de forma din...

Metaprogramming - Hooks

Nesta aula iremos aprender os conceitos de hooks, veremos como utiliza...

Metaprogramming - Missings

Nesta aula iremos aprender a utilizar os comandos const_missing e meth...

Instalando Rails

Nesta aula iremos aprender a instalar e configurar o Rails que é um do...

Rails Generators

Nesta aula iremos aprender um pouco sobre os generators do Rails, util...



Danilo

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.

ELEVE SEUS GANHOS E POTENCIALIZE SUA PERFORMANCE

Receba nossa Ebook de LÓGICA DE PROGRAMAÇÃO

© Didox Business & Technology - CNPJ: 12.127.195/0001-14