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