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

L

Logan Capaldo

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top