From: Mauricio Fernandez Date: 2006-08-29T17:26:25+09:00 Subject: Re: Partial append_features? On Tue, Aug 29, 2006 at 03:26:58PM +0900, Ola Bini wrote: > Logan Capaldo wrote: > >% cat Projects/Ruby Experiments/append_from.rb > >class Module > > def append_from( mod, *methods_to_keep ) > > methods_to_keep.map! { |m| m.to_s } > > methods_to_remove = mod.instance_methods(false) - methods_to_keep > > new_mod = Module.new > > new_mod.module_eval do > > include mod > > methods_to_remove.each { |meth| undef_method meth } > > end > > include new_mod > > end > >end > > > > Thank you for writing it up for me. This was more or less what I had in > mind of writing up myself. This solution is definitely the best for me, > since the methods I want to keep is a small subset compared to how many > to remove, and the ones to remove will grow with time. The above code effectively removes inherited methods too (as well as those from other modules that were included previously): class Module def append_from( mod, *methods_to_keep ) methods_to_keep.map! { |m| m.to_s } methods_to_remove = mod.instance_methods(false) - methods_to_keep new_mod = Module.new new_mod.module_eval do include mod methods_to_remove.each { |meth| undef_method meth } end include new_mod end end module A; def foo; "A#foo" end end module B def foo; "B#foo" end def bar; "B#bar" end end class X; include A end x = X.new x.foo # => "A#foo" class X; append_from B, :bar end x.bar # => "B#bar" x.foo # => # ~> -:24: undefined method `foo' for # (NoMethodError) In this example, #undef_method has blocked A#foo too. Here's another way to do it without clobbering inherited methods; the key difference is that the original module will not be added to the inheritance chain: RUBY_VERSION # => "1.8.5" RUBY_RELEASE_DATE # => "2006-08-25" class Module def append_from(mod, *methods) methods.map!{|x| x.to_s} m = mod.clone m.module_eval do (instance_methods(false) - methods).each{|x| remove_method x } end include m end end module A; def foo; "A#foo" end end module B def foo; "B#foo" end def bar; "B#bar" end end class X; include A end x = X.new x.foo # => "A#foo" class X; append_from B, :bar end x.bar # => "B#bar" x.foo # => "A#foo" X.ancestors # => [X, #, A, Object, Kernel] ==================== B(') is missing in the inheritance chain -- Mauricio Fernandez - http://eigenclass.org - singular Ruby