From: Robert Dober Date: 2008-09-02T03:20:44+09:00 Subject: Re: Undo Object.extend On Mon, Sep 1, 2008 at 3:39 PM, José Ignacio wrote: Maybe you want to use pushable behavior class Behavior attr_reader :block def initialize &blk @block = blk end end module Kernel def Behavior &blk Behavior::new &blk end end class Module def empty?; instance_methods.empty? end def empty!; instance_methods.each do |im| remove_method im end end end module Pushable CannotPopException = Class::new RuntimeError ArgumentError = Class::new ::ArgumentError def pop_behavior @__bsp__ -= 1 raise CannotPopException, "empty entity #{self}" if @__bsp__ < 0 @__behavior_stack__[@__bsp__].empty! end def push_behavior *behaviors, &blk @__behavior_stack__ ||= [] @__bsp__ ||= 0 raise ArgumentError, "push_behavior takes at least one behavior or block" if behaviors.empty? and blk.nil? behaviors.each do |behavior| _push_behavior behavior end _push_behavior blk if blk self end private def _push_behavior behavior m = @__behavior_stack__[@__bsp__] @__behavior_stack__ << ( m = Module::new ) unless m include m rescue extend m # this is autoprotected against double inclusion; so finally turns out it is a feature ;) m.empty! m.module_eval &(behavior.block rescue behavior) @__bsp__ += 1 end end # module Pushable class << Pushable def new *args, &blk c = Class::new( *args, &blk ) c.extend self c end end # class << Pushable class << PushableModule = Module::new def new *args, &blk m = Module::new( *args, &blk ) m.extend Pushable m end end ------------------------------------ 8< See these test cases to learn more about how to use this: o = Object.new o.extend Pushable b = Behavior do def a; 42 end end o.push_behavior b assert_equal 42, o.a o.pop_behavior assert_raise NoMethodError do o.a end HTH Robert -- C'est véritablement utile puisque c'est joli. Antoine de Saint Exupéry