From: "Mauricio Fernández" Date: 2004-01-22T18:51:32+09:00 Subject: Re: Fighting Ruby's bad fame On Thu, Jan 22, 2004 at 10:04:51AM +0900, Gavin Sinclair wrote: > > That is a feature I would definitely like to see in Ruby ('include' > having an effect local to the enclosing block, or whatever the Would the 'new include' work like the current one, i.e. using a proxy class (so that the return value of Module#ancestors changes), or are you rather thinking of a way to use singleton methods from another module/object? That is, is the feature you're thinking of only related to the namespace in a scope or does it involve something more complex such as several per-object namespaces? > terminology should be). Must remember to raise an RCR. batsman@tux-chan:/tmp$ expand -t2 c.rb require 'test/unit' # scoped singleton method import # # using(ModWithSingletons, someobject) do # blah # runs ModWithSingletons.blah or someobject.blah if it cannot be # # resolved with self # end # # can be nested but is not thread-safe def using(*modules) ## this doesn't propagate the block :-( #klass = class << self; self end #klass.module_eval{ alias_method :_method_missing_, :method_missing } #klass.send(:define_method,:method_missing) do |meth,*args| # begin # _method_missing_ meth, *args # rescue NameError # modules.each do |m| # return m.send(meth, *args) if m.respond_to? meth # end # raise # end #end @_using_modules_ ||= [] @_level_ ||= 0 @_level_ += 1 old = @_using_modules_ @_using_modules_ = modules + @_using_modules_ if @_level_ == 1 class << self alias_method :_method_missing_, :method_missing def method_missing(meth, *args, &block) begin _method_missing_ meth, *args, &block rescue NameError @_using_modules_.each do |m| return m.send(meth, *args, &block) if m.respond_to? meth end raise end end end end begin yield ensure @_level_ -= 1 if @_level_ == 0 class << self alias_method :method_missing, :_method_missing_ end end @_using_modules_ = old end end class TC_using < Test::Unit::TestCase module Blah; def self.foo; "Blah.foo" end end module Foo; def self.foo; "Foo.foo" end end module Bar def self.bar; "Bar.bar" end def self.baz; yield end end def test_single_module assert_equal("Foo.foo", using(Foo){ foo }) assert_equal("Blah.foo", using(Blah){ foo }) end def test_several_modules assert_equal("Foo.foo", using(Foo,Blah){foo}) assert_equal("Blah.foo", using(Blah,Foo){foo}) end def test_call_with_block assert_equal("Bar.baz", using(Bar){baz{"Bar.baz"}}) end def test_nested assert_equal("Blah.foo", using(Foo){using(Blah){foo}}) using(Foo) do assert_equal("Blah.foo", using(Blah){foo}) assert_equal("Foo.foo", foo) end end def test_namerror assert_raises(NameError) { using(Foo){ jurl } } end end batsman@tux-chan:/tmp$ ruby c.rb Loaded suite c Started ..... Finished in 0.003045 seconds. 5 tests, 9 assertions, 0 failures, 0 errors -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Apples have meant trouble since eden. -- MaDsen Wikholm, mwikholm@at8.abo.fi