Temporarily Suppress or Replace a Method on a Ruby Object
You probably shouldn't do this for real, but it's a neat trick that I seriously considered using to get around validations on an associated ActiveRecord model.
class Suppress
def initialize method
@method_name = method.to_sym
end
def self.method_named method
new method
end
def on_object object, &block
@object ||= object
@original_method ||= @object.method(@method_name).unbind
if block_given?
method = block
else
method = Proc.new { puts "suppressed" }
end
@object.define_singleton_method(@method_name) do
method.call
end
self
end
def empower
method = @original_method.bind(@object)
@object.define_singleton_method(@method_name) do
method.call
end
end
end
if $0 == __FILE__
require 'ostruct'
a = OpenStruct.new(:our_method => "The default return value")
puts a.our_method
x = Suppress.method_named(:our_method).on_object(a)
puts a.our_method
x.on_object(a) { puts "our own return value" }
puts a.our_method
x.empower
puts a.our_method
end
# Output...
# The default return value
#
# suppressed
#
# our own return value
#
Notice that we can use the Suppress
object to replace, or suppress, any method on the target object.
The magic is in the use of the Method#unbind method, which literally gives us a proc that's been disassociated from the original object, allowing us to save it for later and then bind
the original object to a new method instance, using the old method as a receiver (yes, that's a little confusing I know). Then we simply define_singleton_method
on the original object, calling the newly bound instance of the original method.
Written by James Martin
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Ruby
Authors
Related Tags
#ruby
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#