multimethod 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.svn/README.txt +2 -0
  2. data/.svn/empty-file +0 -0
  3. data/.svn/entries +68 -0
  4. data/.svn/format +1 -0
  5. data/.svn/text-base/ChangeLog.svn-base +3 -0
  6. data/.svn/text-base/Manifest.txt.svn-base +54 -0
  7. data/.svn/text-base/README.txt.svn-base +40 -0
  8. data/.svn/text-base/Rakefile.svn-base +132 -0
  9. data/.svn/text-base/Releases.txt.svn-base +7 -0
  10. data/ChangeLog +3 -0
  11. data/Manifest.txt +54 -0
  12. data/README.txt +40 -0
  13. data/Rakefile +132 -0
  14. data/Releases.txt +7 -0
  15. data/examples/.svn/README.txt +2 -0
  16. data/examples/.svn/empty-file +0 -0
  17. data/examples/.svn/entries +22 -0
  18. data/examples/.svn/format +1 -0
  19. data/examples/.svn/props/ex1.rb.svn-work +5 -0
  20. data/examples/ex1.rb +26 -0
  21. data/lib/.svn/README.txt +2 -0
  22. data/lib/.svn/empty-file +0 -0
  23. data/lib/.svn/entries +24 -0
  24. data/lib/.svn/format +1 -0
  25. data/lib/.svn/text-base/multimethod.rb.svn-base +8 -0
  26. data/lib/multimethod.rb +8 -0
  27. data/lib/multimethod/.svn/README.txt +2 -0
  28. data/lib/multimethod/.svn/empty-file +0 -0
  29. data/lib/multimethod/.svn/entries +53 -0
  30. data/lib/multimethod/.svn/format +1 -0
  31. data/lib/multimethod/.svn/text-base/core_extensions.rb.svn-base +38 -0
  32. data/lib/multimethod/.svn/text-base/method.rb.svn-base +232 -0
  33. data/lib/multimethod/.svn/text-base/multimethod.rb.svn-base +171 -0
  34. data/lib/multimethod/.svn/text-base/parameter.rb.svn-base +64 -0
  35. data/lib/multimethod/.svn/text-base/table.rb.svn-base +99 -0
  36. data/lib/multimethod/core_extensions.rb +38 -0
  37. data/lib/multimethod/method.rb +232 -0
  38. data/lib/multimethod/multimethod.rb +171 -0
  39. data/lib/multimethod/parameter.rb +64 -0
  40. data/lib/multimethod/table.rb +99 -0
  41. data/test/.svn/README.txt +2 -0
  42. data/test/.svn/empty-file +0 -0
  43. data/test/.svn/entries +53 -0
  44. data/test/.svn/format +1 -0
  45. data/test/.svn/text-base/method_test.rb.svn-base +89 -0
  46. data/test/.svn/text-base/multimethod_test.rb.svn-base +92 -0
  47. data/test/.svn/text-base/parameter_test.rb.svn-base +31 -0
  48. data/test/.svn/text-base/test_base.rb.svn-base +25 -0
  49. data/test/.svn/text-base/usage_test.rb.svn-base +146 -0
  50. data/test/method_test.rb +89 -0
  51. data/test/multimethod_test.rb +92 -0
  52. data/test/parameter_test.rb +31 -0
  53. data/test/test_base.rb +25 -0
  54. data/test/usage_test.rb +146 -0
  55. metadata +108 -0
@@ -0,0 +1,7 @@
1
+ = Multimethod Release History
2
+
3
+ == Release 0.0.1: 2006/11/18
4
+
5
+ * Initial Release
6
+ * TODO
7
+ * Fix how default parameters are scored.
@@ -0,0 +1,2 @@
1
+ This is a Subversion working copy administrative directory.
2
+ Visit http://subversion.tigris.org/ for more information.
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
@@ -0,0 +1,5 @@
1
+ K 14
2
+ svn:executable
3
+ V 1
4
+ *
5
+ END
@@ -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"
@@ -0,0 +1,2 @@
1
+ This is a Subversion working copy administrative directory.
2
+ Visit http://subversion.tigris.org/ for more information.
File without changes
@@ -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>
@@ -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'
@@ -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'
@@ -0,0 +1,2 @@
1
+ This is a Subversion working copy administrative directory.
2
+ Visit http://subversion.tigris.org/ for more information.
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
+