multimethod 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|