Created
October 28, 2011 02:52
-
-
Save forforf/1321516 to your computer and use it in GitHub Desktop.
Unbind, destroy and recreate a method at runtime. Meta-programming goodness
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#This captures the Array#sort method and stores it in m | |
m = Array.instance_method(:sort) | |
#Shows that sort still works | |
[3,2,1].sort | |
#=> [1,2,3] | |
#Here we override the array sort method | |
#Array#sort no longer works | |
[3,2,1].class.send(:define_method, :sort){nil} | |
[3,2,1].sort | |
#=> nil | |
#Here's where we attach the original sort back | |
#to an array object | |
new_sort = nil | |
[3,2,1].tap{|me| new_sort = m.bind(me).call} | |
#=> [1,2,3] | |
#Breaking it down | |
# Because tap returns itself, we need to | |
# declare a variable to capture the output | |
# of the function modifying itself | |
# new_sort = nil | |
# Use tap to get a reference to the object | |
# [3,2,1].tap{|me| ... me is [3,2,1] here ...} | |
# Bind the original sort method to the current object | |
# m.bind(me) | |
# call the bound original sort method and assign | |
# the result to the variable we initialized | |
# new_sort = m.bind(me).call | |
# Ed. note: Verify and clean up to be more clear and concise | |
# this is *almost* the equivalent of calling me.sort | |
# the difference is that in this case the method is not | |
# permanently bound to the object, as the block doing the | |
# binding doesn't persist. | |
# new_sort now contains the result of applying the method | |
#We can put improve tap now | |
class Object | |
def tapout(block) | |
ret_val = nil | |
self.tap{|me| ret_val = block.call(me)} | |
ret_val | |
end | |
end | |
[5,3,1].respond_to? :tapout | |
#=> true | |
wrap_sort = lambda{|o| m.bind(o).call} | |
[5,3,1].tapout(wrap_sort) | |
#=> [1,3,5] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment