Method: Module#method_space

Defined in:
lib/core/facets/module/method_space.rb

#method_space(name, mod = nil, &blk) ⇒ Object

Create method namespaces, allowing for method chains but still accessing the object’s instance.

class A
  attr_writer :x
  method_space :inside do
    def x; @x; end
  end
end

a = A.new
a.x = 10
a.inside.x  #=> 10

expect NoMethodError do
  a.x
end

NOTE: This method is not a common core extension and is not loaded automatically when using require 'facets'.

CREDIT: Pit Captain

Uncommon:

  • require ‘facets/module/method_space’



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
# File 'lib/core/facets/module/method_space.rb', line 32

def method_space(name, mod=nil, &blk)

  ## If block is given then create a module, otherwise
  ## get the name of the module.
  if block_given?
    name = name.to_s
    raise ArgumentError if mod
    mod  = Module.new(&blk)
  else
    if Module === name
      mod = name
      name = mod.basename.downcase
    end
    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.module_eval %{
      def #{m}(*a,&b)
        super(*a,&b)
      end
    }
    ##mod.instance_eval do
    ##  define_method(m)
    ##    super
    ##  end
    ##end
  end

  ## Add a method for the namespace that delegates
  ## via the Functor to the saved instance methods.
  define_method(name) do
    mtab = methods
    Functor.new do |op, *args|
      if meth = mtab[op.to_sym]
        meth.bind(self).call(*args)
      else
        #self.__send__(op, *args)
        raise NoMethodError, "undefined method `#{m}'"
      end
    end
  end
end