23
loading...
This website collects cookies to deliver better user experience
first_person.valid?
, Ruby has to determine a few things:.valid?
is defined..valid?
method is defined? If so, which is the right one to use in this context.prepend
, include
, or extend
. When this happens, the class has access to the methods defined in the modules, and Ruby goes into the modules to search for the method that has been called. It's also important to know that other modules can be mixed into the initial modules, and the search also progresses into these.class Human
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
hello
method that we have created above on instances of the Human
class; for example,john = Human.new("John")
john.hello # Output -> Hello John
hello
method is an instance method; this is why we can call it on instances of the Human
class. There might be cases where we do not want the method to be called on instances. In these cases, we want to call the method on the class itself. To achieve this, we'll have to create a class method. Defining a class method for the class we have above will look like this:def self.me
puts "I am a class method"
end
Human.me
. As the complexity of our application grows (imagine we're building a new start-up here), there might come a time when two or more of our classes have multiple methods that do the same thing. If this happens, it means we need to keep things dry and make sure that we do not repeat ourselves. The issue involves how we share functionality across these classes.module Movement
def walk
puts "I can walk!"
end
end
module
keyword instead of class
.Movement.new
.[2, 3, 4]
assigned to a variable called numberList
, the .push
method is an action that can be performed by the array to put the value it receives into the array. This code snippet is an example:john.walk
john
references an object that is an instance of Human
, and walk
is the method. However, this isn't completely true because the inferred method tends to come from the object's class, superclass, or mixed-in module.john
, because everything is an object in Ruby, even a class used in creating objects.def john.drip
puts "My drip is eternal"
end
drip
method can only be accessible by the object assigned to john
. drip
is a singleton method that will be available to the john
object. It is important to know that there's no difference between singleton methods and class methods, as you can see from this Stack Overflow answer. Unless you're referring to a method defined on an object like in the example above, it would be incorrect to say that the method belongs to a certain object. In our example, the walk
method belongs to the Movement
module, while the hello
method belongs to the Human
class. With this understanding, it will be easier to take this a step further, which is that to determine the exact method that is being called on an object, Ruby has to check the object's class or super class or modules that have been mixed in the object's hierarchy.walk
method available to instances of the Human
class, we can mix in the Movement
module in the Human
class. So, a rewrite of the Human
class using include
will look like this:require "movement" # Assuming we have the module in a file called movement.rb
class Human
include Movement
attr_reader :name
def initialize(name)
@name = name
end
def hello
put "Hello! #{name}"
end
end
walk
method on the instance:john = Human.new("John")
john.walk
Human
class, such that the Movement
module can be seen as a parent of the Human
class. As you can see in the example we shown above, we've called the walk
method on the instance of the Human
class.Feeding
that looks likemodule Feeding
def food
"I make my food :)"
end
end
Human
class by requiring it and adding extend Feeding
. However, to use it, instead of calling the food
method on the instance of the class, we'll call it on the class itself, the same way we call class methods.Human.food
It actually works like include, except that instead of inserting the module between the class and its superclass in the chain, it will insert it at the bottom of the chain, even before the class itself.
What it means is that when calling a method on a class instance, Ruby will look into the module methods before looking into the class.
hello
method that we then mix into the Human
class by using prepend
, Ruby will call the method we have in the module instead of the one we have in the class.prepend
works, I suggest taking a look at this article.module One
def another
puts "From one module"
end
end
module Two
def another
puts "From two module"
end
end
module Three
def another
puts "From three module"
end
end
class Creature
def another
puts "From creature class"
end
end
Human
class.class Human < Creature
prepend Three
extend Two
include One
def another
puts "Instance method"
end
def self.another
puts "From Human class singleton"
end
end
Human
class is a subclass of the Creature
class.Human.another
, what gets printed is From Human class singleton
, which is what we have in the class method. If we comment out the class method and run it again, it will print From two module
to the console. This comes from the module we mixed in using extend
. It goes to show that the lookup begins among singleton methods. If we remove (or comment out) extend Two
and run the command again, this will throw a method missing error. We get this error because Ruby could not find the another
method among the singleton methods.n = Human.new
def n.another
puts "From n object"
end
n.another
, the version that gets called is the singleton method defined on the n
object. The reason Ruby won't look call the module mixed in using extend
in this case is because we're calling the method on the instance of the class. It is important to know that singleton methods have a higher relevance than methods involving modules mixed in using extend
.n
object and run the command, the version of the method that gets called is the module we mixed in using prepend
. This is because the use of prepend
inserts the module before the class itself.Three
, the version of the another
method that gets called is the instance method defined on the class.include
. So, when we comment out the instance method, the version we get is that which is in module One
.Creature
class, the method will get called..ancestors
on the class. Doing this for the Human
class will return [Three, Human, One, Creature, Object, Kernel, BasicObject]
. The search for a method ends at the BasicObject
class, which is Ruby's root class. Every object that is an instance of some class originated from the BasicObject
class.Object
classKernel
moduleBasicObject
classNoMethodError
, which happens when you attempt to an unknown method on an object. This happens after Ruby has gone through the ancestors of the object and could not find the called method. The error message you receive is handled by the method_missing
method, defined in the BasicObject
class. It is possible to override the method for the object you're calling the method on, which you can learn about by checking this.