Beast_Code
Beast_Code

Reputation: 3257

Why is the Ruby capitalize method trying to call its self on an empty variable?

This is a class for an address book. I want to be able to call the full_name method. If there is no middle name then there shouldn't be a space displayed between first and last name.

I am invoking the capitalize method so that it will capitalize the first letter of the name. When I enter a middle name it runs correctly, but if there is no middle name I receive this error:

contact.rb:9:in `middle_name': undefined method `capitalize' for nil:NilClass (NoMethodError)
    from contact.rb:18:in `full_name'
    from contact.rb:31:in `<main>'

This is the Contact class:

class Contact
  attr_writer :first_name, :middle_name, :last_name

  def first_name
    @first_name.capitalize
  end

  def middle_name
    @middle_name.capitalize
  end

  def last_name
    @last_name.capitalize
  end

  def full_name
    full_name = first_name
    if !middle_name.nil?
      full_name += " "
      full_name += middle_name
    end
    full_name += " "
    full_name += last_name
    full_name
  end
end

Name without a middle name:

jon = Contact.new
jon.first_name = "jon"
jon.last_name = "bell"
puts jon.full_name

With a middle name:

hugo = Contact.new
hugo.first_name = "hugo"
hugo.middle_name = "don"
hugo.last_name = "boss"
puts hugo.full_name

Upvotes: 1

Views: 226

Answers (4)

Vamsi Krishna
Vamsi Krishna

Reputation: 3792

class Contact
  attr_writer :first_name, :middle_name, :last_name

  def first_name
    @first_name.capitalize if @first_name
  end

  def middle_name
    @middle_name.capitalize if @middle_name
  end

  def last_name 
    @last_name.capitalize if @last_name
  end

  # The full_name method can be refactored as below...

  def full_name # If plain Ruby
    name = [first_name, middle_name, last_name].reject{|name_type| !(name_type =~ /\A[[:space:]]*\z/).nil?}
    name.join(" ")
  end

  def full_name_rails # If Ruby on Rails
    name = [first_name, middle_name, last_name].reject(&:blank?).join(" ")
  end

end

Upvotes: 0

floum
floum

Reputation: 1159

Here is the cleanest implementation of #full_name I can think of :

def full_name
  [@first_name, @middle_name, @last_name].reject(&:nil?).map(&:capitalize).join(' ')
end

To prevent String#capitalizeto be used, I would implement #first_name=, #middle_name= and #last_name= as this :

def middle_name=(value)
  @middle_name = value.capitalize
end
# you can now omit the .map(&:capitalize) part from #full_name 

Upvotes: 1

Leo Correa
Leo Correa

Reputation: 19839

The reason you're getting the error is because you're calling the method middle_name when you're checking for a nil value. on !middle_name.nil?

On that note, without too many modifications to your code, simply replace that method call to

if [email protected]?

and it should work just fine.

Your full_name method should read like this...

def full_name
  full_name = first_name
  if @middle_name
    full_name += " "
    full_name += middle_name
  end
  full_name += " "
  full_name += last_name
  full_name
end

Note, you can simply just say if @middle_name instead of !@middle_name.nil?

Upvotes: 1

Nikita Singh
Nikita Singh

Reputation: 370

Since in the full_name method you are calling middle_name name as well. So whether or not you provide a middle name it will call that method.

Please change your class definition like this -

  class Contact
    attr_writer :first_name, :middle_name, :last_name

    def first_name
      @first_name.capitalize if @first_name
    end

    def middle_name
      @middle_name.capitalize if @middle_name
    end

    def last_name 
      @last_name.capitalize if @last_name
    end

    def full_name
      full_name = first_name
      if !middle_name.nil?
        full_name += " "
        full_name += middle_name
      end
      full_name += " "
      full_name += last_name
      full_name
    end
  end

Upvotes: 1

Related Questions