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.
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
+