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.



26
27
28
29
30
31
32
# File 'lib/multimethod/table.rb', line 26

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

  # Type name lookup cache
  @name_to_object = { }
end

Instance Attribute Details

#debugObject

Enable debugging info.



23
24
25
# File 'lib/multimethod/table.rb', line 23

def debug
  @debug
end

#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.



156
157
158
159
160
161
# File 'lib/multimethod/table.rb', line 156

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.



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

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.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/multimethod/table.rb', line 85

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



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

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.



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/multimethod/table.rb', line 139

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.



169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/multimethod/table.rb', line 169

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.



128
129
130
131
132
133
# File 'lib/multimethod/table.rb', line 128

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