File: namespace.rb

package info (click to toggle)
ruby-facets 2.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 9,824 kB
  • sloc: ruby: 25,483; xml: 90; makefile: 20
file content (169 lines) | stat: -rw-r--r-- 2,777 bytes parent folder | download
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