<- More on classes
Writing iterators ->

Implementing AddressBook

Now that we have the classes Address and Person, let's move on to create AddressBook.

First step

The first step is very simple. AddressBook has an array which contains all our contacts. We will not use attr_accessor because we don't want the user to access this array directly. We will write our own access methods.


class AddressBook
    def initialize
        # Empty array.  
        @persons = []
    end
end
                       

That was easy enough. Let's add two access methods: AddressBook#add and AddressBook#remove


class AddressBook
    def initialize
        @persons = []  
    end
    def add(person)
        @persons += [person]  
    end
    def remove(person)
        # Use Array#delete
        @persons.delete(person)  
    end
end
                       

The Array#delete method will delete all the entries that match the given input. For example:


>> a = [ 1, 3, 3, 3, 3, 5]  
=> [1, 3, 3, 3, 3, 5]
>> a.delete(3)
=> 3
>> a
=> [1, 5]
                       

Since @persons is an array, we can use Array#delete

Automatic sorting

Now we are going to add a very neat feature to our AddressBook class: automatic sorting. What I mean by that is what when you type:


addr_book = AddressBook.new  

addr_book.add mary
addr_book.add joe
addr_book.add sandy
                       

All the entries will be sorted automatically. This feature makes our class much better than a regular array. Now, let's look at this task one step at a time.

How do we sort an array?

We want to sort the array alphabetically by first name, then last. In the section Sorting the addressbook had something like this:


# p_a == "person a"
addressbook.sort do |p_a, p_b|
    p_a["first name"] <=> p_b["first name"]  
end
                       

Let's adapt this to our class AddressBook:


@persons.sort do |a, b|
    a.first_name <=> b.first_name  
end
                       

If you did the exercises of this section, you also know how to sort by full names. Here is one way to do it:


@persons.sort do |a, b|
    if  a.first_name  == b.first_name  
        a.last_name  <=> b.last_name
    else
        a.first_name <=> b.first_name  
    end
end
                       

If the first names are the same, we compare the last names. Otherwise, we compare the first names.

Simplifying things.

The basis of simplification is to divide the problem into smaller components. Let's start by putting the code block in a method:


def by_name(a,b)
    if  a.first_name  == b.first_name  
        a.last_name  <=> b.last_name
    else
        a.first_name <=> b.first_name  
    end
end
                       

Now we can write:


@persons.sort do |a, b|  
    by_name(a,b)
end
                       

This is much shorter. Now, you will learn something about code blocks. In addition to the notation:


@persons.sort do |a, b|  
    ...
end
                       

You can also write:


@persons.sort { |a, b|  
    ...
}
                       

The two notations mean exactly the same thing. The difference is that the do...end notation is more clear, and the {...} notation is shorter. But the sort notation means that you can write:


@persons.sort { |a, b| by_name(a,b) }  
                       

You can almost read this as "sort by name". This is very readable code. I suggest that, for now, you only use the {...} notation when you can put everything in one line.

Finishing off

Now it's time to put this into our AddressBook class and and implement our auto-sort feature.


class AddressBook
    def add(person)
        @persons += [person]  
        @persons = @persons.sort{|a,b| by_name(a,b)} 
    end

    def by_name(a,b)
        if  a.first_name  == b.first_name  
            a.last_name  <=> b.last_name
        else
            a.first_name <=> b.first_name  
        end
    end
end
                       

Now, whenever you add a person, the addressbook gets sorted automatically.


book.add sandy
book.add joe
book.add mary
book.add melissa

# 'book' is sorted.  
                       
<- More on classes
Writing iterators ->