multimethod 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +21 -54
- data/Rakefile +19 -2
- data/Releases.txt +7 -0
- data/lib/multimethod.rb +1 -0
- data/lib/multimethod/core_extensions.rb +6 -1
- data/lib/multimethod/method.rb +43 -185
- data/lib/multimethod/multimethod.rb +58 -3
- data/lib/multimethod/multimethod_version.rb +6 -0
- data/lib/multimethod/parameter.rb +124 -17
- data/lib/multimethod/signature.rb +322 -0
- data/lib/multimethod/table.rb +75 -30
- data/test/add_remove_test.rb +99 -0
- data/test/method_test.rb +2 -67
- data/test/multimethod_test.rb +18 -16
- data/test/signature_test.rb +190 -0
- metadata +23 -56
- data/.svn/README.txt +0 -2
- data/.svn/empty-file +0 -0
- data/.svn/entries +0 -68
- data/.svn/format +0 -1
- data/.svn/text-base/ChangeLog.svn-base +0 -3
- data/.svn/text-base/Manifest.txt.svn-base +0 -54
- data/.svn/text-base/README.txt.svn-base +0 -40
- data/.svn/text-base/Rakefile.svn-base +0 -132
- data/.svn/text-base/Releases.txt.svn-base +0 -7
- data/examples/.svn/README.txt +0 -2
- data/examples/.svn/empty-file +0 -0
- data/examples/.svn/entries +0 -22
- data/examples/.svn/format +0 -1
- data/examples/.svn/props/ex1.rb.svn-work +0 -5
- data/lib/.svn/README.txt +0 -2
- data/lib/.svn/empty-file +0 -0
- data/lib/.svn/entries +0 -24
- data/lib/.svn/format +0 -1
- data/lib/.svn/text-base/multimethod.rb.svn-base +0 -8
- data/lib/multimethod/.svn/README.txt +0 -2
- data/lib/multimethod/.svn/empty-file +0 -0
- data/lib/multimethod/.svn/entries +0 -53
- data/lib/multimethod/.svn/format +0 -1
- data/lib/multimethod/.svn/text-base/core_extensions.rb.svn-base +0 -38
- data/lib/multimethod/.svn/text-base/method.rb.svn-base +0 -232
- data/lib/multimethod/.svn/text-base/multimethod.rb.svn-base +0 -171
- data/lib/multimethod/.svn/text-base/parameter.rb.svn-base +0 -64
- data/lib/multimethod/.svn/text-base/table.rb.svn-base +0 -99
- data/test/.svn/README.txt +0 -2
- data/test/.svn/empty-file +0 -0
- data/test/.svn/entries +0 -53
- data/test/.svn/format +0 -1
- data/test/.svn/text-base/method_test.rb.svn-base +0 -89
- data/test/.svn/text-base/multimethod_test.rb.svn-base +0 -92
- data/test/.svn/text-base/parameter_test.rb.svn-base +0 -31
- data/test/.svn/text-base/test_base.rb.svn-base +0 -25
- data/test/.svn/text-base/usage_test.rb.svn-base +0 -146
@@ -1,64 +0,0 @@
|
|
1
|
-
module Multimethod
|
2
|
-
class Parameter
|
3
|
-
RESTARG_SCORE = 9999
|
4
|
-
|
5
|
-
attr_accessor :name
|
6
|
-
attr_accessor :i
|
7
|
-
attr_accessor :type
|
8
|
-
attr_accessor :default
|
9
|
-
attr_accessor :restarg
|
10
|
-
|
11
|
-
attr_accessor :method
|
12
|
-
|
13
|
-
def initialize(name, type = nil, default = nil, restarg = false)
|
14
|
-
# $stderr.puts "initialize(#{name.inspect}, #{type}, #{restarg.inspect})"
|
15
|
-
name = name.to_s
|
16
|
-
if name.sub!(/^\*/, '')
|
17
|
-
restarg = true
|
18
|
-
end
|
19
|
-
|
20
|
-
name = name.intern unless name.kind_of?(Symbol)
|
21
|
-
@name = name
|
22
|
-
@i = nil
|
23
|
-
@type = type || Kernel
|
24
|
-
@default = default
|
25
|
-
@restarg = restarg
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
def score(arg)
|
30
|
-
return RESTARG_SCORE if @restarg
|
31
|
-
score = all_types(arg).index(type_object)
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
|
-
def all_types(arg)
|
36
|
-
arg.ancestors
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
def type_object
|
41
|
-
if @type.kind_of?(String)
|
42
|
-
@type = @method.multimethod.table.name_to_object(@type, @method.mod, @method)
|
43
|
-
end
|
44
|
-
@type
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
def to_s
|
49
|
-
@restarg ? "*#{@name}" : @name
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
def to_s_long
|
54
|
-
"#{@type} #{to_ruby}"
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
def to_ruby
|
59
|
-
"#{to_s}#{@default ? ' = ' + @default : ''}"
|
60
|
-
end
|
61
|
-
|
62
|
-
end # class
|
63
|
-
end # module
|
64
|
-
|
@@ -1,99 +0,0 @@
|
|
1
|
-
module Multimethod
|
2
|
-
class Table
|
3
|
-
|
4
|
-
@@instance = nil
|
5
|
-
def self.instance
|
6
|
-
# THREAD CRITICAL BEGIN
|
7
|
-
@@instance ||= self.new
|
8
|
-
# TRREAD CRITICAL END
|
9
|
-
end
|
10
|
-
|
11
|
-
@@hook_var = :@@__multimethods
|
12
|
-
|
13
|
-
def initialize(*opts)
|
14
|
-
@method = { }
|
15
|
-
|
16
|
-
# Type name lookup cache
|
17
|
-
@name_to_object = { }
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
@@match_def = /^\s*def\s+(\w+)([(](.*)[)])?/
|
22
|
-
# Interface to Multimethod::Module mixin multimethod
|
23
|
-
def install_method(mod, body, file = nil, line = nil)
|
24
|
-
name = nil
|
25
|
-
params = nil
|
26
|
-
|
27
|
-
# Parse first line.
|
28
|
-
if md = body.match(@@match_def)
|
29
|
-
name = md[1]
|
30
|
-
params = md[3] || ''
|
31
|
-
else
|
32
|
-
raise("Cannot determine name(params) from body")
|
33
|
-
end
|
34
|
-
|
35
|
-
# Get our Multimethod for this
|
36
|
-
mm = lookup_multimethod(name)
|
37
|
-
mm.install_dispatch(mod)
|
38
|
-
m = mm.new_method(mod, params)
|
39
|
-
|
40
|
-
# Evaluate our method.
|
41
|
-
new_body = body.clone
|
42
|
-
new_body.sub!(@@match_def, m.to_ruby)
|
43
|
-
|
44
|
-
# if m.restarg
|
45
|
-
# $stderr.puts "install_method(#{mod}) => #{m.to_ruby}:\n#{new_body}"
|
46
|
-
# end
|
47
|
-
|
48
|
-
file ||= __FILE__; line ||= __LINE__
|
49
|
-
m.file = file; m.line = line
|
50
|
-
mod.module_eval(new_body, file || __FILE__, line || __LINE__)
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
def lookup_multimethod(name)
|
55
|
-
name = name.to_s
|
56
|
-
|
57
|
-
# THREAD CRITICAL BEGIN
|
58
|
-
unless mm = @method[name]
|
59
|
-
mm = Multimethod.new(name)
|
60
|
-
mm.table = self
|
61
|
-
@method[name] = mm
|
62
|
-
end
|
63
|
-
# THREAD CRITICAL END
|
64
|
-
|
65
|
-
mm
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
# Interface to code generated by #install_dispatch.
|
70
|
-
def dispatch(name, rcvr, args)
|
71
|
-
unless mm = @method[name]
|
72
|
-
raise NameError, 'No method for multmethod #{name}' unless mm
|
73
|
-
end
|
74
|
-
mm.dispatch(rcvr, args)
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
#################################################
|
79
|
-
# Support
|
80
|
-
#
|
81
|
-
|
82
|
-
def name_to_object(name, scope = nil, method = nil)
|
83
|
-
scope ||= Kernel
|
84
|
-
# THREAD CRITICAL
|
85
|
-
unless x = (@name_to_object[scope] ||= { })[name]
|
86
|
-
# $stderr.puts " name_to_object(#{name.inspect}) in #{scope}"
|
87
|
-
x =
|
88
|
-
@name_to_object[scope][name] =
|
89
|
-
scope.module_eval(name, method ? method.file : __FILE__, method ? method.line : __LINE__)
|
90
|
-
end
|
91
|
-
|
92
|
-
x
|
93
|
-
end
|
94
|
-
|
95
|
-
end # class
|
96
|
-
|
97
|
-
end # module
|
98
|
-
|
99
|
-
|
data/test/.svn/README.txt
DELETED
data/test/.svn/empty-file
DELETED
File without changes
|
data/test/.svn/entries
DELETED
@@ -1,53 +0,0 @@
|
|
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/test"
|
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_test.rb"
|
16
|
-
text-time="2006-11-21T05:04:48.000000Z"
|
17
|
-
committed-date="2006-11-21T15:59:22.761488Z"
|
18
|
-
checksum="40b4ca1c1c328339e7380b23522998e5"
|
19
|
-
last-author="kstephens"
|
20
|
-
kind="file"/>
|
21
|
-
<entry
|
22
|
-
committed-rev="3"
|
23
|
-
name="parameter_test.rb"
|
24
|
-
text-time="2006-11-21T07:25:08.000000Z"
|
25
|
-
committed-date="2006-11-21T15:59:22.761488Z"
|
26
|
-
checksum="6893f4ec384c8ed8b5bede4642783d13"
|
27
|
-
last-author="kstephens"
|
28
|
-
kind="file"/>
|
29
|
-
<entry
|
30
|
-
committed-rev="3"
|
31
|
-
name="usage_test.rb"
|
32
|
-
text-time="2006-11-21T06:51:40.000000Z"
|
33
|
-
committed-date="2006-11-21T15:59:22.761488Z"
|
34
|
-
checksum="c3b86cfd548e87f6a3abfba9b6e64c54"
|
35
|
-
last-author="kstephens"
|
36
|
-
kind="file"/>
|
37
|
-
<entry
|
38
|
-
committed-rev="3"
|
39
|
-
name="test_base.rb"
|
40
|
-
text-time="2006-11-20T21:58:18.000000Z"
|
41
|
-
committed-date="2006-11-21T15:59:22.761488Z"
|
42
|
-
checksum="52aa7dfea864715aede8ab3e5aba1ca0"
|
43
|
-
last-author="kstephens"
|
44
|
-
kind="file"/>
|
45
|
-
<entry
|
46
|
-
committed-rev="3"
|
47
|
-
name="multimethod_test.rb"
|
48
|
-
text-time="2006-11-21T07:23:21.000000Z"
|
49
|
-
committed-date="2006-11-21T15:59:22.761488Z"
|
50
|
-
checksum="4de3fbfd3e551eaecc1b9a550b08a80a"
|
51
|
-
last-author="kstephens"
|
52
|
-
kind="file"/>
|
53
|
-
</wc-entries>
|
data/test/.svn/format
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
4
|
@@ -1,89 +0,0 @@
|
|
1
|
-
require 'test_base'
|
2
|
-
|
3
|
-
module Multimethod
|
4
|
-
|
5
|
-
class MethodTest < TestBase
|
6
|
-
|
7
|
-
class A < Object; end
|
8
|
-
class B < A; end
|
9
|
-
class C < Object; end
|
10
|
-
class D < B; end
|
11
|
-
|
12
|
-
def setup
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_scan_parameter
|
17
|
-
assert_not_nil m1 = Method.new(Object, :m, [ A, :a, B, :b, :c, '*d' ])
|
18
|
-
|
19
|
-
assert_equal 5, m1.parameter.size
|
20
|
-
|
21
|
-
i = -1
|
22
|
-
|
23
|
-
i = i + 1
|
24
|
-
assert_equal :self, m1.parameter[i].name
|
25
|
-
assert_equal Object, m1.parameter[i].type
|
26
|
-
assert ! m1.parameter[i].restarg
|
27
|
-
|
28
|
-
i = i + 1
|
29
|
-
assert_equal :a, m1.parameter[i].name
|
30
|
-
assert_equal A, m1.parameter[i].type
|
31
|
-
assert ! m1.parameter[i].restarg
|
32
|
-
|
33
|
-
i = i + 1
|
34
|
-
assert_equal :b, m1.parameter[i].name
|
35
|
-
assert_equal B, m1.parameter[i].type
|
36
|
-
assert ! m1.parameter[i].restarg
|
37
|
-
|
38
|
-
i = i + 1
|
39
|
-
assert_equal :c, m1.parameter[i].name
|
40
|
-
assert_equal Kernel, m1.parameter[i].type
|
41
|
-
assert ! m1.parameter[i].restarg
|
42
|
-
|
43
|
-
i = i + 1
|
44
|
-
assert_equal :d, m1.parameter[i].name
|
45
|
-
assert_equal Kernel, m1.parameter[i].type
|
46
|
-
assert m1.parameter[i].restarg
|
47
|
-
|
48
|
-
m1
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_scan_parameter_string
|
52
|
-
assert_not_nil m1 = Method.new(Object, :m, 'A a, B b, c = nil, *d')
|
53
|
-
|
54
|
-
assert_equal 5, m1.parameter.size
|
55
|
-
|
56
|
-
i = -1
|
57
|
-
|
58
|
-
i = i + 1
|
59
|
-
assert_equal :self, m1.parameter[i].name
|
60
|
-
assert_equal Object, m1.parameter[i].type
|
61
|
-
assert ! m1.parameter[i].restarg
|
62
|
-
|
63
|
-
i = i + 1
|
64
|
-
assert_equal :a, m1.parameter[i].name
|
65
|
-
assert_equal 'A', m1.parameter[i].type
|
66
|
-
assert ! m1.parameter[i].restarg
|
67
|
-
|
68
|
-
i = i + 1
|
69
|
-
assert_equal :b, m1.parameter[i].name
|
70
|
-
assert_equal 'B', m1.parameter[i].type
|
71
|
-
assert ! m1.parameter[i].restarg
|
72
|
-
|
73
|
-
i = i + 1
|
74
|
-
assert_equal :c, m1.parameter[i].name
|
75
|
-
assert_equal Kernel, m1.parameter[i].type
|
76
|
-
assert ! m1.parameter[i].restarg
|
77
|
-
|
78
|
-
i = i + 1
|
79
|
-
assert_equal :d, m1.parameter[i].name
|
80
|
-
assert_equal Kernel, m1.parameter[i].type
|
81
|
-
assert m1.parameter[i].restarg
|
82
|
-
|
83
|
-
m1
|
84
|
-
end
|
85
|
-
|
86
|
-
end # class
|
87
|
-
|
88
|
-
end # module
|
89
|
-
|
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'test_base'
|
2
|
-
|
3
|
-
module Multimethod
|
4
|
-
|
5
|
-
class MethodTest < TestBase
|
6
|
-
|
7
|
-
class A < Object; end
|
8
|
-
class B < A; end
|
9
|
-
class C < Object; end
|
10
|
-
class D < B; end
|
11
|
-
class E < A; end
|
12
|
-
|
13
|
-
def setup
|
14
|
-
super
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_score
|
18
|
-
# Make some argument lists.
|
19
|
-
types = [ A, B, C, D, E ]
|
20
|
-
a = { }
|
21
|
-
c = { }
|
22
|
-
types.each do |t1|
|
23
|
-
n1 = t1.name.clone
|
24
|
-
n1.sub!(/^.*::/, '')
|
25
|
-
n1 = n1[0..0]
|
26
|
-
types.each do |t2|
|
27
|
-
n2 = t2.name.clone
|
28
|
-
n2.sub!(/^.*::/, '')
|
29
|
-
n2 = n2[0..0]
|
30
|
-
|
31
|
-
symbol = "#{n1.downcase}_#{n2.downcase}".intern
|
32
|
-
a[symbol] = [ 1, t1.new, t2.new ]
|
33
|
-
c[symbol] = a[symbol].collect{|x| x.class}
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
rs = Parameter::RESTARG_SCORE
|
38
|
-
|
39
|
-
assert_not_nil m1 = Method.new(Object, :m, [ A, :x, A, :y ])
|
40
|
-
assert_equal 3, m1.min_args
|
41
|
-
assert_equal 3, m1.max_args
|
42
|
-
|
43
|
-
assert_not_nil m2 = Method.new(Object, :m, [ B, :x, A, :y ])
|
44
|
-
assert_equal 3, m2.min_args
|
45
|
-
assert_equal 3, m2.max_args
|
46
|
-
|
47
|
-
assert_not_nil m3 = Method.new(Object, :m, [ C, :x, '*rest' ])
|
48
|
-
assert_equal 2, m3.min_args
|
49
|
-
assert_equal nil, m3.max_args
|
50
|
-
assert_not_nil m3.restarg
|
51
|
-
|
52
|
-
assert_not_nil m4 = Method.new(Object, :m, [ D, :x, :y ])
|
53
|
-
assert_equal 3, m4.min_args
|
54
|
-
assert_equal 3, m4.max_args
|
55
|
-
|
56
|
-
assert_not_nil m5 = Method.new(Object, :m, [ E, :y, :y ])
|
57
|
-
assert_equal 3, m4.min_args
|
58
|
-
assert_equal 3, m4.max_args
|
59
|
-
|
60
|
-
# 5 == 1.class.ancestors.index(Object)
|
61
|
-
assert_equal [ 5, 0, 0 ] , m1.score(c[:a_a])
|
62
|
-
assert_equal [ 5, 0, 1 ] , m1.score(c[:a_b])
|
63
|
-
assert_equal nil , m1.score(c[:a_c])
|
64
|
-
assert_equal [ 5, 1, 1 ] , m1.score(c[:b_b])
|
65
|
-
assert_equal nil , m1.score(c[:c_a])
|
66
|
-
assert_equal [ 5, 1, 2 ] , m1.score(c[:b_d])
|
67
|
-
|
68
|
-
assert_equal nil , m3.score(c[:a_a])
|
69
|
-
assert_equal nil , m3.score(c[:a_b])
|
70
|
-
assert_equal nil , m3.score(c[:b_b])
|
71
|
-
assert_equal [ 5, 0, rs ] , m3.score(c[:c_a])
|
72
|
-
assert_equal [ 5, 0, rs ] , m3.score(c[:c_c])
|
73
|
-
|
74
|
-
# Create a multimethod for later.
|
75
|
-
assert_not_nil mm = Multimethod.new(:test)
|
76
|
-
mm.add_method(m1)
|
77
|
-
mm.add_method(m2)
|
78
|
-
mm.add_method(m3)
|
79
|
-
mm.add_method(m4)
|
80
|
-
|
81
|
-
# Check method lookup.
|
82
|
-
assert_equal m1 , mm.lookup_method_(c[:a_a])
|
83
|
-
assert_equal m2 , mm.lookup_method_(c[:b_a])
|
84
|
-
assert_equal m2 , mm.lookup_method_(c[:b_b])
|
85
|
-
|
86
|
-
mm
|
87
|
-
end
|
88
|
-
|
89
|
-
end # class
|
90
|
-
|
91
|
-
end # module
|
92
|
-
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'test_base'
|
2
|
-
|
3
|
-
module Multimethod
|
4
|
-
|
5
|
-
class ParameterTest < TestBase
|
6
|
-
|
7
|
-
class A < Object; end
|
8
|
-
class B < A; end
|
9
|
-
class C < Object; end
|
10
|
-
class D < B; end
|
11
|
-
|
12
|
-
def setup
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_score
|
17
|
-
pA = Parameter.new(:a, A)
|
18
|
-
assert_equal 0, pA.score(A)
|
19
|
-
assert_equal 1, pA.score(B)
|
20
|
-
assert_equal nil, pA.score(C)
|
21
|
-
assert_equal 2, pA.score(D)
|
22
|
-
|
23
|
-
pB = Parameter.new(:b, B)
|
24
|
-
assert_equal nil, pB.score(A)
|
25
|
-
assert_equal 0, pB.score(B)
|
26
|
-
assert_equal nil, pB.score(C)
|
27
|
-
assert_equal 1, pB.score(D)
|
28
|
-
end
|
29
|
-
end # class
|
30
|
-
|
31
|
-
end # module
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'multimethod'
|
3
|
-
|
4
|
-
module Multimethod
|
5
|
-
|
6
|
-
class TestBase < Test::Unit::TestCase
|
7
|
-
def setup
|
8
|
-
super
|
9
|
-
end
|
10
|
-
|
11
|
-
# Avoid "No test were specified" error.
|
12
|
-
def test_foo
|
13
|
-
assert true
|
14
|
-
end
|
15
|
-
|
16
|
-
# Helpers.
|
17
|
-
def assert_equal_float(x, y, eps = 1.0e-8)
|
18
|
-
d = (x * eps).abs
|
19
|
-
assert (x - d) <= y
|
20
|
-
assert y <= (x + d)
|
21
|
-
end
|
22
|
-
|
23
|
-
end # class
|
24
|
-
|
25
|
-
end # module
|