How to understand super when overriding method_missing? - ruby

class MyClass
def method_missing(id,*args,&block)
return A if something
return B if something_else
super
end
end
Here if neither A nor B is returned, super is called, which will raise a NoMethodError. I suppose here the super is the superclass of MyClass. However, how is NoMethodError raised since here we are solely calling super without calling the missing method along with it?

Your supposition is wrong. super is not the superclass of MyClass. It is a call of a method with the same name on the superclass of MyClass.

Related

Why private class methods are not allowed in ruby classes?

I came across this error while in development.
class ABC
def self.method_1
method_2
p "method_1"
end
private
def method_2
p "method_2"
end
end
ABC.method_1 # `method_1': undefined local variable or method `method_2' for ABC:Class (NameError)
But if I do it like this, then it works
def self.method_1
method_2
p "method_1"
end
def self.method_2
p "method_2"
end
private_class_method :method_2
end
ABC.method_1
Please help me in understanding this.
In Ruby, the default implicit receiver of a message send, if you do not explicitly specify a receiver, is self.
Also, the default definee of a method definition expression, if you do not explicitly define a definee, is the closest lexically enclosing module definition.
In your first example, method1 is defined with an explicit definee of self, which at that point in the execution is the class ABC itself. This means that method1 is a class method of class ABC, which is actually just a singleton method of ABC, which in turn is just an instance method of ABC's singleton class.
method2 is defined without an explicit definee, which means it will be defined on the default definee. The closest lexically enclosing class or module definition in this case is the class definition of ABC, so method2 is defined as an instance method of ABC.
In other words: method1 and method2 are defined in two completely different classes.
Now, when you call ABC.method1, you are sending the message method1 to the explicit receiver ABC. This works, because method1 is found in ABC's singleton class.
Inside of method1, you are calling method2 without an explicit receiver. That means, the message is sent to the implicit receiver self, which is ABC in this case. So, it is roughly equivalent (module access restrictions) to ABC.method2.
BUT there is no definition of method2 in either the singleton class of ABC er the class of ABC (which is Class) or any of its superclasses (Module, Object, Kernel, BasicObject) because method2 is defined in ABC itself.
Therefore, method2 cannot be found in the method lookup chain.
In the second example, both methods are defined in the same class, namely both methods are defined in ABC's singleton class. Therefore, method2 is in the method lookup chain when called inside of method1.
In fact, your first example is actually not substantially different from this:
class Foo
def method 1
method2
end
end
class Bar
def method2; end
end
foo = Foo.new
foo.method1
#Jorg's answer is correct, but this might be easier to read. As Jorg pointed out, the use of the "self" applies to the class object, not the specific instance of it. basically mixing and matching the "self" and not-"self" entries is hard work, and you shouldn't try to cross the streams. the "self" and non-"self" objects will act as completely different classes.
class
class ABC
def method_1
method_2
p "method_1"
end
def self.method_3
method_4
p "method_3"
end
private
def method_2
p "method_2"
end
def self.method_4
p "method_4"
end
end
output
> ABC.new.method_1
"method_2"
"method_1"
=> "method_1"
> ABC.method_3
"method_4"
"method_3"
=> "method_3"

Calling Singleton Class Methods Inside Open Singleton Class

I'm trying to understand why I can't call methods defined on the singleton class from within the open class but I can from the actual class.
Can someone explain why the first example fails and the second one doesn't?
class One
class << self
def one; end
one
end
end
NameError (undefined local variable or method 'one' for #<Class:One>)
class Two
class << self
def one; end
end
self.one
end
=> nil
Your example is more confusing than it needs to be. It doesn't require a singleton class at all:
class Foo
def bar; end
bar # NameError
end
Foo.new.bar
Here, we have a class Foo with an instance method bar. A singleton class is still just a class, so this is actually the exact same example as yours.
def without an explicit definee defines an instance method of the closest lexically enclosing class definition, in this case Foo. A message send without an explicit receiver like bar sends the message to self. Inside the class definition body, self is the class itself.
So, def bar defines an instance method in Foo, i.e. a method you can call on instances of Foo.
bar inside the class definition body sends a message to self, which is Foo. Since Foo is not an instance of itself, it does not have a method named bar, ergo, the method call fails.
This works exactly the same with a singleton class, since it is still just a class.
You made the wrong assumption about where the method belongs to, in the first place. The call to the instance method one from inside class context should not succeed. In your first snippet, you try to call method one from the singleton class of the singleton class of One (because it’s called from singleton_class context).
Example with normal class / instance methods to clarify:
class One
def self.one()
puts :class
end
def one
puts :instance
end
one()
end
#⇒ class
So, the expected behavior would be to raise NameError. Now the answer is simple: it raises NameError because this method does not exist.

Why is call to super failing here

module A
def foo
if super.respond_to? :foo
puts 'super responded to :foo'
end
end
end
class Lab
include A
end
puts Lab.ancestors.inspect #=> Lab, A, Object, Kernel, BasicObject]
Lab.new.foo
foo': super: no superclass methodfoo' for # (NoMethodError)
I was assuming that in this case the call to super would go to Object and then to BasicObject and finally false would be returned.
Why I'm getting no superclass method foo ?
I'm using ruby 1.9.3 .
Super calls the method of the same name on a parent class.
if super.respond_to? foo
That line will be calling foo on any parent class in the hierachy.
EDIT:
You probably want to do something like
self.ancestors.select{|a| a.respond_to? :foo}.size > 0
as the check.
Your code doesn't really make sense: you guard the call to super with a condition, but you are calling super in that condition anyway. In other words: you are calling super in order to determine whether it is safe to call super. Therefore, you will get an error if there is no method called foo in the ancestry chain.

When an instance method calls a class method, I have to use self.class_method?

I'm getting an error so I guess I have to reference a class method from inside of an instance method with self.class_method_name, but why is that?
Shouldn't it resolve this by itself? Confused.
def self.blah(string)
..
end
def some_method()
some_thing = blah("hello")
end
If you have
# This won't work
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This won't work
self.blah("hello")
end
end
foo = Foo.new
foo.some_method
It won't work, because it'll look for the instance method Foo#blah. Instead, you're looking for Foo.bar.
To make some_method call Foo.bar, you have to make some_method refer to the Foo class, and then call blah on it.
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This will work
self.class.blah("hello")
end
end
foo = Foo.new
foo.some_method
The reason you have def self.blah to define the method, but self.class.blah to call the method, is that in the former, self refers to the Foo class, while in the latter, self refers to the foo object, so you need self.class to refer to the Foo class.
It may be easier to think of self as part of the method name, that way it's clear that you never defined a blah method, you defined only a self.blah method. (To clarify: the previous sentence shouldn't be thought of too much, so please don't read into it, as it's not how things are actually working, just a sort of "layman's terms" attempt at describing why it doesn't work.)
Also, what if you had defined a blah instance method in addition to the class method? If calling blah was enough to access the class method, how would you call the instance method?
Finally, there really isn't any such thing as a class method in Ruby, "class methods" are really methods of the singleton class.

Ruby metaclass madness

I'm stuck. I'm trying to dynamically define a class method and I can't wrap my head around the ruby metaclass model. Consider the following class:
class Example
def self.meta; (class << self; self; end); end
def self.class_instance; self; end
end
Example.class_instance.class # => Class
Example.meta.class # => Class
Example.class_instance == Example # => true
Example.class_instance == Example.meta # => false
Obviously both methods return an instance of Class. But these two instances
are not the same. They also have different ancestors:
Example.meta.ancestors # => [Class, Module, Object, Kernel]
Example.class_instance.ancestors # => [Example, Object, Kernel]
What's the point in making a difference between the metaclass and the class instance?
I figured out, that I can send :define_method to the metaclass to dynamically define a method, but if I try to send it to the class instance it won't work. At least I could solve my problem, but I still want to understand why it is working this way.
Update Mar 15, 2010 13:40
Are the following assumptions correct.
If I have an instance method which calls self.instance_eval and defines a method, it will only affect the particular instance of that class.
If I have an instance method which calls self.class.instance_eval (which would be the same as calling class_eval) and defines a method it will affect all instances of that particular class resulting in a new instance method.
If I have a class method which calls instance_eval and defines a method it will result in a new instance method for all instances.
If I have a class method which calls instance_eval on the meta/eigen class and defines a method it will result in a class method.
I think it starts to make sense to me. It would certainly limit your possibilities if self inside an class method would point to the eigen class. If so it would not be possible to define an instance method from inside a class method. Is that correct?
Defining a singleton method dynamically is simple when you use instance_eval:
Example.instance_eval{ def square(n); n*n; end }
Example.square(2) #=> 4
# you can pass instance_eval a string as well.
Example.instance_eval "def multiply(x,y); x*y; end"
Example.multiply(3,9) #=> 27
As for the difference above, you are confusing 2 things:
The meta class defined by you, is what called in Ruby community as singelton class or eigen class. That singleton class is the class that you can add class(singleton) methods to.
As for the class instance you are trying to define using the class_instance method, is nothing but the class itself, to prove it, just try adding an instance method to the class Example and check if the class_instance method defined by you returns the class Example itself by checking the existence of that method:
class Example
def self.meta; (class << self; self; end); end
def self.class_instance; self; end
def hey; puts hey; end
end
Example.class_instance.instance_methods(false) #=> ['hey']
Anyway to sum it for you, when you want to add class methods, just add them to that meta class. As for the class_instance method is useless, just remove it.
Anyway I suggest you read this post to grasp some concepts of Ruby reflection system.
UPDATE
I suggest you read this nice post: Fun with Ruby's instance_eval and class_eval,
Unfortunately class_eval and instance_eval are confusing because they somehow work against their naming!
Use ClassName.instance_eval to define class methods.
Use ClassName.class_eval to define instance methods.
Now answering your assumptions:
If I have an instance method which
calls self.instance_eval and defines a
method, it will only affect the
particular instance of that class.
yes:
class Foo
def assumption1()
self.instance_eval("def test_assumption_1; puts 'works'; end")
end
end
f1 = Foo.new
f1.assumption1
f1.methods(false) #=> ["test_assumption_1"]
f2 = Foo.new.methods(false) #=> []
If I have an instance method which
calls self.class.instance_eval (which
would be the same as calling
class_eval) and defines a method it
will affect all instances of that
particular class resulting in a new
instance method.
no instance_eval in that context will define singleton methods(not instance ones) on the class itself:
class Foo
def assumption2()
self.class.instance_eval("def test_assumption_2; puts 'works'; end")
end
end
f3 = Foo.new
f3.assumption2
f3.methods(false) #=> []
Foo.singleton_methods(false) #=> ["test_assumption_2"]
For that to work replace instance_eval with class_eval above.
If I have a class method which calls
instance_eval and defines a method it
will result in a new instance method
for all instances.
Nope:
class Foo
instance_eval do
def assumption3()
puts 'works'
end
end
end
Foo.instance_methods(false) #=> []
Foo.singleton_methods(false) #=> ["assumption_3"]
That will make singleton methods, not instance methods. For that to work replace instance_eval with class_eval above.
If I have a class method which calls
instance_eval on the meta/eigen class
and defines a method it will result in
a class method.
well no, that will make so sophisticated stuff, as it will add singleton method to the singleton class, I don't think that will have any practical use.
If you define a method on a class, it can be invoked on its objects. It is an instance method.
class Example
end
Example.send :define_method, :foo do
puts "foo"
end
Example.new.foo
#=> "foo"
If you define a method on a metaclass, it can be invoked on the class. This is similar to the concept of a class method or static method in other languages.
class Example
def self.metaclass
class << self
self
end
end
end
Example.metaclass.send :define_method, :bar do
puts "bar"
end
Example.bar
#=> "bar"
The reason that metaclasses exist is because you can do this in Ruby:
str = "hello"
class << str
def output
puts self
end
end
str.output
#=> "hello"
"hi".output
# NoMethodError
As you can see, we defined a method that is only available to one instance of a String. The thing that we defined this method on is called the metaclass. In the method lookup chain, the metaclass is accessed first before searching the object's class.
If we replace the object of type String with an object of type Class, you can imagine why this means we're only defining a method on a specific class, not on all classes.
The differences between the current context and self are subtle, you can read more if you're interested.

Resources