1
resposta

Erro ao tentar obter a posição do vetor no matcher

Estou com problemas ao obter os campos do método passado ao método method_missing sobreescrito na classe estoque. O erro relata que não há posição não nula no vetor. No final há o código completo mas aqui vou resumir a chamada e o method_missing que talvez já facilite:

  • Método method_missing sobreescrito
#http://ruby-doc.org/core-2.4.1/BasicObject.html#method-i-method_missing
    def method_missing (name)
        matcher = name.to_s.match "(.+)_que_mais_vendeu_por_(.+)"
        #puts matcher[0]
        #puts matcher[1]
        #puts matcher[2]
        puts matcher
        if !matcher
            puts "Método #{name} não encontrado"
        end
    end
  • Chamada de método ainda não existente
ebook_mais_vendido_por_ano = estoque3.ebook_que_mais_vendeu_por(&:titulo)
  • Código completo

  • sistema.rb

require_relative 'livro'
require_relative 'newsletter'
require_relative 'estoque'
#require_relative 'array'

class Float
    def para_dinheiro
        valor = "R$" << self.to_s.tr('.', ',')
        valor << "0" unless valor.match /(.*)(\d{2})$/
        valor
    end
end

agile = Livro.new("Agile Web Development with Rails", 70.00, 2011, false, 'Abril', 'Livro')
livro1 = Livro.new("Livro 1 &&**$$%%á", 100.00, 2002, false, 'Abril', 'Livro')
livro2 = Livro.new("Livro horário 2/|@}{", 200.00, 2002, true, 'Abril', 'Livro')
livro3 = Livro.new("Livro 3", 300.00, 2007, false, 'Globo', 'Livro')
livro4 = Livro.new("Livro 4", 400.00, 2007, true, 'Globo', 'Livro')
livro5 = Livro.new("Livro 5", 500.00, 1999, true, 'Abril', 'Livro')
livro6 = Livro.new("Livro 6", 600.00, 1999, false, 'Abril', 'Revista')
livro7 = Livro.new("Livro 6", 700.00, 1999, false, 'Atlas', 'Livro')
algoritmos = Livro.new("Algoritmos", 10.00, 1998, true, 'Abril', 'Livro')
arquitetura = Livro.new("Introdução À Arquitetura e Design de Software", 70.00, 2011, true, nil, 'Livro')

puts "#{agile.titulo}, #{agile.preco}, #{agile.ano_lancamento}, #{agile.possui_reimpressao?}"
puts "#{livro1.titulo}, #{livro1.preco}, #{livro1.ano_lancamento}, #{livro1.possui_reimpressao?}"
puts "#{livro2.titulo}, #{livro2.preco}, #{livro2.ano_lancamento}, #{livro2.possui_reimpressao?}"
puts "#{livro3.titulo}, #{livro3.preco}, #{livro3.ano_lancamento}, #{livro3.possui_reimpressao?}"
puts "#{livro4.titulo}, #{livro4.preco}, #{livro4.ano_lancamento}, #{livro4.possui_reimpressao?}"
puts "#{livro5.titulo}, #{livro5.preco}, #{livro5.ano_lancamento}, #{livro5.possui_reimpressao?}"
puts "#{livro6.titulo}, #{livro6.preco}, #{livro6.ano_lancamento}, #{livro6.possui_reimpressao?}"
puts "#{algoritmos.titulo}, #{algoritmos.preco}, #{algoritmos.ano_lancamento}, #{algoritmos.possui_reimpressao?}"
puts "#{arquitetura.titulo}, #{arquitetura.preco}, #{arquitetura.ano_lancamento}, #{arquitetura.possui_reimpressao?}"

livros = []
livros << agile
livros << livro1
livros << livro2
livros << livro3
livros << livro4
livros << livro5
livros << livro6 << livro7
livros << algoritmos
livros << arquitetura

estoque = Estoque.new
estoque.livros << agile
estoque.livros << livro1
estoque.livros << livro2
#puts "Máximo necessário: #{estoque.livros.maximo_necessario}"
estoque.livros << livro3
estoque.livros << livro4
#puts "Máximo necessário: #{estoque.livros.maximo_necessario}"
estoque.livros << livro5
puts "**************************"
estoque.livros << livro6 << livro7
puts "**************************"
estoque.livros << algoritmos << arquitetura
puts "Máximo necessário: #{estoque.livros.maximo_necessario}"
estoque.livros << Livro.new("Teste", 10.00, 1998, true, nil, 'Livro')
estoque.livros << Livro.new("Teste", 11.00, 1999, true, nil, 'Livro')
#estoque.livros.delete livro5
#puts "Máximo necessário: #{estoque.livros.maximo_necessario}"
#puts "Máximo necessário: #{estoque.livros.maximo_necessario}"

puts "Total de livros no estoque: #{estoque.total}"

estoque.exporta_csv

puts estoque.mais_barato_que 80

estoque2 = Estoque.new
estoque2 << livro1
estoque2 << livro2
estoque2 << livro3 << livro4


puts "Total de livros no estoque 2: #{estoque2.total}"

estoque2.vende livro2

puts "Total de livros no estoque 2: #{estoque2.total}"

puts "Máximo necessário de livros no estoque 2: #{estoque2.maximo_necessario}"

puts precos = [30.00, 40.00, 70.00, 59.00]
precos_string = []
precos.each do |preco|
  puts preco.class
  precos_string << preco.para_dinheiro
end
puts precos_string.to_s

puts "Total de títulos no estoque (V1): #{estoque.quantidade_titulos_v1}"
puts "Total de títulos no estoque (V2): #{estoque.quantidade_titulos_v2}"

#newsletter = Newsletter.new
#newsletter.notifica_livros_com_desconto livros

estoque.vende livro2
estoque.vende livro6
estoque.vende livro7

#puts estoque.quantidade_de_vendas_por(livro6, "titulo")

#puts "Quantidade de vendas do livro #{livro6.titulo}: #{estoque.quantidade_de_vendas_por(livro6, 'titulo')}"
#puts "Quantidade de vendas do livro #{livro2.titulo}: #{estoque.quantidade_de_vendas_por(livro2, 'titulo')}"


livro_cabana_1 = Livro.new("A Cabana", 10.00, 1998, true, 'Abril', 'Livro')
livro_cabana_2 = Livro.new("A Cabana", 10.00, 1998, true, 'Abril', 'Livro')
livro_cabana_3 = Livro.new("A Cabana", 10.00, 1998, true, 'Abril', 'Livro')
livro_cabana_4 = Livro.new("A Cabana", 10.00, 1998, true, 'Abril', 'Revista')
livro_cabana_5 = Livro.new("A Cabana", 10.00, 1998, true, 'Globo', 'Livro')
livro_cabana_6 = Livro.new("A Cabana", 10.00, 1998, true, 'Atlas', 'Livro')

livro_casa_1 = Livro.new("A Casa", 11.00, 1999, true, 'Globo', 'Livro')
livro_casa_2 = Livro.new("A Casa", 11.00, 1999, true, 'Globo', 'Livro')
livro_casa_3 = Livro.new("A Casa", 11.00, 1999, true, 'Siciliano', 'Revista')
livro_casa_4 = Livro.new("A Casa", 11.00, 1999, true, 'Atlas', 'Livro')
livro_casa_5 = Livro.new("A Casa", 11.00, 1999, true, 'Saraiva', 'Revista')
livro_casa_6 = Livro.new("A Casa", 11.00, 1999, true, 'Saraiva', 'Livro')
livro_casa_7 = Livro.new("A Casa", 11.00, 1999, true, 'Siciliano', 'Revista')
livro_casa_8 = Livro.new("A Casa", 11.00, 1999, true, 'Atlas', 'eBook')

livro_mansao_1 = Livro.new("A Mansao", 11.00, 1998, true, 'Abril', 'Revista')
livro_mansao_2 = Livro.new("A Mansao", 11.00, 1998, true, 'Atlas', 'Revista')
livro_mansao_3 = Livro.new("A Mansao", 11.00, 1998, true, 'Atlas', 'Revista')
livro_mansao_4 = Livro.new("A Mansao", 11.00, 1998, true, 'Atlas', 'eBook')

estoque3 = Estoque.new
estoque3 << livro_cabana_1 << livro_cabana_2 << livro_cabana_3 << livro_cabana_4 << livro_cabana_5 << livro_cabana_6
estoque3 << livro_casa_1 << livro_casa_2 << livro_casa_3 << livro_casa_4
estoque3 << livro_mansao_1 << livro_mansao_2 << livro_mansao_3 << livro_mansao_4

estoque3.vende livro_cabana_1
estoque3.vende livro_cabana_2
estoque3.vende livro_cabana_3
estoque3.vende livro_cabana_4
estoque3.vende livro_cabana_6

estoque3.vende livro_casa_1
estoque3.vende livro_casa_2
estoque3.vende livro_casa_3
estoque3.vende livro_casa_4
estoque3.vende livro_casa_5

estoque3.vende livro_mansao_1
estoque3.vende livro_mansao_2
estoque3.vende livro_mansao_3

livro_mais_vendido_por_titulo = estoque3.livro_que_mais_vendeu_por_titulo
livro_mais_vendido_por_editora = estoque3.livro_que_mais_vendeu_por_editora
livro_mais_vendido_por_ano = estoque3.livro_que_mais_vendeu_por_ano

puts "Livro mais vendido por titulo: #{livro_mais_vendido_por_titulo.titulo}"
puts "Livro mais vendido por editora: #{livro_mais_vendido_por_editora.editora} - #{livro_mais_vendido_por_editora.titulo}"
puts "Livro mais vendido por ano: #{livro_mais_vendido_por_editora.ano_lancamento} - #{livro_mais_vendido_por_editora.titulo}"
puts
puts "====================================================================="
puts

livro_mais_vendido_por_titulo = estoque3.livro_que_mais_vendeu_por(&:titulo)
livro_mais_vendido_por_editora = estoque3.livro_que_mais_vendeu_por(&:editora)
livro_mais_vendido_por_ano = estoque3.livro_que_mais_vendeu_por(&:ano_lancamento)

puts "Livro mais vendido por titulo: #{livro_mais_vendido_por_titulo.titulo}"
puts "Livro mais vendido por editora: #{livro_mais_vendido_por_editora.editora} - #{livro_mais_vendido_por_editora.titulo}"
puts "Livro mais vendido por ano: #{livro_mais_vendido_por_editora.ano_lancamento} - #{livro_mais_vendido_por_editora.titulo}"


revista_mais_vendido_por_titulo  = estoque3.revista_que_mais_vendeu_por(&:titulo)
revista_mais_vendido_por_editora = estoque3.revista_que_mais_vendeu_por(&:editora)
revista_mais_vendido_por_ano     = estoque3.revista_que_mais_vendeu_por(&:ano_lancamento)

puts "Revista mais vendido por titulo:  #{revista_mais_vendido_por_titulo.titulo}"
puts "Revista mais vendido por editora: #{revista_mais_vendido_por_editora.editora} - #{revista_mais_vendido_por_editora.titulo}"
puts "Revista mais vendido por ano:     #{revista_mais_vendido_por_editora.ano_lancamento} - #{revista_mais_vendido_por_editora.titulo}"


ebook_mais_vendido_por_ano = estoque3.ebook_que_mais_vendeu_por(&:titulo)
  • livro.rb
require_relative('conversor')

class Livro

    attr_reader :titulo, :preco, :ano_lancamento, :editora, :tipo

    def initialize(titulo, preco, ano_lancamento, possui_reimpressao, editora, tipo)
        @titulo = Conversor.new().string_para_alfanumerico(titulo)
        @preco = preco
        @ano_lancamento = ano_lancamento
        @possui_reimpressao = possui_reimpressao
        @preco = calcula_preco(preco)
        @editora = editora
        @tipo = tipo
    end

    def calcula_preco(preco)
        if @ano_lancamento < 2000
            preco *= 0.7 #30%
        elsif @ano_lancamento < 2006
            if @possui_reimpressao
                preco *= 0.90 #10%
            else
                preco *= 0.95 #5%
            end           
        elsif ano_lancamento <= 2010
            preco *= 0.96 #4%
        else
            preco
        end
    end

    def possui_reimpressao?
        @possui_reimpressao
    end

    def to_csv
        "#{@titulo}, #{@ano_lancamento}, #{@preco}"
    end

end
  • estoque.rb
require_relative 'contador'

class Estoque

    attr_reader :livros

    def initialize
        @livros = []
        @livros.extend Contador
        @vendas = []
    end

    def adiciona(livro)
        @livros << livro if livro #Verifica se livro é um livro? Como isto funciona?
    end

    def total
        @livros.size
    end

    def mais_barato_que(preco)
        # Mais com mais escrita de código
        #
        #livros_mais_baratos = []
        #@livros.each do |livro|
        #    if livro.preco < preco
        #        livros_mais_baratos << livro
        #    end
        #end
        #livros_mais_baratos

        # Maneira com escrita mais curta
        # O resultado da execução do método livros.select é o retorno do método mais_barato_que
        # Ele filtra os elementos do Array livros através da condição livro.preco < preco, que é a última instrução
        #
        @livros.select do |livro|
            livro.preco < preco
        end

    end

    def exporta_csv
        @livros.each do |livro|
            puts livro.to_csv
        end
    end

    def << (livro)
        @livros << livro
        self
    end

    def remove(livro)
        @livros.delete livro
    end

    def vende(livro)
        @livros.delete livro
        @vendas << livro
    end

    def maximo_necessario
        @livros.maximo_necessario
    end

    #versao1
    def quantidade_titulos_v1
        titulos = []

        @livros.each do |livro|

            if !titulos.include? livro.titulo
                titulos << livro.titulo
            end
        end

        titulos.size
    end

    #versao2
    def quantidade_titulos_v2
        titulos = []

        @livros.each do |livro|
            titulos << livro.titulo
        end

        titulos.uniq.size
    end

    def quantidade_titulos(titulo)
        titulos = []

        @livros.each do |livro|
            titulos << livro.titulo == titulo
        end

        titulos.size
    end

    def quantidade_de_vendas_de_titulo_beta(livro, titulo)
        quantidade_titulos titulo
    end

    def quantidade_de_vendas_por(livro, &campo)
         #@vendas.count { |venda| venda.titulo == livro.titulo }
         @vendas.count { |venda| campo.call(venda) == campo.call(livro) }
    end

    #Para entender qual bloco de código pode ser usado para os métodos é importante ler a documentação
    #de cada classe http://ruby-doc.org/core-2.4.1/Array.html
    #Abaixo o método sort aceita um bloco de código onde espera comparar dois objetos para definir
    #a regra de sua ordenação. O resultado da chamada do método sort é um novo array e para este
    #novo array o método last foi chamado para obter o último elemento do array
    def livro_que_mais_vendeu_por_titulo
        #Utilização de lambdas
         @vendas.sort {|v1,v2| quantidade_de_vendas_por(v1, &:titulo) <=> quantidade_de_vendas_por(v2, &:titulo)}.last
    end

    def livro_que_mais_vendeu_por_editora
        #Utilização de lambdas
         @vendas.sort {|v1,v2| quantidade_de_vendas_por(v1, &:editora) <=> quantidade_de_vendas_por(v2, &:editora)}.last
    end

    def livro_que_mais_vendeu_por_ano
        #Utilização de lambdas
         @vendas.sort {|v1,v2| quantidade_de_vendas_por(v1, &:ano_lancamento) <=> quantidade_de_vendas_por(v2, &:ano_lancamento)}.last
    end


    def vendas_por_tipo(tipo)
        @vendas.select { |vendas| vendas.tipo == tipo}
    end

    #usando lambda para tornar o método mais genérico
    #chamada exemplo: livro_mais_vendido_por_titulo = estoque3.livro_que_mais_vendeu_por(&:titulo)
    #estranho!: campo de lambda deve ser o último
    def livro_que_mais_vendeu_por(&campo)
        que_mais_vendeu_por("Livro", &campo)
    end

    def revista_que_mais_vendeu_por(&campo)
        que_mais_vendeu_por("Revista", &campo)
    end

    def que_mais_vendeu_por(tipo, &campo)
        vendas_de_um_tipo = vendas_por_tipo tipo
        vendas_de_um_tipo.sort {|v1,v2| quantidade_de_vendas_por(v1, &campo) <=> quantidade_de_vendas_por(v2, &campo)}.last
    end

    #http://ruby-doc.org/core-2.4.1/BasicObject.html#method-i-method_missing
    def method_missing (name)
        matcher = name.to_s.match "(.+)_que_mais_vendeu_por_(.+)"
        #puts matcher[0]
        #puts matcher[1]
        #puts matcher[2]
        puts matcher
        if !matcher
            puts "Método #{name} não encontrado"
        end
    end

    #def method_missing(name)
    #    matcher = name.to_s.match "(.+)_que_mais_vendeu_por_(.+)"
#
#    #    if matcher
#    #        tipo = matcher[1]
#    #        campo = matcher[2].to_sym  #pois precisamos converter para simbolo
#    #        que_mais_vendeu_por(tipo, &campo)
#    #    else
#    #        super
#    #    end
    #end

end
  • conversor.rb
class Conversor

    def string_para_alfanumerico(texto)
        #texto.gsub(/[\W]/, "")
        texto.gsub(/[^\w\s]/, "")
    end

end
  • contador.rb
module Contador
    def <<(livro)
        push (livro)
        if @maximo_necessario.nil? || @maximo_necessario < size
            @maximo_necessario = size
        end
        self
    end

    def maximo_necessario
        @maximo_necessario
    end
end
  • newsletter.rb
require_relative 'livro'

class Newsletter

    def notifica_livros_com_desconto(livros)
        livros.each do |livro|
            if livro.ano_lancamento < 2000
                puts "Newsletter: livros com desconto"
                puts livro.titulo
                puts livro.preco
            end
        end
    end

end
1 resposta

Oi Joacir, não me parece legível todo esse código espalhado aqui, você poderia zipar tudo e disponibilizar pra download ou mesmo criar um repositório no GitHub pra gente ver arquivo a arquivo direitinho e poder testar de forma mais fácil?