Class: Multimethod::Table

Inherits:
Object
  • Object
show all
Defined in:
lib/multimethod/table.rb

Overview

Represents a Multimethod repository.

There is typically only one instance.

It provides the interface to the core extensions.

Constant Summary collapse

@@instance =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*opts) ⇒ Table

Creates a new Table object.



23
24
25
26
27
28
29
# File 'lib/multimethod/table.rb', line 23

def initialize(*opts)
  @multimethod_by_name = { }
  @multimethod = [ ]

  # Type name lookup cache
  @name_to_object = { }
end

Instance Attribute Details

#multimethodObject

A list of all Multimethod objects.



20
21
22
# File 'lib/multimethod/table.rb', line 20

def multimethod
  @multimethod
end

Class Method Details

.instanceObject

Returns the current instance or creates a new one.



12
13
14
15
16
# File 'lib/multimethod/table.rb', line 12

def self.instance
  # THREAD CRITICAL BEGIN
  @@instance ||= self.new
  # TRREAD CRITICAL END
end

Instance Method Details

#dispatch(name, rcvr, args) ⇒ Object

Dispatches to the appropriate Method based on name, receiver and arguments.



153
154
155
156
157
158
# File 'lib/multimethod/table.rb', line 153

def dispatch(name, rcvr, args)
  unless mm = @multimethod_by_name[name]
    raise NameError, 'No method for multmethod #{name}' unless mm
  end
  mm.dispatch(rcvr, args)
end

#find_method(x) ⇒ Object

Returns a list of all the Methods that match a signature.

The signature can be a String, Method or Signature object.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/multimethod/table.rb', line 101

def find_method(x)
  case x
  when String
    signature = Signature.new(:string => x)
  when Method
    signature = x.signature
  when Signature
    signature = x
  end

  x = @multimethod.select{|mm| mm.matches_signature(signature)}
  # $stderr.puts "find_method(#{x}) => #{x.inspect}"
  x = x.collect{|mm| mm.find_method(signature)}.flatten

  # $stderr.puts "find_method(#{x}) => #{x.inspect}"
  x
end

#find_multimethod(x) ⇒ Object

Returns the Multimethods that matches a signature. The signature can be a String, Method or Signature object.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/multimethod/table.rb', line 82

def find_multimethod(x)
  case x
  when String
    signature = Signature.new(:string => x)
  when Method
    signature = x.signature
  when Signature
    signature = x
  end

  x = @multimethod.select{|mm| mm.matches_signature(signature)}

  x
end

#install_method(mod, body, file = nil, line = nil) ⇒ Object

Installs a new Multimethod Method using the multimethod syntax:

class A
  multimethod q{
    def foo(x)
      ...
    end
  }
  multimethod q{
    def foo(A x)
    end
  }
end

Interface to Multimethod::Module mixin multimethod



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
# File 'lib/multimethod/table.rb', line 47

def install_method(mod, body, file = nil, line = nil)
  file ||= __FILE__
  line ||= __LINE__
  verbose = nil
  #if body =~ /def bar\(x, y\)/
  #  verbose = 1
  #end

  # Parse the signature from the method body
  signature = Signature.new
  signature.mod = mod
  signature.verbose = verbose
  signature.file = file
  signature.line = line
  new_body = signature.scan_string(body.clone)
  
  # Get our Multimethod for this
  mm = lookup_multimethod(signature.name)
  mm.install_dispatch(mod)
  m = mm.new_method_from_signature(signature)

  # Replace the multimethod signature with a plain Ruby signature.
  new_body = m.to_ruby_def + new_body

  #if true || m.signature.restarg
  #   $stderr.puts "install_method(#{mod}) => #{m.to_ruby_signature}:\n#{new_body}"
  #end

  # Evaluate the new method body.     
  mod.module_eval(new_body, file, line)
end

#lookup_multimethod(name) ⇒ Object

Returns a Multimethod object for a method name.

Will create a new Multimethod if needed.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/multimethod/table.rb', line 136

def lookup_multimethod(name)
  name = name.to_s

  # THREAD CRITICAL BEGIN
  unless mm = @multimethod_by_name[name]
    mm = Multimethod.new(name)
    mm.table = self
    @multimethod_by_name[name] = mm
    @multimethod << mm
  end
  # THREAD CRITICAL END

  mm
end

#name_to_object(name, scope = nil, file = nil, line = nil) ⇒ Object

Returns the object for name, using the appropriate evaluation scope.



166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/multimethod/table.rb', line 166

def name_to_object(name, scope = nil, file = nil, line = nil)
  scope ||= Kernel
  # THREAD CRITICAL BEGIN
  unless x = (@name_to_object[scope] ||= { })[name]
    # $stderr.puts " name_to_object(#{name.inspect}) in #{scope}"
    x = 
      @name_to_object[scope][name] = 
      scope.module_eval(name, file || __FILE__, line || __LINE__)
  end
  # THREAD CRITICAL END

  x
end

#remove_method(signature) ⇒ Object

Removed the Method that match a signature.

The signature can be a String, Method or Signature object.

Raises an error if more than one Method is found.



125
126
127
128
129
130
# File 'lib/multimethod/table.rb', line 125

def remove_method(signature)
  x = find_method(signature)
  raise("Found #{x.size} multimethods: #{x.inspect}") if x.size > 1
  x = x[0]
  x.multimethod.remove_method(x)
end