More on classes |
|
Writing iterators |
Now that we have the classes Address and Person, let's move on to create AddressBook.
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
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.
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.
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.
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 |