Skip to content

Instantly share code, notes, and snippets.

@Peeja
Created July 23, 2014 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Peeja/5f662e1bf769817ec2c4 to your computer and use it in GitHub Desktop.
Save Peeja/5f662e1bf769817ec2c4 to your computer and use it in GitHub Desktop.
module AliasMethodChainResilient
# Give us a module which will intercept attempts to alias methods named in
# the keys of method_aliases, and instead alias the methods named in the
# values of method_aliases.
def self.alias_intercepting_module(method_aliases)
Module.new do
define_method :alias_method do |new_name, old_name|
if method_aliases.key?(old_name.to_sym)
super new_name, method_aliases[old_name.to_sym]
else
super new_name, old_name
end
end
end
end
def prepend_features(base)
method_aliases = instance_methods.each_with_object({}) do |method_name, aliases|
aliases[method_name] = :"__#{method_name}_before_#{self.name}"
base.send :alias_method, aliases[method_name], method_name
end
base.singleton_class.send :prepend, AliasMethodChainResilient.alias_intercepting_module(method_aliases)
super
end
end
module M
# Without this, we'll get a NoMethodError in Ruby 2.0, and a SystemStackError
# in 2.1. With it, things work as expected.
extend AliasMethodChainResilient
def do_it
puts "M"
super
end
end
class C
def do_it
puts 'C'
end
prepend M
def do_it_with_amc
puts 'amc'
do_it_without_amc
end
alias_method :do_it_without_amc, :do_it
alias_method :do_it, :do_it_with_amc
end
C.new.do_it
# Output, with AliasMethodChainResilient
# M
# amc
# C
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment