What purpose could anonymous modules in a Ruby app serve? The concept itself is easy to grasp, but I can't imagine any reason that you'd ever use such a thing. What problem do they solve?
There is a more general principle at work here.
Phil Karlton famously said: "There are only two hard problems computer science: cache invalidation and naming things." So, naming things is hard. Which means that if we can get away with not naming a thing, we should do it!
Or, if you look at it from a different perspective: if naming things is hard, then giving something a name means that thing is important. But sometimes, there are things in our programs which aren't important and thus aren't worthy of a name.
This is not unique to Ruby modules. You could ask the question about any anonymous concept, and in fact, the question does get asked all the time. When C# 2.0 introduced anonymous methods, people asked why one would ever want to use a method without a name, when C# 3.0 introduced anonymous lambdas (and anonymous types), people asked why one would ever want to use them. Python's anonymous functions are severely restricted compared to Python's named functions, and the Python community asks why one would ever need full-blown anonymous functions. Of course, we, as Ruby programmers are so used to lightweight (blocks) and fully reified (Proc
s) anonymous functions that we can't understand why one would ever not want to use one.
Java has anonymous classes since 1.1 and anonymous lambdas since 8. Basically, anonymous "things" are everywhere and they are useful, especially for quick one-off usage.
For example, if you just want to wrap some existing method, without going through the hassle of alias_method
(which you really shouldn't use any more for that problem, Module#prepend
now exists and is a much better solution), you could do:
class Array
prepend(Module.new do
def [](*)
puts 'Before-hook'
super.tap { puts 'After-hook' }
end
end)
end
p [42][0]
# Before-hook
# After-hook
# => 42
This is a Rails specific answer, it's not about anonymous modules in general.
Being able to call super
when overriding generated methods.
Given a module that creates methods:
module Generator
def generate_method(name)
define_method(name) do
"I am #{name}"
end
end
end
Calling generate_method
from within a class creates a new instance method:
class MyClass
extend Generator
generate_method :foo
end
MyClass.new.method(:foo) #=> #<Method: MyClass#foo>
Invoking the method works as expected:
MyClass.new.foo #=> "I am foo"
But you can't easily alter foo
:
class MyClass
def foo
super.upcase
end
end
MyClass.new.foo #=> no superclass method `foo'
If our generator uses an anonymous module to define the methods within:
module Generator
def generate_method(name)
generated_methods.module_eval do
define_method(name) do
"I am #{name}"
end
end
end
def generated_methods
@generated_methods ||= begin
mod = Module.new
include(mod)
mod
end
end
end
We get:
class MyClass
extend Generator
generate_method :foo
end
MyClass.new.method(:foo) #=> #<Method: MyClass(#<Module:0x007fbd29833658>)#foo>
And altering foo
now works as expected:
class MyClass
def foo
super.upcase
end
end
MyClass.new.foo #=> "I AM FOO"
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