In the following code include module is used. The way I see it if include module is removed then also an instance method would be created. Then why user include module ?
http://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations.rb#L1416
include Module.new {
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def destroy # def destroy
super # super
#{reflection.name}.clear # posts.clear
end # end
RUBY
}
For example, when you have a module whose sole purpose is to basically do one single (probably large) task, and the coding is getting unruly (although it’s difficult to define “unruly”), the code itself may be simplified and easier maintained by going into a class module instead of a standard module.
The Module#module_eval is the equivalent of Module#class_eval for modules $> post.add_comment ("Very nice !") => ["Very nice !"] We said that class_eval is used for adding methods and attributes to an existing class. And module_eval is used for adding methods and attributes to an existing modules. But this is just a convention..
Finally, module_ {eval|exec} is the same as the corresponding class_ {eval|exec}, but they are slightly different from instance_ {eval|exec} as they change what is the current opened class (i.e. what will be affected by def) in different ways:
When to use Class Modules in VBA. When you have one module that crunches a lot of code to do one particular task, likely the module only really has one main entry (one public sub/function that’s called), usually with a rather long list of arguments, most of which are probably optional, set with a default.
First of all let's make one thing clear. When they call super
inside the class_eval
— it has absolutely nothing to do with why they used include Module.new {}
thing. In fact the super
which was called inside the destroy
method is completely irrelevant to answering your question. There could be any arbitrary code inside that destroy method.
Now that we got it out of the way, here's what's going on.
In ruby, if you simply define a class method, and then define it again in the same class, you will not be able to call super
to access the previous method.
For example:
class Foo
def foo
'foo'
end
def foo
super + 'bar'
end
end
Foo.new.foo # => NoMethodError: super: no superclass method `foo' for #<Foo:0x101358098>
This makes sense, because the first foo
was not defined in some superclass, or anywhere up the lookup chain (which is where super
points). However, you can define the first foo
in such a way that when you later overwrite it — it will be available by calling super
. This is exactly what they wanted to achieve with doing module include.
class Foo
include Module.new { class_eval "def foo; 'foo' end" }
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
This works, because when you include a module, ruby inserts it into the lookup chain. This way you can subsequently call super
in the second method, and expect the included method to be called. Great.
However, you may wonder, why not simply include a module without all the tricks? Why are they using block syntax? We know that my above example is exactly equivalent to the following:
module A
def foo
'foo'
end
end
class Foo
include A
def foo
super + 'bar'
end
end
Foo.new.foo # => "foobar"
So why didn't they do that? The answer is — the call to reflection
. They needed to capture the variable (or method) which was available in the current context, which is reflection
.
Since they are defining the new module using block syntax, all the variables outside of the block are available for usage inside the block. Convenient.
Just to illustrate.
class Foo
def self.add_foo_to_lookup_chain_which_returns(something)
# notice how I can use variable something in the class_eval string
include Module.new { class_eval "def foo; '#{something}' end" }
end
end
# so somewhere else I can do
class Foo
add_foo_to_lookup_chain_which_returns("hello")
def foo
super + " world"
end
end
Foo.new.foo # => "hello world"
Neat, huh?
Now let me stress it again. The call to super
inside of the destroy
method in your example has nothing to do with any of the above. They called it for their own reasons, because maybe the class where this is happening is subclassing another class which already defined destroy
.
I hope this made it clear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With