Map method does not work as expected

4

I'm studying Ruby (without Rails, for now).

And I have the following scenario:

agenda.rb

require 'set'

class Agenda

    def initialize
        @contatos = Set.new
    end

    def contatos
        @contatos.to_a
    end

    def query_by_email(email)
        contatos.flatten.select { |e| e.email == email }
    end

    def add(*contato)
        @contatos << contato
    end

end

contato.rb

class Contato

    attr_accessor :nome
    attr_accessor :numero
    attr_accessor :email

    def initialize(nome, numero, email)
        @nome = nome
        @numero = numero
        @email = email
    end

    def hash
        email.hash
    end

    def eql?(other)
        other.class == self.class && other.email == @email
    end

    def to_s
        "Nome: #{@nome}, Numero: #{@numero}, Email: #{@email}"
    end

end

and my main.rb class (which I use for testing ..)

main.rb

require File.expand_path("contato")
require File.expand_path("agenda")

agenda = Agenda.new

a = Contato.new('Rafael', '98-88891948', '[email protected]')
b = Contato.new('Rafael', '98-88891948', '[email protected]')
c = Contato.new('Renan', '98-88891948', '[email protected]')
d = Contato.new('Renan', '98-88891948', '[email protected]')
e = Contato.new('Renan', '98-88891948', '[email protected]')

agenda.add a,b,c,d,e

puts agenda.contatos.map(&:email)

The last line is returning me the following error:

  
    

main.rb: 14: in map': undefined method email 'for # > > (NoMethodError)      from main.rb: 14: in ''

  

And I realized that if I add the flatten method, it works as waiting.

puts agenda.contatos.flatten.map(&:email)

I just do not understand why, since flatten does nothing special, it just returns an array that already existed without making any kind of modification or if you want to change the type. Could someone explain to me why it worked?

(I'm coming from java, the only 'functional' language I've ever worked with is javascript)

    
asked by anonymous 10.02.2015 / 18:42

2 answers

3

As mentioned by @Roh Barboza, your #contatos is not returning a simple list of contacts. The actual problem that needs to be fixed is not in how you run #map . The error is here:

def add(*contato)
    @contatos << contato
end

Within this function, contato is a list of contacts, not a single list. This is the list of arguments passed to the function. It should, in fact, be implemented like this:

def add(*contatos)
    contatos.each do |contato|
        @contatos << contato
    end
end

And that's it. Everything else is correct and will work properly.

    
10.02.2015 / 21:22
0

Your agenda.contacts is currently returning this:

[
 [
  Nome: Rafael, Numero: 98-88891948, Email: [email protected],
  Nome: Rafael, Numero: 98-88891948, Email: [email protected],
  Nome: Renan,  Numero: 98-88891948, Email: [email protected],
  Nome: Renan,  Numero: 98-88891948, Email: [email protected], 
  Nome: Renan,  Numero: 98-88891948, Email: [email protected]
 ]
]

Your Array is inside another Array, use this:

agenda.contatos.flatten.map(&:email)

or

agenda.contatos.first.map(&:email) 
    
10.02.2015 / 19:33