Reputation: 34135
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?
Upvotes: 0
Views: 4497
Reputation: 110675
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.
Upvotes: 1
Reputation: 37409
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
.
Upvotes: 5