A pure Ruby implementation is unfortuately far from ideal. Nonetheless
their are some appraoches that get close. Below I give one that I
developed awhile back. Also I believe Mauricio Fernandez has done some
expirementation on this too. Perhaps he has some ideas.
---- cut.rb ----
# Cut, Transparent Subclass
# Copyright (c) 2004 Thomas Sawyer
# cut.rb
#
# == Notes
#
# This implementation uses a single transparent subclass, the
ProxyCut,
# into which module mixins are included. This essentially works
# and allows cuts to be somewhat dynamic. But it does not follow the
# formal design of cuts which uses multiple transparent subclasses,
# not mixins.
#
# This implementation suffers from the dynamic module inclusion
problem.
# Due to the nature of module inclusion this is a somewhat serious
# limitation. The upshot of this is that cuts can only be defined on
# a class up to the point of instantiation. Adding subsequent cuts
# will not effect already instantiated objects. Thus all cuts to be
used
# must be defined before instantiation.
#
# = Class
#
class Class
alias_method :anew, :new
def new(*args, &blk)
proxycut.anew(*args, &blk)
end
def proxycut
@proxycut ||= ProxyCut.new(self)
end
private

roxycut
def cuts
proxycut.ancestors.select{ |a| a.is_a?(Cut) }
end
def preclude( mod )
proxycut.class_eval { include mod }
end
# this finds the nearest cut which lacks a specified method
def clearcut(meth)
#acuts = cut.ancestors.select{ |a| a.is_a?(Cut) }
r = cuts.reverse.detect{|a| !
a.instance_methods.include?(meth.to_s) }
return r
end
def wrap( meth, &meth_proc )
c = clearcut( meth )
c = Cut.new( self ) if ! c
c.send( :define_method, meth, &meth_proc )
return c
end
end
#
# = ProxyCut
#
class ProxyCut
def self.new(supclass)
Class.anew(supclass) #do
# this seems to cause problems
#alias_method :real_class, :class
#define_method

class) { supclass }
#end
end
end
#
# = Cut
#
class Cut < Module
attr :superclass
def initialize(superclass, &block)
class_eval(&block) if block_given?
@superclass = superclass
s = self
@superclass.send

proxycut).class_eval{ include s }
end
end
#
# = Kernel
#
module Kernel
def cut(cut_name, klass, &block)
self.class.module_eval { const_set( cut_name, Cut.new(klass,
&block) ) }
end
end
# ---- primative test ----
if __FILE__ == $0
class C
def m1; "X"; end
end
# cut A < C
A = Cut.new(C) do
def m1; "<" + super + ">"; end
end
# cut B < C
# cut B,C do
B = Cut.new(C) do
def m1; "[" + super + "]"; end
end
c = C.new
puts c.m1
p C.clearcut

t)
p c.class
end