Let say we have classes A,B,C.
A
def self.inherited(sub)
# meta programming goes here
# take class that has just inherited class A
# and for foo classes inject prepare_foo() as
# first line of method then run rest of the code
end
def prepare_foo
# => prepare_foo() needed here
# some code
end
end
B < A
def foo
# some code
end
end
C < A
def foo
# => prepare_foo() needed here
# some code
end
end
As you can see I am trying to inject foo_prepare()
call to each one of foo()
methods.
How can that be done?
Also I have been thinking about overriding send
class in class A
that way I would run foo_prepare
and than just let send
(super) to do rest of the method.
What do you guys think, what is the best way to approach this problem?
Here's a solution for you. Although it's based on module inclusion and not inheriting from a class, I hope you will still find it useful.
module Parent
def self.included(child)
child.class_eval do
def prepare_for_work
puts "preparing to do some work"
end
# back up method's name
alias_method :old_work, :work
# replace the old method with a new version, which has 'prepare' injected
def work
prepare_for_work
old_work
end
end
end
end
class FirstChild
def work
puts "doing some work"
end
include Parent # include in the end of class, so that work method is already defined.
end
fc = FirstChild.new
fc.work
# >> preparing to do some work
# >> doing some work
I recommend Sergio's solution (as accepted). Here is what I did which fit my needs.
class A
def send(symbol,*args)
# use array in case you want to extend method covrage
prepare_foo() if [:foo].include? symbol
__send__(symbol,*args)
end
end
or
class A
alias_method :super_send, :send
def send(symbol,*args)
prepare_foo() if [:foo].include? symbol
super_send(symbol,*args)
end
end
As of Ruby 2.0 you can use 'prepend' to simplify Sergio's solution:
module Parent
def work
puts "preparing to do some work"
super
end
end
class FirstChild
prepend Parent
def work
puts "doing some work"
end
end
fc = FirstChild.new
fc.work
This allows a module to override a class's method without the need for alias_method.
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