Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I remove a method alias in Ruby?

Suppose I've got a section of Ruby code where I'd like to alias a method (I don't know why; let's just suppose I have a good reason).

class String
    alias_method :contains?, :include?
end

Would it be possible for me, after this section, to remove this alias?

like image 929
Dan Tao Avatar asked Jul 12 '12 17:07

Dan Tao


2 Answers

remove_method should work in most cases. But if your alias_method overwrites an existing method, you may need to save the original via a separate alias_method call.

# assuming :contains? is already a method 
alias_method :original_contains?, :contains?
alias_method :contains?, :include?

Then to restore the original state:

alias_method :contains?, :original_contains?
remove_method :original_contains?  # optional

Note also that modifying a class that's used in multiple threads is prone to race conditions. And if you're trying to disallow libs from using the alias, you can't prevent that if you're calling those libs' methods while the alias exists. We might see a way to do this in ruby 2.0: http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice/

It would be helpful if you could say why you want to remove the alias. If the method name did not exist before, no other libs should be affected by your monkey-patch. Also, you should consider subclassing String (or delegating to a string instance) rather than patching String.

like image 92
Kelvin Avatar answered Sep 19 '22 22:09

Kelvin


def hello
   puts "Hello World"
end
alias :hi :hello

hi #=> "Hello World"
undef hi
hi #=> NameError
hello #=> "Hello World"

EDIT: Note that this will only work on methods created on the main object. In order to enact this on a class, you'd need to do something like , Hello.class_eval("undef hi")

However, from a metaprogramming standpoint, when dealing with classes, I like the usage of remove_method :hi since it'll cause the method lookup to fall down and grab the method from a parent class.

class Nums < Array
   def include?
      puts "Just Kidding"
   end
end

n = Nums.new
n << 4 #=> [4]
n.include? #=> "Just kidding"
Nums.class_eval("remove_method :include?")
n.include? 4 #=> true
Number.class_eval("undef include?")
n.include? 4 #=> NoMethodError

remove_method is much more meta friendly.

like image 25
Charles Caldwell Avatar answered Sep 18 '22 22:09

Charles Caldwell