# Module to make guerilla (monkey?) / reopening classes easier

**URL:** <https://www.ruby-forum.com/t/module-to-make-guerilla-monkey-reopening-classes-easier/64802>\
**Category:** Ruby\
**Created:** [August 15, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/module-to-make-guerilla-monkey-reopening-classes-easier/64802 "2006-08-15T14:19:11Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Logan\_C](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/e47774/32.png) [@Logan\_C](https://www.ruby-forum.com/u/Logan_C)\
**Post date:** [August 15, 2006, 2:19pm UTC](https://www.ruby-forum.com/t/module-to-make-guerilla-monkey-reopening-classes-easier/64802/1 "2006-08-15T14:19:11Z")

</div>

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
