-->

Ruby: NoMethodError, but why?

2020-06-03 09:30发布

问题:

I was working on a simple Pi Generator while learning Ruby, but I kept getting NoMethodError on RubyMine 6.3.3, so I decided to make a new project and new class with as simple as possible, and I STILL get NoMethodError. Any reason?

class Methods
  def hello (player)
    print "Hello, " << player
  end
  hello ("Annie")
end

And the error I get is:

C:/Users/Annie the Eagle/Documents/Coding/Ruby/Learning Environment/methods.rb:5:in `<class:Methods>': undefined method `hello' for Methods:Class (NoMethodError)

回答1:

You have defined an instance method and are trying to call it as a method of a class. Thus you need to make the method hello a class method, not an instance method of the class Methods.

class Methods
  def self.hello(player)
    print "Hello, " << player
  end
  hello("Annie")
end

Or, if you want to define it as instance method then call it as below :

class Methods
  def hello(player)
    print "Hello, " << player
  end
end
Methods.new.hello("Annie")


回答2:

You're trying to call an instance method as a class method.

Here's some code that illustrates the difference between the two in ruby:

class Person

  # This is a class method - note it's prefixed by self
  # (which in this context refers to the Person class)
  def self.species
    puts 'Human'
    # Note: species is OK as a class method because it's the same 
    # for all instances of the person class - ie, 'Bob', 'Mary', 
    # 'Peggy-Sue', and whoever else, are ALL Human.
  end

  # The methods below aren't prefixed with self., and are
  # therefore instance methods

  # This is the construct, called automatically when
  # a new object is created
  def initialize(name)
    # @name is an instance variable
    @name = name
  end

  def say_hello
    puts "Hello from #{@name}"
  end

end

And now try it out, calling the methods...

# Call a class method...
# We're not referring to any one 'instance' of Person,
Person.species #=> 'Human'

# Create an instance
bob = Person.new('Bob')

# Call a method on the 'Bob' instance
bob.say_hello #=> 'Hello from Bob'

# Call a method on the Person class, going through the bob instance
bob.class.species #=> 'Human'

# Try to call the class method directly on the instance
bob.species #=> NoMethodError

# Try to call the instance method on the class
# (this is the error you are getting)
Person.say_hello #=> NoMethodError


回答3:

You've created an instance method, but you're calling a class method. In order to call hello("Annie"), you have to make an instance of Methods. For instance:

class Methods
  def self.hello(player)
      print "Hello, " << player
  end
end

my_method = Methods.new
my_method.hello("Annie")

This would output Hello, Annie



回答4:

By defining a method with def method_name args you are defining a instance method that will be included in every object of that class, but not in the class itself.

On the other hand, by def self.method_name args you will get a class method that will be directly in the class, without the need of instanciate an object from it.

So If you have this:

Class Test
   def self.bar
   end

   def foo
   end

end

You can execute the instance method this way:

a = Test.new
a.foo

And as for the class one should be:

Test.foo