I have a module lets call "Calculator" that I want to include in a class "Product". Calculator will extend "Product" which will copy the class methods onto Product. One of these class methods is "memoize". The idea being that I can do something like this:
module Calculator
def self.extended(base)
base.memoize :foo_bar
end
end
With the purpose of memoizing the method (specifically a class method) :foo_bar. Inside of memoize I call the method "alias_method" which attempts to alias a class method to a different name (here :foo_bar). This fails. Memoize looks something like:
module Calculator (the extended module)
def memoize(name)
alias_method "memoized_#{name}", name
end
end
When this is called via memoize :foo_bar, the alias_method line kicks an error saying Product has no method "name".. my understanding is this is because alias_method will attempt to alias instance methods not class methods.. (I don't know why but ok no big deal)..
I can reopen the eigenclass like so
module Calculator
def memoize(name)
class << self
alias_method "memoized_#{name}", name
end
end
end
This would work but name is not available to the scope of the class << self definition. People have mentioned using self.class_eval and self.instance_eval but neither of these seem to work.. I'd like my cake and eat it too.. how can I keep alias_method dynamic but use it on class_methods?
So just learned that this will do the trick:
module Calculator
def memoize
define_singleton_method(name, method(name))
end
end
Then when Calculator gets included in Product it will define the singleton method as I needed. I still don't know why alias_method needs to only work on instance methods.. and I don't know why class_eval or instance_eval didn't solve the problem.. but at least I have a solution..
What if you put the instance method to be aliased before the include/extend? If you're putting the extend right after the class name, the instance method will not yet have been defined.
module Foo
def self.extended(base)
base.memoize :flavor
end
def memoize(name)
alias_method "memoized_#{name}", name
end
end
class Bar
def flavor
puts "Orange"
end
extend Foo
end
if __FILE__==$0
b = Bar.new
b.memoized_flavor #=> Orange
end
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