Hi Erik,

Nice write-up. A couple of thoughts...

I think pre_ and post_condition is a bit, um... non-Rubyish, I guess is
the best way to put it. I don't think the reciever of the wrap should
be an argument. Instead just let it be ther reciever of the pre_ call.
For example Instead of:

  def def_types(*types)
    pre_condition(Module, :method_added) do |*args|
    ...

try

  def def_types(*types)
    Module.pre_condition(:method_added) do |*args|
    ...

Yes, that would mean the pre_ methods are public, but does it matter
since that's what you're doing anyway. Of course you could always use
#send too.

Also, #wrap_method seems like it could do with some simplification.
Taking that to the furthest case, is their a reason the the following
definition isn't enough?

  def wrap_method( sym, &blk )
    raise ArgumentError, "method does not exist" unless
method_defined?( sym )
    old = instance_method(sym)
    define_method(sym) { |*args| blk.call(old.bind(self), *args) }
  end

Thanks,
T.