Daniel DeLorme wrote:
end
Firetruck.class_eval{ include FastFiretruck }
That only works because there is no initialize method defined in
Firetruck. You might as well have done:
class Firetruck
def initialize(*args)
super
self.extend FastFiretruck
end
end
module FastFiretruck
def put_out_fire(options = {})
super({:fast => “please!”}.merge(options))
end
end
If you’re just after one method you can alway use Facets’
module#wrap_method. If you want to do aspecting (is that what this
“monkeypatching” is all about?), well I would love to see a Cut
implementation, but short of that, I’ve been working on
#instance_interception. It still has some kinks, but it essentially
works.
class Module
def instance_interception(&block)
@instance_interception ||= Module.new do
def self.append_features(mod)
append_features_without_instance_interception( mod )
end
end
@instance_interception.module_eval(&block) if block_given?
@instance_interception
end
private :instance_interception
alias_method :append_features_without_instance_interception,
:append_features
Append features
def append_features( mod )
aspect = instance_interception
aspect.__send__( :append_features_without_instance_interception,
mod )
aspect.instance_methods.each do |meth|
if mod.method_defined?( meth )
aspect.advise( mod, meth )
end
end
append_features_without_instance_interception( mod )
#if mod.instance_of? Module
aspect.__send__( :append_features_without_instance_interception,
mod.send(:instance_interception) )
#end
end
Apply the around advice.
def advise( mod, meth )
advice = instance_method( meth )
instance_target = mod.instance_method(meth)
mod.send( :define_method, meth ) { |*args| #, &blk|
target = instance_target.bind( self )
(class << target; self; end).class_eval { define_method( :super
){ call( *args ) } }
advice.bind( self ).call( target, *args ) #, &blk )
}
end
If a method is added to the module/class that is advised.
def method_added( meth )
return if @method_added_short
if instance_interception.method_defined?( meth )
include instance_interception
@method_added_short = true
instance_interception.advise( self, meth )
@method_added_short = false
end
end
end
EXAMPLE
module A
def f ; “F” ; end
def g ; “G” ; end
instance_interception do
def f( target, *args, &blk )
‘{’ + target.super + ‘}’
end
def g( target, *args, &blk )
‘{’ + target.super + ‘}’
end
end
end
class X
def f ; super ; end
include A
def g ; super ; end
end
x = X.new
p x.f
p x.g
T.