Method Namespace

I have need for a general purpose simple namespace construction. Not
selector namespaces, mind you, just a method namespace. I made the
following attempt. So close! But it fails b/c if a method is already
defined in the class and the namespace module being added also has a
method of the same name they will clash. I worked around it by aliasing
the method with a temporary name then realiasing it to the original
name. This words EXCEPT when super is called in the method (see the
test case a the bottom).

Anone have any better ways of implementing?

Thanks,
T.

namespace.rb

require ‘facet/functor’
require ‘facet/module/basename’

class Module

# Define a simple namespace.
#
#   class A
#     attr_writer :x
#     namespace :inside do
#       def x; @x; end
#     end
#   end
#
#   a = A.new
#   a.x = 10
#   a.inside.x #=> 10
#   a.x  # no method error

def namespace( mod, &blk )

  # If block is given then create a module, othewise
  # get the name of the module.
  if block_given?
    name = mod.to_s
    mod  = Module.new(&blk)
  else
    name = mod.basename.downcase
    mod  = mod.dup
  end

  # We have to work around name clashes.
  nameclashes = mod.instance_methods & instance_methods
  nameclashes.each do |n|
    alias_method "#{n}:namespace", n
  end

  # Include the module. This is neccessary, otherwise
  # Ruby won't let us bind the instance methods.
  include mod

  # Undefine the instance methods of the module.
  mod.instance_methods.each{ |m| undef_method m }

  # Redefine the methods that clashed.
  nameclashes.each do |n|
    alias_method n, "#{n}:namespace"
    undef_method "#{n}:namespace"
  end

  # Add a method for the namespace that delegates
  # via the Functor to the module instance methods.
  define_method(name) do
    Functor.new(mod) do |op, base, *args|
      base.instance_method(op).bind(self).call(*args)
    end
  end
end

end

begin test

require ‘test/unit’

class TestNamespace1 < Test::Unit::TestCase

module M
  def x; "x"; end
end

class C
  namespace M
end

def test_01
  c = C.new
  assert_equal('x', c.m.x)
end

def test_02
  c = C.new
  assert_raises(NoMethodError){ c.x }
end

end

class TestNamespace2 < Test::Unit::TestCase

class B
  def x; 1; end
end

class C < B
  def x; super; end
  namespace :m do
    def x; "x"; end
  end
end

def test_01
  c = C.new
  assert_equal('x', c.m.x)
end

# THIS FAILS !!!
def test_02
  c = C.new
  assert_equal(1, c.x)
end

end

Trans schrieb:

I have need for a general purpose simple namespace construction.

This words EXCEPT when super is called in the method (see the
test case a the bottom).

Tom, could you try this version?

def namespace( mod, &blk )

 # If block is given then create a module, otherwise
 # get the name of the module.
 if block_given?
   name = mod.to_s
   mod  = Module.new(&blk)
 else
   name = mod.basename.downcase
   mod  = mod.dup
 end

 # Include the module. This is neccessary, otherwise
 # Ruby won't let us bind the instance methods.
 include mod

 # Save the instance methods of the module and
 # replace them with a "transparent" version.
 methods = {}
 mod.instance_methods(false).each do |m|
   methods[ m.to_sym ] = mod.instance_method(m)
   mod.instance_eval do
     define_method(m) do
       super
     end
   end
 end

 # Add a method for the namespace that delegates
 # via the Functor to the saved instance methods.
 define_method(name) do
   Functor.new(methods) do |op, mtab, *args|
     mtab[op].bind(self).call(*args)
   end
 end

end

Regards,
Pit

Pit C. wrote:

   name = mod.basename.downcase
 mod.instance_methods(false).each do |m|
 define_method(name) do
   Functor.new(methods) do |op, mtab, *args|
     mtab[op].bind(self).call(*args)
   end
 end

end

Bloody hek, that’s a clever solution. Works like a charm. Pit Captain,
you never cease to amaze! I’m putting this in Facets to replace the
weak SimpleDelegtor I had been using.

Thanks!
T.