Mauricio Fern?ndez <batsman.geo / yahoo.com> wrote in message news:<20040122095123.GA18582 / student.ei.uni-stuttgart.de>...
> 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
> 
 
Cool.  A good example of how just about any new feature that someone
thinks of can often be implemented in Ruby without requiring a change
to the language itself.

Oh, and I also thought it was about time to change the subject name on
this thread: I don't think Ruby has 'bad fame' (as in "The Infamous
Ruby").  I find that those who have heard of Ruby usually have heard
good things about it and if they have heard negatives those
perceptions are often out of date.

Phil