module SailCat
Object.send :include, self
Module.send :include, self
def singleton_class
class << self; self; end
end
def define_alias_method(symbol, manner = :alter, *arg, &block)
in_class = self.is_a?(Class)
attr_sym = in_class ? :instance_method : :method
def_sym = in_class ? :class_eval : :eval
old = send(attr_sym, symbol)
old_n = old.arity
old_n = ~old_n if old_n < 0
if block_given?
(in_class ? self : singleton_class).send :define_method, symbol, &block
new = send(attr_sym, symbol)
else
new = send(attr_sym, arg[-1])
arg = arg[0..-2]
end
s_new = "new#{in_class ? '.bind(self)' : ''}.call(*args)"
s_old = "old#{in_class ? '.bind(self)' : ''}.call(*old_args)"
case manner
when :before
method_eval = "#{s_new}; #{s_old}"
when :after
method_eval = "v = #{s_old}; #{s_new}; v"
when :alter
method_eval = "#{s_old}; #{s_new}"
when :around
method_eval = s_new.sub(/\*args/) {s_old[0..-17] + ", *args"}
when :inherit
method_eval = s_new.sub(/\*args/) {s_old + ", *args"}
when :if
method_eval = "#{s_new} if v = #{s_old}; v"
when :unless
method_eval = "#{s_new} unless v = #{s_old}; v"
when :and
method_eval = "#{s_new} and #{s_old}"
when :or
method_eval = "#{s_new} or #{s_old}"
end
context = in_class ? "self" : "singleton_class"
send def_sym, %(#{context}.send :define_method, symbol do |*args|
old_args = args[0, old_n] + arg; #{method_eval}
end)
end
end
module A
def self.b(a, b = 6)
a + b
end
def self.b2
0
end
define_alias_method(:b, :around) {|b, x| p x, b.call(x, 9); }
define_alias_method(:b, :before, 4) { p 1 }
define_alias_method(:b, :alter, :b2)
define_alias_method(:b, :inherit) {|b, x| p b - x}
end
A.b(5) #=> 1/4, 13/-5