More on classes Writing iterators

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

 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:

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

 @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