How do you extend a Ruby module with macro-like metaprogramming methods?
- by Ian Terrell
Consider the following extension (the pattern popularized by several Rails plugins over the years):
module Extension
def self.included(recipient)
recipient.extend ClassMethods
recipient.class_eval { include InstanceMethods }
end
module ClassMethods
def macro_method
puts "Called macro_method within #{self.name}"
end
end
module InstanceMethods
def instance_method
puts "Called instance_method within #{self.object_id}"
end
end
end
If you wished to expose this to every class, you can do the following:
Object.send :include, Extension
Now you can define any class and use the macro method:
class FooClass
macro_method
end
#=> Called macro_method within FooClass
And instances can use the instance methods:
FooClass.new.instance_method
#=> Called instance_method within 2148182320
But even though Module.is_a?(Object), you cannot use the macro method in a module:
module FooModule
macro_method
end
#=> undefined local variable or method `macro_method' for FooModule:Module (NameError)
This is true even if you explicitly include the original Extension into Module with Module.send(:include, Extension).
How do you add macro like methods to Ruby modules?