为什么Ruby大写方法试图在空变量上调用self?

时间:2015-06-29 13:56:12

标签: ruby

这是地址簿的课程。我希望能够调用full_name方法。如果没有中间名,那么在名字和姓氏之间不应显示空格。

我正在调用capitalize方法,以便将名称的第一个字母大写。当我输入一个中间名时它会正确运行,但如果没有中间名,我会收到此错误:

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>'

这是Contact类:

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

没有中间名的名称:

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

中间名:

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

4 个答案:

答案 0 :(得分:1)

您收到错误的原因是因为您在检查nil值时调用方法middle_name。在!middle_name.nil?

在这方面,如果没有对代码进行太多修改,只需将该方法调用替换为

即可
if !@middlename.nil?

它应该工作得很好。

您的full_name方法应该是这样的......

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

注意,您只需说if @middle_name而不是!@middle_name.nil?

答案 1 :(得分:1)

因为在full_name方法中,您也调用了middle_name名称。 因此,无论您是否提供中间名,它都会调用该方法。

请更改您的班级定义 -

  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

答案 2 :(得分:1)

以下是我能想到的#full_name最干净的实现:

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

为防止使用String#capitalize,我会实施#first_name=#middle_name=#last_name=,因为:

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

答案 3 :(得分:0)

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