From: Logan Capaldo Date: 2006-08-14T04:28:54+09:00 Subject: Module to make guerilla (monkey?) / reopening classes easier. Comments? I hammered this out today. It has some limitations (works only for classes, not modules), and when using the block only form of patch your method redefinitions are evaluated twice. I'm looking for commentary before I take the step of writing some testcases and packaging it up for human consumption: Usage: class A def b(x, y) x + y end end a = A.new require 'patch' class A include Patchable end A.patch(:b) do |y| hyper(1, y) # I only ever call b with an x argument of 1 end a.b(5) #=> 6 class B def foof yield end end class B include Patchable end B.patch do def foof hyper { yield + 1 } end end b = B.new b.foof { 3 } #=> 4 And heres the code: patch.rb: module Patchable module ClassMethods def patch(method_name = nil, &new_body) if method_name method_name = method_name.to_sym pre_patched_versions[method_name] = instance_method (method_name) define_method(method_name, &new_body) else klass = Class.new imeths = klass.instance_methods klass.class_eval(&new_body) new_meths = klass.instance_methods - imeths new_meths.each do |m| pre_patched_versions[m.to_sym] = instance_method(m) end class_eval(&new_body) end self end def pre_patched_versions @pre_patched_versions ||= {} end end def hyper(*args, &block) meth_name = caller[0][/`([^']+)'/, 1].to_sym self.class.pre_patched_versions[meth_name].bind(self).call (*args, &block) end def self.included(other) other.extend(ClassMethods) end end