Please consider the following code:
module MyClass
def foo
"method"
end
end
now, I can instantiate a new class of this by usual
#my_new_class = MyClass.new
or, I can do some meta-programming magic
#my_new_class = Class.new { include MyClass }.send :new
Questions is what is the difference between the two?
The code above is (almost) equivalent to:
MyNewClass = Class.new { include MyClass }
#my_new_class = MyNewClass.new
Which is like
class MyNewClass
include MyClass
end
#my_new_class = MyNewClass.new
using Class.new declares an anonymous new class on the fly:
Creates a new anonymous (unnamed) class with the given superclass (or Object if no parameter is given). You can give a class a name by assigning the class object to a constant.
If a block is given, it is passed the class object, and the block is evaluated in the context of this class using class_eval.
Your naming of the module is akin to sue = Boy.new, so I've changed it to befit its heritage. I trust you won't mind.
module MyModule
def foo
"method"
end
end
Let's first gather some basic information:
Module.class #=> Class
Module.ancestors #=> [Module, Object, Kernel, BasicObject]
Module.methods.include? :new #=> true
Module.new #=> #<Module:0x000001022050c8>
As you see, Module is an instance of Class and has a method :new. Now let's look at the module you created:
MyModule.class #=> Module
MyModule.ancestors #=> [MyModule]
MyModule.instance_methods #=> [:foo]
MyModule.methods.include? :new #=> false
It is an instance of Class and has just one instance method (:foo), which you created. It has no ancestors, so it does not inherit any methods. Importantly, instances of Module do not have a method :new. If we try to invoke it, therefore, the results are predictable:
my_new_module = MyModule.new
#=> NoMethodError: undefined method `new' for MyModule:Module
End of story for approach #1`.
Now gather information related to your second approach:
my_new_instance = Class.new { include MyModule }.send :new
I've changed the name of the variable my_new_class to my_new_instance, for reasons that will soon become apparent. We can write this in two steps, like this:
Class1 = Class.new { include MyModule }
Class1.instance_methods.include? :foo #=> true
Class1.methods.include? :new #=> true
Class1.method(:new).owner #=> Class
So we confirm Class1 was constructed properly, has the instance method :foo and inherits the class method :new from Class.
my_new_instance = Class1.new #=> #<Class1:0x00000101a1edc8>
my_new_instance = Class1.send :new #=> #<Class1:0x0000010204eab8>
my_new_instance.class #=> Class1
my_new_instance.is_a? Class #=> false
my_new_instance.foo # (prints) "method"
my_new_instance.send :foo # (prints) "method"
We see that my_new_instance is indeed an instance of Class1 (which can be created by either of the methods shown), and invokes :foo in either of the two ways shown.
Related
I am very confused about this. In Programming Ruby book, it says,
"receiver checks for the method definition in its own class"
So class object stores all instance methods. Then why can't I call
instance method from within a class?
For example
Class ExampleClass
def example_method
end
example_method
end
I cannot call example_method inside ExampleClass.
However if I define a method in top level like this:
class ExampleClass
def example_method
end
end
def example_method1
end
example_method1
Then I can call top level method example_method1.
Isn't top level also a class? How come it is different than
a calling instance method from within ExampleClass?
The biggest reason that you cannot call that function in the way that you have written it is that it is, as you say, an instance method.
Try defining it in this way:
class ExampleClass
def self.class_method
puts "I'm a class method"
end
class_method
end
I believe you will find that you have a different result. It's not that it's "Top Level", it's whether or not it's in scope for what you're dealing with. Since you're dealing with a class, a class method would be necessary. If you're dealing with an object (an instantiated class) it's a different "scope".
Those "global" methods are an exception. They are defined as private instance methods of Object. Everything inherits from Object, so these methods are "globally" visible.
p self.class # => Object
p self.private_methods.sort # => [:Array, :Complex, ... :using, :warn] # all (?) from Kernel module
def aaaa
end
p self.private_methods.sort # => [:aaaa, :Array, ... :using, :warn]
The receiver checks for the method definition in its own class. The receiver is ExampleClass. The class of ExampleClass is Class. There is no example_method method in the Class class, ergo, you get a NoMethodError.
I'll try to explain it as follows.
class MyClass
def self.my_method
puts "Me, I'm a class method. Note that self = #{self}"
end
def my_method
puts "Me, I'm an instance method. Note that self = #{self}"
end
# I'm about to invoke :my_method on self. Which one will it be?"
# "That depends on what self is now, of course.
puts "self = #{self}"
# OK. It's MyClass. But wait. I'm just defining the set now.
# Do the methods I defined above even exist yet?
# Does the class exist yet? Let's find out.
print "class methods: "
puts self.methods(false)
print "instance methods: "
puts self.instance_methods(false)
# Cool! Let's try invoking my_method
my_method
# It worked. It was the class method because self = MyClass
# Now let's see if we can create an instance of the class before
# we finish defining the class. Surely we can't.
my_instance = new
puts "my_instance = #{my_instance}"
# We can! Now that's very interesting. Can we invoke the
# instance method on that instance?
my_instance.my_method
# Yes!
end
The following is printed while the class is being defined:
self = MyClass
class methods: my_method
instance methods: my_method
Me, I'm a class method. Note that self = MyClass
my_instance = #<MyClass:0x007fd6119125a0>
Me, I'm an instance method. Note that self = #<MyClass:0x007fd6119125a0>
Now let's confirm the methods can be invoked from outside the class. There should be no surprises here:
MyClass.my_method
#-> Me, I'm a class method. Note that self = MyClass
my_instance = MyClass.new
my_instance.my_method
#-> Me, I'm an instance method. Note that self = #<MyClass:0x007fd61181d668>
I want to define a constant for a single instance of an object, not for all instances of an object.
class MyTest
def call
Foo
end
end
t = MyTest.new
t.call # => NameError (as expected)
t.singleton_class.class_eval do
const_set 'Foo', 'foo'
end
t.singleton_class::Foo # => 'foo'
t.call # => NameError
Why does the const lookup not include the const defined in the objects singleton class?
Here is another attempt:
Dog = Class.new { def call; Bark; end }
d = Dog.new
d.call # => NameError (expected)
d.singleton_class.const_set('Bark', 'woof')
d.call # => NameError (not expected)
The constant has been defined in the instance's singleton class but Foo doesn't include (singleton_class)::Foo in one of its possible evaluations so specify it explicitly:
class MyTest
def call
singleton_class::Foo
end
end
I believe it is not possible:
const_set is defined on Module
Ruby looks for constant in nesting and ancestors
There is no place where to define the constant for a MyTest instance
class MyTest
def call
puts (Module.nesting + Module.ancestors).uniq.inspect
end
end
MyTest.new.call
# => [MyTest, Module, Object, Kernel, BasicObject]
I think this comment is correct - t.singleton_class.class_eval first gets the singleton_class of t and then evals something on that singleton classes' class.
Instead what you want is to define the constant on the instance of that singleton class, like so:
t.singleton_class.instance_eval do
Foo = 'foo'
end
After that, t.call returns "foo".
Start be creating an arbitrary set and an instance of that set.
class A; end
a = A.new
#=> #<A:0x00007ff0bbaa9f98>
For convenience, assign a's singleton class1 to a variable.
as = a.singleton_class
#=> #<Class:#<A:0x00007ff0bbaa9f98>>
Create a constant in as whose value equals 3.
as.const_set(:A, 3)
#=> 3
Check that the constant was defined.
as.constants
#=> [:A]
Let's check its value also.
as.const_get(:A)
#=> 3
Now let's create a method in as that references the constant we've created.
as.define_method(:cat) { puts "#{as.const_get(:A)} cats"}
#=> :cat
Try it.
a.cat
#=> "3 cats"
See Module#const_set and Module#const_get.
1. Every Ruby object has a singleton class. Singleton classes are like regular classes except they cannot be subclassed and one cannot create instances of subclasses.
I am learning some metaprogramming and I was stuck trying to find a method. Let's say I have the following class:
class MyClass
def self.my_method
end
def your_method
end
end
With the following code I can search for each method in the object space:
type = Class
name = /^my_method$/
result = ObjectSpace.each_object(type).select do |o|
o.instance_methods(false).grep(name).size > 0 || o.methods.grep(name).size > 0
end
p result
And it finds it showing the following output:
[MyClass]
As the searcher code also searches for instance methods, it shows the same output when looking for your_method.
Even with if I add a singleton method to an object:
mc = MyClass.new
def mc.our_method
end
Just changing the searcher like this:
type = Object
name = /^our_method$/
result = ObjectSpace.each_object(type).select do |o|
o.methods.grep(name).size > 0
end
p result
It also finds it:
[#<MyClass:0x8f86760>]
The question is, how do I find a method defined in the top level object? This method:
def hidden
end
Besides, which is the current class when defining a method like this?
Which is the current class when defining a method like this?
We can easily figure out what object we’re in by inspecting self in this top level scope:
self #=> main
self.class #=> Object
So we’re not in a Class, but an instance of Object which is dubbed “main”.
How do I find a method defined in the top level object?
This is where it gets interesting. The top-level scope object in Ruby behaves specially, but it’s relatively easy to discover where a method here defined lives:
def foo; :bar; end
method(:foo).owner #=> Object
Object.new.foo #=> NoMethodError: private method `foo' called
Object.new.send(:foo) #=> :bar
So methods defined at the top-level are made (private*) instance methods of Object. The reason your ”searcher” cannot find it is because these methods are private, and neither methods nor instance_methods include private methods, instead you need private_methods and private_instance_methods:
Object.instance_methods.include?(:foo) #=> false
Object.private_instance_methods.include?(:foo) #=> true
* Note that Pry (at least v0.10.1) alters this to make methods defined at top-level in its REPL public.
If you had this:
def my_method() end
class A
def self.my_method() end
end
class B < A
def my_method() end
end
class C
def my_method() end
end
and wanted to find methods named 'my_method' that you've created, you could do this:
ObjectSpace.each_object(Class).select do |o|
o.instance_methods(false).include?(:my_method)
end
#=> [C, B]
ObjectSpace.each_object(Class).select do |o|
o.methods(false).include?(:my_method)
end
#=> [A]
ObjectSpace.each_object(Class).select do |o|
o.private_instance_methods(false).include?(:my_method)
end
#=> [Object]
class Invoice
def Invoice.generate(order_id, charge_amount, credited_amount = 0.0)
Invoice.new(:order_id => order_id, :amount => charge_amount, :invoice_type => PURCHASE, :credited_amount => credited_amount)
end
end
Why would you create Invoice.generate inside Invoice class rather than self.generate?
self.generate is easier to work with, whereas Invoice.generate is arguably more explicit. Other than that, there's no difference between the two.
Explanation
You can define a method on any instance using this form
def receiver.method(args)
end
Check this out
class Foo
end
def Foo.bar
"bar"
end
Foo.bar # => "bar"
And yes, I mean any instance. It's absolutely possible that one instance has some method while another doesn't
f = Foo.new
def f.quux
'quux'
end
f2 = Foo.new
f.quux # => "quux"
f2.quux # => # ~> -:20:in `<main>': undefined method `quux' for #<Foo:0x007fe4e904a6c0> (NoMethodError)
A reminder: inside of class definition (but outside of method definitions) self points to that class.
class Foo
# self is Foo
end
So, armed with this knowledge, the difference between self.generate and Invoice.generate should be obvious.
Under normal circumstances, it would practically have no difference from def self.generate.
The only edge case I can think of is if you have a nested class with the same name, then the explicit version would apply only to the nested class.
class A
def self.x
name
end
def A.y
name
end
class A
# nested class A::A
end
def self.p
name
end
def A.q
name
end
end
> A.x # => "A"
> A.y # => "A"
> A.p # => "A"
> A.q # => NoMethodError: undefined method `q' for A:Class
> A::A.q # => "A::A"
As you see, after a nested class with the same name is defined, subsequent explicit class method definitions made with the class name refer to the nested class, but explicit definitions made beforehand refer to the original.
Implicit definitions made with self always refer to the base class.
You have 2 ways for defining a class method.
1) You can use the name of the class directly
class Test #Test is now an instance of a built-in class named Class
def Test.class_method
"I'm a class method."
end
end
2) You can use the self variable, which is always pointing to the current object
class Test
def self.class_method
"I'm a class method."
end
end
Once you understand that classes are objects, this use of the self variable to define a class method finally makes sense.
The value of self
Not too surprinsingly, when you are inside a class method, the value of self refers to the object that holds the class structure (the instance of class Class). This means that :
class Test
def self.class_method
self.x
end
end
is equivalent to :
class Test
def self.class_method
Test.x
end
end
When you are inside an instance method, the value of self still refers to the current object. This time however, the current object is an instance of class Test, not an instance of class Class.
More info. : http://www.jimmycuadra.com/posts/self-in-ruby
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.