对Ruby中的NoMethodError感到困惑

时间:2012-11-26 22:55:01

标签: ruby

在一个简单的Ruby示例中,我收到了irb中没有出现的错误。

name = "Joe"
def say_hi
  "\"Hi there!\" said #{self}"
end
response = name.say_hi
puts response

此代码应返回“嗨那里!”乔说。

它在irb中运行得非常好。但是,当我尝试将相同的代码放在一个文件中并运行该文件时,我收到此错误:

say_hi.rb:8:in `<main>': private method `say_hi' called for "Joe":String (NoMethodError)

有关为何会发生这种情况的任何建议吗?

5 个答案:

答案 0 :(得分:3)

你快到了:

name = "Joe"
def name.say_hi
  "\"Hi there!\" said #{self}"
end

response = name.say_hi
puts response
#=> "Hi there!" said Joe

def name.say_hi会在name上定义单身方法,因此您可以按预期调用它:name.say_hi

答案 1 :(得分:1)

您为say_hi定义的方法main不是name。如果你想为名称定义它,你应该这样做:

class << name
  def say_hi
    %["Hi there!" said #{self}]
  end
end

答案 2 :(得分:1)

这是因为当您在IRB中定义方法时,它们将成为系统中所有对象的实例方法。包括那个字符串“乔”。但是当你正常运行代码时,它不会发生。您必须自己将该方法添加到String类。像这样,例如:

class String
  def say_hi
    "\"Hi there!\" said #{self}"
  end
end

"Joe".say_hi # => "\"Hi there!\" said Joe"

答案 3 :(得分:1)

您定义了变量'name`和方法。但他们之间没有联系。

你可以扩展String:

name = "Joe"
class String
  def say_hi
    "\"Hi there!\" said #{self}"
  end
end
response = name.say_hi
puts response

或者您为对象name本身定义方法(请参阅slivus answer

或者您可以在模块中定义方法并扩展变量。

优点:您也可以将该模块用于其他对象。

示例:

module Hi
  def say_hi
    "\"Hi there!\" said #{self}"
  end
end

name = "Joe"
name.extend(Hi)
puts name.say_hi

name2 = "Jane"
name2.extend(Hi)
puts name2.say_hi

答案 4 :(得分:1)

在irb内部(在顶级范围内),self设置为main类型为Object。这在此描述:What is "main" in Ruby?。所以:say_hi是在Object上定义的实例方法,因此所有接收器都会响应它,包括String的实例,如“Joe”。

尝试添加:

puts "Private methods: " + Object.private_methods.grep(/say/).inspect
puts "Public methods: " + Object.public_methods.grep(/say/).inspect

并且您将看到IRB将公共方法添加到Object,而脚本作为私有方法添加,因此无法使用explict接收器调用。