1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
require 'facets/more/functor'
module Namespace
#
def namespace(name, &block)
define_method(name) do
Functor.new do |op, *args|
send("#{name}:#{op}",*args)
end
end
begin
@namespace = name
module_eval &block
ensure
@namespace = nil
end
end
#
def method_added(name)
return if @method_being_added
if @namespace
@method_being_added = true
alias_method "#{@namespace}:#{name}", name
undef_method name
@method_being_added = false
end
end
end
class X
extend Namespace
def initialize(x)
@x = x
end
namespace :m do
def x ; @x; end
end
end
x = X.new(6)
p x.m.x
p x.x
exit
require 'facets/more/functor'
require 'facets/core/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
def test_02
c = C.new
assert_equal(1, c.x)
end
end
=end
|