multimethod 0.0.1
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/.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
@@ -0,0 +1,171 @@
|
|
1
|
+
module Multimethod
|
2
|
+
class Multimethod
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :method
|
6
|
+
attr_accessor :table
|
7
|
+
|
8
|
+
def initialize(name, *opts)
|
9
|
+
raise NameError, "multimethod name not specified" unless name && name.to_s.size > 0
|
10
|
+
|
11
|
+
@name = name
|
12
|
+
@name_i = 0
|
13
|
+
@method = [ ]
|
14
|
+
@dispatch = { }
|
15
|
+
|
16
|
+
@lookup_method = { }
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def gensym(name = nil)
|
21
|
+
name ||= @name
|
22
|
+
"_multimethod_#{@name_i = @name_i + 1}_#{name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def new_method(mod, *args)
|
27
|
+
m = Method.new(mod, gensym, *args)
|
28
|
+
add_method(m)
|
29
|
+
m
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def add_method(method)
|
34
|
+
# THREAD CRITICAL BEGIN
|
35
|
+
@method.push(method)
|
36
|
+
method.multimethod = self
|
37
|
+
@lookup_method = { } # flush cache
|
38
|
+
# THREAD CRITICAL END
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def dispatch(rcvr, args)
|
43
|
+
apply_method(lookup_method(rcvr, args), rcvr, args)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Interface to Multimethod::Table
|
48
|
+
def apply_method(meth, rcvr, args)
|
49
|
+
unless meth # && false
|
50
|
+
$stderr.puts "Available multimethods for #{rcvr.class.name}##{@name}(#{args}):"
|
51
|
+
$stderr.puts " " + @method.sort{|a,b| a.min_args <=> b.min_args }.collect{|x| x.to_s(name)}.join("\n ")
|
52
|
+
$stderr.puts "\n"
|
53
|
+
end
|
54
|
+
raise NameError, "Cannot find multimethod for #{rcvr.class.name}##{@name}(#{args})" unless meth
|
55
|
+
rcvr.send(meth.name, *args)
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def lookup_method(rcvr, args)
|
60
|
+
args = args.clone
|
61
|
+
args.unshift(rcvr)
|
62
|
+
lookup_method_cached_(args)
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def lookup_method_cached_(args)
|
67
|
+
args_type = args.collect{|x| x.class}
|
68
|
+
|
69
|
+
# THREAD CRITICAL BEGIN
|
70
|
+
unless result = @lookup_method[args_type]
|
71
|
+
result = @lookup_method[args_type] =
|
72
|
+
lookup_method_(args_type)
|
73
|
+
end
|
74
|
+
# THREAD CRITICAL END
|
75
|
+
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def lookup_method_(args)
|
81
|
+
scores = score_methods(@method, args)
|
82
|
+
if scores.empty?
|
83
|
+
result = nil
|
84
|
+
else
|
85
|
+
result = scores[0][1]
|
86
|
+
raise("Ambigious method") if scores.select{|x| x[0] == result}.size > 1
|
87
|
+
end
|
88
|
+
|
89
|
+
#if @name.to_s == 'bar'
|
90
|
+
# $stderr.puts "args = " + args.collect{|x| x.class.name + ' ' + x.to_s}.join(", ")
|
91
|
+
# $stderr.puts "scores:\n " + scores.collect{|x| x.inspect}.join("\n ")
|
92
|
+
# end
|
93
|
+
|
94
|
+
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
def score_methods(meths, args)
|
99
|
+
scores = meths.collect do |meth|
|
100
|
+
score = meth.score_cached(args)
|
101
|
+
if score
|
102
|
+
score = [ score, meth ]
|
103
|
+
else
|
104
|
+
score = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
score
|
108
|
+
end
|
109
|
+
|
110
|
+
scores.compact!
|
111
|
+
scores.sort!
|
112
|
+
|
113
|
+
# $stderr.puts "score_methods(#{args.inspect}) => \n#{scores.inspect}"
|
114
|
+
|
115
|
+
scores
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def install_dispatch(mod)
|
120
|
+
# THREAD CRITICAL BEGIN
|
121
|
+
unless @dispatch[mod]
|
122
|
+
@dispatch[mod] = true
|
123
|
+
# $stderr.puts "install_dispatch(#{name}) into #{mod}\n";
|
124
|
+
mod.class_eval(body = <<-"end_eval", __FILE__, __LINE__)
|
125
|
+
def #{name}(*args)
|
126
|
+
::#{table.class.name}.instance.dispatch(#{name.inspect}, self, args)
|
127
|
+
end
|
128
|
+
end_eval
|
129
|
+
# $stderr.puts "install_dispatch = #{body}"
|
130
|
+
end
|
131
|
+
# THREAD CRITICAL END
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
##################################################
|
136
|
+
# Support
|
137
|
+
#
|
138
|
+
|
139
|
+
@@name_map = {
|
140
|
+
'@' => 'AT',
|
141
|
+
'=' => 'EQ',
|
142
|
+
'<' => 'LT',
|
143
|
+
'>' => 'GT',
|
144
|
+
'+' => 'ADD',
|
145
|
+
'-' => 'SUB',
|
146
|
+
'*' => 'MUL',
|
147
|
+
'/' => 'DIV',
|
148
|
+
'%' => 'MOD',
|
149
|
+
'^' => 'XOR',
|
150
|
+
'|' => 'OR',
|
151
|
+
'&' => 'AND',
|
152
|
+
'!' => 'NOT',
|
153
|
+
'~' => 'TIL',
|
154
|
+
nil => nil
|
155
|
+
};
|
156
|
+
@@name_map.delete(nil)
|
157
|
+
|
158
|
+
@@name_rx = Regexp.new('(' + @@name_map.keys.collect{|x| Regexp.quote(x)}.join('|') + ')')
|
159
|
+
|
160
|
+
def self.normalize_name(name)
|
161
|
+
name = name.to_s.clone
|
162
|
+
name.sub!(@@name_rx){|x| "_#{@@name_map[x] || '_'}_"}
|
163
|
+
|
164
|
+
name.intern
|
165
|
+
end
|
166
|
+
|
167
|
+
end # class
|
168
|
+
|
169
|
+
end # module
|
170
|
+
|
171
|
+
|
@@ -0,0 +1,64 @@
|
|
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
|
+
|
@@ -0,0 +1,99 @@
|
|
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
|
+
|
@@ -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
|
+
|