Codes316 Codes316 - 1 month ago 9
Ruby Question

How use other variables in other classes in Ruby

I have this phone book program that takes a phone number and the type of phone number (it can be your home phone, cell phone, etc.) which is referred to as label. The program can take those values and store it in an address book where it can add contacts, delete contacts, and find a contact.

There is a class called PhoneContact that uses two parameters: phone number and label. The purpose of this class is to take in a phone number along with a label(Home phone, work phone, cell phone, etc.) and returns the output of what type of phone number it is, what the area code of that number is, etc.

An example would be:

James_May = PhoneContact.new('(555) 555-5555', :mobile)
puts James_May.phone_number
>> (555) 555-555
puts James_May.label
>> mobile


I created a PhoneBook class that is able to store, add, delete, and find phone contacts.

An Example of this is:

JG_contact = PhoneBook.new
JG_contact.add('Gary, James', '5555555555', :home)
puts "** JG's new entry:"
>> **James's new entry:
puts book.find('Gary, James')
>>(954) 111-2222 (work)
(444) 555-5555 (cell)


My problem is I'm not sure how to implement the variables like phone_number and label from the PhoneNumber class to the PhoneBook class. How do I use variables from other classes and does it make sense to implement these variables in a hash?

Here is a snippet of the code from the PhoneClass:

class PhoneContact
attr_reader :label

def initialize(phone_number, label)
@label = label
@phone_number = normalize(phone_number)
end


Here is the code from the PhoneBook Class:

require_relative ./PhoneContact

class PhoneBook

def contactList
@contactList ||= {}
end

def add_contact (newContact = {})
flag = false
if newContact.length < 1
return flag
else
flag = true
newContact.collect do |name, number|
contactList[name] = number
end
return flag
end
end

def delete (targetName)
if !contactList.has_key?(targetName)
return false
else
contactList.delete(targetName)
return true
end

end
def display_contact (targetName)
number = -1
if contactList.has_key?(targetName)
number = contactList(targetName)
puts "Contact name : #{targetName}, Contact Number, #{number}"
else
puts "#{targetName} doesn't exist in the phonebook"
end
end

def display_all_contacts
if !contactList.empty?
contactList.each {|name, number| puts "Contact name: #{name}, contact number #{number}" }
else
puts "You don't have any contact details your phonebook"
end
end
end

Answer

Ok, so your confusion seems to be two-fold. The first problem is what object to call a method on. Let me provide you an explanation here. Say I have this class A

class A
  attr_accessor :b, :c

  def initialize(b, c)
    @b = b
    @c = c
  end

  class << self
    def alphabet
      'abcdefghijklmnopqrstuvwxyz'
    end
  end
end

Also, let's say I have a = A.new('b', 8). I can call the methods I defined like this:

a.b # => 'b'
a.c # => 8
A.alphabet # => 'abcdefghijklmnopqrstuvwxyz'

This works like this because b and c are instance methods which means they are called on an instance variable. a is an instance of the class A. However, alphabet is a class method (as evident by its being inside the class << self class), so that is called on the class itself. This should explain instance methods vs. class methods

Second problem: how do I write a find method for the phonebook class. So Phonebook has an attribute contactList and all of the elements in that array should be of the type Phonecontact, so to find a person from contactList by name we can do this

def find(name)
  @contactList.select {|i| i.name == name}
end

This will return an array of people with the name specified. If you want that array to be of their phone numbers you can do something like this. (Assume pb is a Phonebook with a contact list)

pb.find('james').map(&:phone_number)

Additionally, I recommend that your add method store PhoneContacts, so it can really be as simple as this

def add(contact)
  @contactList << contact
end