Reputation: 99
being reading some codes of self used in ruby, still can not figure out some examples:
class A
def hi
"hi"
end
def self.hello
"hello"
end
end
a=A.new
a.hi
A.hello
understand I can use below to change instance method def:
class << a
def hi
"hi from a <<"
end
end
a.hi => "hi from a <<"
but what is this?
class << a
def self.hello
"H E L L O"
end
end
[21] pry(main)> A.hello
=> "hello"
[22] pry(main)> a.hello
<<ERROR1>> NoMethodError: undefined method `hello' for #<A:0x007fe41338ecb8>
and I am not really sure what I am doing here actually.
and what is difference between the definition
class << a
def hi
"hi from a <<"
end
end
and
class << A
def hi
"hi from a <<"
end
end
?
----------------------question added a little further----------------------
class A
p "in class A: #{self}, type: #{self.class}"
def f
p "in f: #{self}, type: #{self.class}"
end
def self.m
p "in selfm: #{self}, type: #{self.class}"
end
end
metaclass = class << a;self;end
metaclass.instance_eval do
"hi : #{self}, type: #{self.class}"
def f7
"in f7 .. : #{self}, type: #{self.class}"
end
def self.f9
"in f7 .. : #{self}, type: #{self.class}"
end
end
A.f7
a.f7
A.f9
a.f9
<<ERROR2>>
[20] pry(main)> A.f9
NoMethodError: undefined method f9' for A:Class
from (pry):40:in
pry'
[21] pry(main)> a.f9
NoMethodError: undefined method f9' for #<A:0x007fb70717c0d0>
from (pry):41:in
pry'
<<ERROR3>>
[22] pry(main)>
[23] pry(main)> A.f7
NoMethodError: undefined method f7' for A:Class
from (pry):42:in
pry'
[24] pry(main)> a.f7
NoMethodError: undefined method f7' for #<A:0x007fb70717c0d0>
from (pry):43:in
pry'
[25] pry(main)> A.f9
NoMethodError: undefined method f9' for A:Class
from (pry):44:in
pry'
[26] pry(main)> a.f9
NoMethodError: undefined method f9' for #<A:0x007fb70717c0d0>
from (pry):45:in
pry'
Can you help pin point what exactly these errors are: refer to <> mark
Does it make any sense to define self.method in an object, if not, why there is no warring/error? if it make sense, what does it mean for a self.method for an object?
>, why f7 is not callable using both A's class and object?
>, why f9 is not callable using both A's class and object?
A little more for discussion:
<>
class A
def self.f1
"f1"
end
def self.f2(&block)
(class << self; self; end).instance_eval do
define_method("f1", &block)
end
end
def self.f3(&block)
m=(class << self; self; end)
m.instance_eval do
define_method("f1", &block)
end
end
def self.f4(&block)
m=(class << self; self; end)
m.instance_eval do
def f1
"f4 is called"
end
end
end
def self.f5(&block)
m=(class << self; self; end)
m.instance_eval do
def f1
"f5 is called"
end
end
end
end
Seems I am little closer to the truth now, here's final one need to get the magic revealed:
If I do
A.f2 do
"f2 is called"
end
A.f1
A.f3 do
"f3 is called"
end
A.f1
I am able to overwrite the f1 method with either A.f2 or A.f3 call, however if I directly def method in instance_eval block, it won't achieve the same goal, what's the difference here?
A.f4
A.f1
A.f5
A.f1
the A.f1 still returns "f1". What I found is that if you use the def, then the method is defined and tied with eigen class instance, if you use define_method, the method then is tied with class A as static method.
What's the difference here between the usage of define_method and def ?
Upvotes: 1
Views: 223
Reputation: 4986
The questions you are asking here is really about the basics of how classes, methods, and objects work within Ruby.
What you have going on is really just the difference between class
methods and instance
methods.
An instance
method means in the most basic sense that the method can only be called from the level of an instantiated object.
This is what you see with your syntax here.
class A
def hi
"hi"
end
end
In this case the method hi
is an instance method of class A
and so we must instantiate an object to call it. To avoid confusion between casing a vs A I will use foo
instead of a
foo = A.new
foo.hi
Now we have just created an instance
foo of A
and as such we can call the method hi
on foo.
Next we have class
methods, or methods that can be called at the level of the class. In Ruby there are multiple syntaxes to achieve this, with all of the following being semantically equivalent.
class A
def self.hello
"hello"
end
end
class A
def A.hello
"hello"
end
end
class A
class << self
def hello
"hello"
end
end
end
Now one of the nice things about the last version that uses class << self
is that we can define multiple methods in that section. I go back and forth between the last two methods above depending on what I'm doing and almost never use the first version, but this is just personal preference.
Now, up to this point, everything I have said is pretty much Ruby's implementation of standard OO class/method definition and similar concepts are going to be found in any other OO language you have used C++, Java, C#, etc...
The last piece where you were confused is where Ruby steps into the idea of metaclasses or as they are typically referred to in Ruby as "eigenclasses".
What this basically means is that there is a class that you do not define that exists between the class and the instance. This is a bit confusing; read here for more clarity (http://en.wikipedia.org/wiki/Metaclass).
But what this allows us to do is define methods directly on an instance so the methods exist only on that instance and not on other instances of the class.
This is where the syntax below comes in.
class << foo
def hi
"hi from foo"
end
end
Now the method hi
has been overridden only for the instance foo
. This can also be used to define completely new methods that only exist on the instance. For example
class << foo
def bar
"bar"
end
end
Now if we instantiate a new instance of A
b = A.new
The method bar
does not exist on b; it only exists on the instance foo
.
Upvotes: 3