multimethod 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.svn/README.txt +2 -0
- data/.svn/empty-file +0 -0
- data/.svn/entries +68 -0
- data/.svn/format +1 -0
- data/.svn/text-base/ChangeLog.svn-base +3 -0
- data/.svn/text-base/Manifest.txt.svn-base +54 -0
- data/.svn/text-base/README.txt.svn-base +40 -0
- data/.svn/text-base/Rakefile.svn-base +132 -0
- data/.svn/text-base/Releases.txt.svn-base +7 -0
- data/ChangeLog +3 -0
- data/Manifest.txt +54 -0
- data/README.txt +40 -0
- data/Rakefile +132 -0
- data/Releases.txt +7 -0
- data/examples/.svn/README.txt +2 -0
- data/examples/.svn/empty-file +0 -0
- data/examples/.svn/entries +22 -0
- data/examples/.svn/format +1 -0
- data/examples/.svn/props/ex1.rb.svn-work +5 -0
- data/examples/ex1.rb +26 -0
- data/lib/.svn/README.txt +2 -0
- data/lib/.svn/empty-file +0 -0
- data/lib/.svn/entries +24 -0
- data/lib/.svn/format +1 -0
- data/lib/.svn/text-base/multimethod.rb.svn-base +8 -0
- data/lib/multimethod.rb +8 -0
- data/lib/multimethod/.svn/README.txt +2 -0
- data/lib/multimethod/.svn/empty-file +0 -0
- data/lib/multimethod/.svn/entries +53 -0
- data/lib/multimethod/.svn/format +1 -0
- data/lib/multimethod/.svn/text-base/core_extensions.rb.svn-base +38 -0
- data/lib/multimethod/.svn/text-base/method.rb.svn-base +232 -0
- data/lib/multimethod/.svn/text-base/multimethod.rb.svn-base +171 -0
- data/lib/multimethod/.svn/text-base/parameter.rb.svn-base +64 -0
- data/lib/multimethod/.svn/text-base/table.rb.svn-base +99 -0
- data/lib/multimethod/core_extensions.rb +38 -0
- data/lib/multimethod/method.rb +232 -0
- data/lib/multimethod/multimethod.rb +171 -0
- data/lib/multimethod/parameter.rb +64 -0
- data/lib/multimethod/table.rb +99 -0
- data/test/.svn/README.txt +2 -0
- data/test/.svn/empty-file +0 -0
- data/test/.svn/entries +53 -0
- data/test/.svn/format +1 -0
- data/test/.svn/text-base/method_test.rb.svn-base +89 -0
- data/test/.svn/text-base/multimethod_test.rb.svn-base +92 -0
- data/test/.svn/text-base/parameter_test.rb.svn-base +31 -0
- data/test/.svn/text-base/test_base.rb.svn-base +25 -0
- data/test/.svn/text-base/usage_test.rb.svn-base +146 -0
- data/test/method_test.rb +89 -0
- data/test/multimethod_test.rb +92 -0
- data/test/parameter_test.rb +31 -0
- data/test/test_base.rb +25 -0
- data/test/usage_test.rb +146 -0
- metadata +108 -0
data/Releases.txt
ADDED
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<wc-entries
|
3
|
+
xmlns="svn:">
|
4
|
+
<entry
|
5
|
+
committed-rev="4"
|
6
|
+
name=""
|
7
|
+
committed-date="2006-11-21T16:23:41.780783Z"
|
8
|
+
url="svn+ssh://rubyforge.org/var/svn/multimethod/multimethod/trunk/examples"
|
9
|
+
last-author="kstephens"
|
10
|
+
kind="dir"
|
11
|
+
repos="svn+ssh://rubyforge.org/var/svn/multimethod"
|
12
|
+
revision="4"/>
|
13
|
+
<entry
|
14
|
+
committed-rev="4"
|
15
|
+
name="ex1.rb"
|
16
|
+
text-time="2006-11-21T16:20:01.000000Z"
|
17
|
+
committed-date="2006-11-21T16:23:41.780783Z"
|
18
|
+
checksum="f101c5d90dab219e7170b1f5dc373a65"
|
19
|
+
last-author="kstephens"
|
20
|
+
kind="file"
|
21
|
+
prop-time="2006-11-21T16:20:23.000000Z"/>
|
22
|
+
</wc-entries>
|
@@ -0,0 +1 @@
|
|
1
|
+
4
|
data/examples/ex1.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'multimethod'
|
2
|
+
|
3
|
+
class A
|
4
|
+
multimethod %q{
|
5
|
+
def foo(x) # matches any argument type
|
6
|
+
"#{x.inspect}"
|
7
|
+
end
|
8
|
+
}
|
9
|
+
|
10
|
+
multimethod %q{
|
11
|
+
def foo(Fixnum x) # matches any Fixnum
|
12
|
+
"Fixnum #{x.inspect}"
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
multimethod %q{
|
17
|
+
def foo(Numeric x) # matches any Numeric
|
18
|
+
"Numeric #{x.inspect}"
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
a = A.new
|
24
|
+
puts a.foo(:symbol) # ==> ":symbol"
|
25
|
+
puts a.foo(45) # ==> "Fixnum 45"
|
26
|
+
puts a.foo(12.34) # ==> "Numeric 12.34"
|
data/lib/.svn/README.txt
ADDED
data/lib/.svn/empty-file
ADDED
File without changes
|
data/lib/.svn/entries
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<wc-entries
|
3
|
+
xmlns="svn:">
|
4
|
+
<entry
|
5
|
+
committed-rev="3"
|
6
|
+
name=""
|
7
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
8
|
+
url="svn+ssh://rubyforge.org/var/svn/multimethod/multimethod/trunk/lib"
|
9
|
+
last-author="kstephens"
|
10
|
+
kind="dir"
|
11
|
+
repos="svn+ssh://rubyforge.org/var/svn/multimethod"
|
12
|
+
revision="3"/>
|
13
|
+
<entry
|
14
|
+
name="multimethod"
|
15
|
+
kind="dir"/>
|
16
|
+
<entry
|
17
|
+
committed-rev="3"
|
18
|
+
name="multimethod.rb"
|
19
|
+
text-time="2006-11-21T01:47:12.000000Z"
|
20
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
21
|
+
checksum="2c65a931e6bd7e177e8996701aca212e"
|
22
|
+
last-author="kstephens"
|
23
|
+
kind="file"/>
|
24
|
+
</wc-entries>
|
data/lib/.svn/format
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
4
|
@@ -0,0 +1,8 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'multimethod/table'
|
5
|
+
require 'multimethod/multimethod'
|
6
|
+
require 'multimethod/method'
|
7
|
+
require 'multimethod/parameter'
|
8
|
+
require 'multimethod/core_extensions'
|
data/lib/multimethod.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'multimethod/table'
|
5
|
+
require 'multimethod/multimethod'
|
6
|
+
require 'multimethod/method'
|
7
|
+
require 'multimethod/parameter'
|
8
|
+
require 'multimethod/core_extensions'
|
File without changes
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<wc-entries
|
3
|
+
xmlns="svn:">
|
4
|
+
<entry
|
5
|
+
committed-rev="3"
|
6
|
+
name=""
|
7
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
8
|
+
url="svn+ssh://rubyforge.org/var/svn/multimethod/multimethod/trunk/lib/multimethod"
|
9
|
+
last-author="kstephens"
|
10
|
+
kind="dir"
|
11
|
+
repos="svn+ssh://rubyforge.org/var/svn/multimethod"
|
12
|
+
revision="3"/>
|
13
|
+
<entry
|
14
|
+
committed-rev="3"
|
15
|
+
name="method.rb"
|
16
|
+
text-time="2006-11-21T07:19:37.000000Z"
|
17
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
18
|
+
checksum="5135e392406babb4d5ffcca1a811af25"
|
19
|
+
last-author="kstephens"
|
20
|
+
kind="file"/>
|
21
|
+
<entry
|
22
|
+
committed-rev="3"
|
23
|
+
name="parameter.rb"
|
24
|
+
text-time="2006-11-21T07:10:23.000000Z"
|
25
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
26
|
+
checksum="60480a946dd2a2fab636bf4c58cb4573"
|
27
|
+
last-author="kstephens"
|
28
|
+
kind="file"/>
|
29
|
+
<entry
|
30
|
+
committed-rev="3"
|
31
|
+
name="core_extensions.rb"
|
32
|
+
text-time="2006-11-21T05:31:07.000000Z"
|
33
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
34
|
+
checksum="ef874d003a994297723e0f07542f168a"
|
35
|
+
last-author="kstephens"
|
36
|
+
kind="file"/>
|
37
|
+
<entry
|
38
|
+
committed-rev="3"
|
39
|
+
name="table.rb"
|
40
|
+
text-time="2006-11-21T06:52:05.000000Z"
|
41
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
42
|
+
checksum="899e5b9f61261a2e9b2da3d00a34d8db"
|
43
|
+
last-author="kstephens"
|
44
|
+
kind="file"/>
|
45
|
+
<entry
|
46
|
+
committed-rev="3"
|
47
|
+
name="multimethod.rb"
|
48
|
+
text-time="2006-11-21T07:30:13.000000Z"
|
49
|
+
committed-date="2006-11-21T15:59:22.761488Z"
|
50
|
+
checksum="32769979f54ce8f8d23f99f098150e1e"
|
51
|
+
last-author="kstephens"
|
52
|
+
kind="file"/>
|
53
|
+
</wc-entries>
|
@@ -0,0 +1 @@
|
|
1
|
+
4
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Multimethod
|
2
|
+
|
3
|
+
module ObjectExtension
|
4
|
+
def self.append_features(base) # :nodoc:
|
5
|
+
# puts "append_features{#{base}}"
|
6
|
+
super
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def multimethod(body, file = nil, line = nil)
|
12
|
+
unless file && line
|
13
|
+
fileline = caller(1)[0]
|
14
|
+
if fileline && md = /^(.*):(\d+)$/.match(fileline)
|
15
|
+
file, line = md[1], md[2].to_i
|
16
|
+
|
17
|
+
newlines = 0
|
18
|
+
body.gsub(/\n/s){|x| newlines = newlines + 1}
|
19
|
+
line -= newlines
|
20
|
+
end
|
21
|
+
|
22
|
+
# $stderr.puts "file = #{file.inspect}, line = #{line.inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
::Multimethod::Table.instance.install_method(self, body, file, line)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end # class
|
29
|
+
end # module
|
30
|
+
|
31
|
+
|
32
|
+
# Add to Module
|
33
|
+
Object.class_eval do
|
34
|
+
include Multimethod::ObjectExtension
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,232 @@
|
|
1
|
+
module Multimethod
|
2
|
+
|
3
|
+
class Method
|
4
|
+
attr_accessor :mod
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :parameter
|
7
|
+
|
8
|
+
attr_accessor :min_args
|
9
|
+
attr_accessor :max_args
|
10
|
+
attr_accessor :restarg
|
11
|
+
attr_accessor :default
|
12
|
+
|
13
|
+
attr_accessor :multimethod
|
14
|
+
attr_accessor :file
|
15
|
+
attr_accessor :line
|
16
|
+
|
17
|
+
def initialize(mod, name, params)
|
18
|
+
raise NameError, "multimethod method name not specified" unless name && name.to_s.size > 0
|
19
|
+
|
20
|
+
name = Multimethod.normalize_name(name)
|
21
|
+
|
22
|
+
@mod = mod
|
23
|
+
@name = name
|
24
|
+
@parameter = [ ]
|
25
|
+
@min_args = 0
|
26
|
+
@max_args = 0
|
27
|
+
@restarg = nil
|
28
|
+
@default = nil
|
29
|
+
|
30
|
+
@score = { }
|
31
|
+
|
32
|
+
# Add self parameter at front.
|
33
|
+
add_parameter(Parameter.new('self', mod))
|
34
|
+
|
35
|
+
# Handle other parameters.
|
36
|
+
case params
|
37
|
+
when Array
|
38
|
+
scan_parameters(params)
|
39
|
+
when String
|
40
|
+
scan_parameters_string(params)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# For sort
|
46
|
+
def <=>(x)
|
47
|
+
0
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def scan_parameters_string(params)
|
52
|
+
|
53
|
+
#$stderr.puts "scan_parameters_string(#{params.inspect})"
|
54
|
+
|
55
|
+
str = params.clone
|
56
|
+
|
57
|
+
until str.empty?
|
58
|
+
name = nil
|
59
|
+
type = nil
|
60
|
+
default = nil
|
61
|
+
|
62
|
+
str.sub!(/^\s+/, '')
|
63
|
+
|
64
|
+
# $stderr.puts " str=#{str.inspect}"
|
65
|
+
|
66
|
+
if md = /^(\w+(::\w+)*)\s+(\w+)/i.match(str)
|
67
|
+
str = md.post_match
|
68
|
+
type = md[1]
|
69
|
+
name = md[3]
|
70
|
+
elsif md = /^(\*?\w+)/i.match(str)
|
71
|
+
str = md.post_match
|
72
|
+
type = nil
|
73
|
+
name = md[1]
|
74
|
+
else
|
75
|
+
raise NameError, "Syntax error in multimethod parameters: #{params.inspect} before #{str.inspect}"
|
76
|
+
end
|
77
|
+
|
78
|
+
if md = /^\s*=\s*([^,]+)/.match(str)
|
79
|
+
str = md.post_match
|
80
|
+
default = md[1]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
str.sub!(/^\s+/, '')
|
85
|
+
if ! str.empty?
|
86
|
+
if md = /^,/.match(str)
|
87
|
+
str = md.post_match
|
88
|
+
else
|
89
|
+
raise NameError, "Syntax error in multimethod parameters: expected ',' before #{str.inspect}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
p = Parameter.new(name, type, default)
|
94
|
+
add_parameter(p)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def scan_parameters(params)
|
100
|
+
until params.empty?
|
101
|
+
name = nil
|
102
|
+
type = nil
|
103
|
+
restarg = false
|
104
|
+
default = nil
|
105
|
+
|
106
|
+
if x = params.shift
|
107
|
+
case x
|
108
|
+
when Class
|
109
|
+
type = x
|
110
|
+
else
|
111
|
+
name = x
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if ! name && (x = params.shift)
|
116
|
+
name = x
|
117
|
+
end
|
118
|
+
|
119
|
+
raise("Parameter name expected, found #{name.inspect}") unless name.kind_of?(String) || name.kind_of?(Symbol)
|
120
|
+
raise("Parameter type expected, found #{type.inspect}") unless type.kind_of?(Module) || type.nil?
|
121
|
+
|
122
|
+
p = Parameter.new(name, type, default)
|
123
|
+
add_parameter(p)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_parameter(p)
|
129
|
+
if p.restarg
|
130
|
+
raise("Too many restargs") if @restarg
|
131
|
+
@restarg = p
|
132
|
+
@max_args = nil
|
133
|
+
end
|
134
|
+
if p.default
|
135
|
+
(@default ||= [ ]).push(p)
|
136
|
+
end
|
137
|
+
|
138
|
+
p.i = @parameter.size
|
139
|
+
@parameter.push(p)
|
140
|
+
p.method = self
|
141
|
+
|
142
|
+
unless p.default || p.restarg
|
143
|
+
@min_args = @parameter.size
|
144
|
+
end
|
145
|
+
|
146
|
+
unless @restarg
|
147
|
+
@max_args = @parameter.size
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def score_cached(args)
|
153
|
+
unless x = @score[args]
|
154
|
+
x = @score[args] =
|
155
|
+
score(args)
|
156
|
+
end
|
157
|
+
x
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def score(args)
|
162
|
+
|
163
|
+
if @min_args > args.size
|
164
|
+
# Not enough args
|
165
|
+
score = nil
|
166
|
+
elsif @max_args && @max_args < args.size
|
167
|
+
# Too many args?
|
168
|
+
# $stderr.puts "max_args = #{@max_args}, args.size = #{args.size}"
|
169
|
+
score = nil
|
170
|
+
else
|
171
|
+
# Interpret how close the argument type is to the parameter's type.
|
172
|
+
i = -1
|
173
|
+
score = args.collect{|a| parameter_at(i = i + 1).score(a)}
|
174
|
+
|
175
|
+
# Handle score for trailing restargs.
|
176
|
+
if @restarg || @default
|
177
|
+
while (i = i + 1) < @parameter.size
|
178
|
+
# $stderr.puts " Adding score i=#{i}"
|
179
|
+
score << parameter_at(i).score(NilClass)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# If any argument cannot match, avoid this method.
|
184
|
+
score = nil if score.index(nil)
|
185
|
+
end
|
186
|
+
|
187
|
+
# if true || @name =~ /_bar$/
|
188
|
+
# $stderr.puts " Method: score #{self.to_s} #{args.inspect} => #{score.inspect}"
|
189
|
+
# end
|
190
|
+
|
191
|
+
score
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
def parameter_at(i)
|
196
|
+
if i >= @parameter.size && @restarg
|
197
|
+
@restarg
|
198
|
+
else
|
199
|
+
@parameter[i]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
def parameter_to_s(p = nil)
|
205
|
+
p ||= @parameter
|
206
|
+
p.collect{|x| x.to_s_long}.join(', ')
|
207
|
+
end
|
208
|
+
|
209
|
+
def to_s(name = nil)
|
210
|
+
name ||= @name
|
211
|
+
p = @parameter.clone
|
212
|
+
rcvr = p.shift
|
213
|
+
"#{rcvr.type.name}##{name}(#{parameter_to_s(p)})"
|
214
|
+
end
|
215
|
+
|
216
|
+
def to_ruby
|
217
|
+
"def #{name}(#{to_s_arg})"
|
218
|
+
end
|
219
|
+
|
220
|
+
def to_s_arg
|
221
|
+
x = @parameter.clone
|
222
|
+
x.shift
|
223
|
+
x.collect{|x| x.to_ruby}.join(', ')
|
224
|
+
end
|
225
|
+
|
226
|
+
def inspect
|
227
|
+
to_s
|
228
|
+
end
|
229
|
+
end # class
|
230
|
+
end # module
|
231
|
+
|
232
|
+
|