vlx-multi 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 (3) hide show
  1. data/sample.rb +148 -0
  2. data/vlx_multi.rb +468 -0
  3. metadata +63 -0
@@ -0,0 +1,148 @@
1
+ require 'vlx_multi'
2
+
3
+ test_global = true
4
+ test_module = true
5
+
6
+
7
+ class A
8
+ end
9
+
10
+ class B < A
11
+ end
12
+
13
+ class C < A
14
+ end
15
+
16
+ class D < C
17
+ end
18
+
19
+
20
+ # test global functions reloading
21
+
22
+ if test_global == true then
23
+
24
+ # reload by regexp
25
+ vlxm(:some,"$array",/<[\w;: ]+>/) do |_1,_2|
26
+ puts 'some<$array;Regexp>' + _1.to_s + ' ' + _2.to_s
27
+ end
28
+
29
+ vlxm(:some,Object,String) do |s,s1| puts 'some<Object,String> ' + s.to_s + ' ' + s1.to_s end
30
+
31
+ vlxm(:some,String) do |s| puts 'some<String> ' + s end
32
+
33
+ vlxm(:some,String,String) do |s,s1| puts 'some<String,String> ' + s + ' ' + s1 end
34
+
35
+ vlxm(:some,Object) do |o| puts 'some<Object> ' + o.inspect end
36
+
37
+ vlxm(:some,:_1,:_2) do |_,_| puts 'some<:_1,:_2> ' end
38
+
39
+ vlxm(:some,:_1) do |_| puts 'some<:_1> ' end
40
+
41
+ vlxm(:some,'nil text',nil) do |_,_| puts 'some<nil text,nil> ' end
42
+
43
+ vlxm(:some,Symbol,Symbol) do |s,s1| puts 'some<Symbol,Symbol> ' + s.to_s + ' ' + s1.to_s end
44
+
45
+ # reload by condition: _ == 'custom def'
46
+ vlxm(:some,vlxmd("_ == 'custom def'")) do |_| puts 'some<Def>'end
47
+
48
+ vlxm(:some,A,D) { |_,_| puts '<A:D>' }
49
+ vlxm(:some,B,C) { |_,_| puts '<B:C>' }
50
+
51
+
52
+ puts 'global test begin'
53
+ begin
54
+ some('text')
55
+ some('text','text2')
56
+ some('nil text',nil)
57
+ some([55,44])
58
+ some(:_1,:_2)
59
+ some(:_1)
60
+ some(:_1,:_b)
61
+ some('$array', '<names:string; values:varaint>')
62
+ some(A.new,D.new)
63
+ some(B.new,C.new)
64
+ some(B.new,D.new)
65
+ some(D.new,D.new)
66
+ some('custom def')
67
+ rescue Exception
68
+ p $!
69
+ end
70
+ puts 'global test end'
71
+
72
+ end
73
+
74
+
75
+
76
+ # test module functions reloading
77
+
78
+ if test_module == true then
79
+
80
+ module VlxTest
81
+ module Inner
82
+
83
+ vlxm(:some,String) do |s| puts 'VlxTest::some<String> ' + s end
84
+
85
+ vlxm(:some,String,String) do |s,s1| puts 'VlxTest::some<String,String> ' + s + ' ' + s1 end
86
+
87
+ vlxm(:some,Object) do |o| puts 'VlxTest::some<Object> ' + o.to_s end
88
+
89
+ vlxm(:some,:_1,:_2) do |_,_| puts 'VlxTest::some<:_1,:_2> ' end
90
+
91
+ vlxm(:some,:_1) do |_,_| puts 'VlxTest::some<:_1> ' end
92
+
93
+ vlxm(:some,Symbol,Symbol) do |s,s1|
94
+ puts 'VlxTest::some<Symbol,Symbol> ' + s.to_s + ' ' + s1.to_s
95
+ end
96
+
97
+
98
+ puts 'module test begin'
99
+ some('text')
100
+ some('text','text2')
101
+ some(55)
102
+ some(:_1,:_2)
103
+ some(:_1)
104
+ some(:_1,:_b)
105
+ puts 'module test end'
106
+
107
+ class Test
108
+ def initialize(name)
109
+ @name = name
110
+ end
111
+
112
+ vlxm(:some,String) do |s|
113
+ puts 'VlxTest::Test::some<String> ' + s + ' ' + @name
114
+ end
115
+
116
+ vlxm(:some,String,String) do |s,s1| puts 'VlxTest::Test::some<String,String> ' + s + ' ' + s1 end
117
+
118
+ vlxm(:some,Object) do |o| puts 'VlxTest::Test::some<Object> ' + o.to_s end
119
+
120
+ vlxm(:some,:_1,:_2) do |_,_| puts 'VlxTest::Test::some<:_1,:_2> ' end
121
+
122
+ vlxm(:some,:_1) do |_|
123
+ puts 'VlxTest::Test::some<:_1> '
124
+ end
125
+
126
+ vlxm(:some,Symbol,Symbol) do |s,s1|
127
+ puts 'VlxTest::Test::some<Symbol,Symbol> ' + s.to_s + ' ' + s1.to_s
128
+ end
129
+
130
+ end # Test
131
+
132
+ end # Inner
133
+ end # VlxTest
134
+
135
+
136
+ puts 'class test begin'
137
+ c = VlxTest::Inner::Test
138
+ c.new('Test1').some('aa')
139
+ c.new('Test2').some('aa')
140
+ puts 'class test end'
141
+
142
+ end
143
+
144
+
145
+
146
+
147
+
148
+
@@ -0,0 +1,468 @@
1
+ =begin
2
+ Multimethod call in http://rubyforge.org/projects/multimethod and http://rubyforge.org/projects/multi/
3
+ implements as several table lookups.
4
+
5
+ Vlx-multimethods generate single method definition for all overloads of one message with series of if-then-else
6
+ condition for all patterns. Overloading allowed by value, by class, by regexp, by custom condition.
7
+
8
+ =end
9
+
10
+
11
+ require 'facets/module/modspace'
12
+ require 'facets/module/basename'
13
+ require 'facets/proc/bind'
14
+
15
+ @@vlx_multi_methods_hook = self
16
+
17
+
18
+
19
+ module Vlx
20
+ module MultiMethods
21
+
22
+ @@debug = false
23
+ @@keys_map = {}
24
+
25
+ def self.debug?
26
+ @@debug
27
+ end
28
+
29
+ def self.debug=(v)
30
+ @@debug = v
31
+ end
32
+
33
+ class IsValidDef
34
+
35
+ def self.s_prev(a,j,t,i)
36
+ return nil if i == 0 && j == 0
37
+ return t[i-1,1] if i > 0
38
+ p = a[j-1]
39
+ p[p.size-1,1]
40
+ end
41
+
42
+ def self.s_next(a,j,t,i)
43
+ return nil if i == t.size - 1 && j == a.size - 1
44
+ return t[i+1,1] if i+1 < t.size
45
+ a[j+1][0,1]
46
+ end
47
+
48
+ def self.good_char?(c)
49
+ return true if c == nil
50
+ return false if c == '_'
51
+ return false if /\d+/.match(c) != nil
52
+ return true
53
+ end
54
+
55
+ def self.index_(a,j,i)
56
+ o = 0
57
+ k = 0
58
+ while k < j
59
+ o = o + a[k].size
60
+ k = k + 1
61
+ end
62
+ o + i
63
+ end
64
+
65
+ def self.in_string?(s,min,count)
66
+ c1c = s[min,count].count "'"
67
+ c2c = s[min,count].count '"'
68
+ c1c % 2 != 0 || c1c % 2 != 0
69
+ end
70
+
71
+ def self.check(t)
72
+ ur = []
73
+ r = []
74
+ t.each('_'){ |e| r << e }
75
+ #p r
76
+ i=0
77
+ while i < r.size
78
+ c = r[i]
79
+ i = i + 1
80
+ index = c.index('_')
81
+ next if index == nil
82
+ #puts 'check: ' + c
83
+ sPrev = s_prev( r, i-1, c, index )
84
+ sNext = s_next( r, i-1, c, index )
85
+ if good_char?(sPrev) && good_char?(sNext) then
86
+ i1 = index_(r,i-1,index)
87
+ if !in_string?( t, 0, i1 ) then
88
+ #puts c
89
+ ur << i1
90
+ end
91
+ end
92
+ end
93
+ ur
94
+ end
95
+
96
+ end
97
+
98
+
99
+ class Def
100
+ def initialize(text)
101
+ @text = text
102
+ end
103
+
104
+ attr_reader :text
105
+ end
106
+
107
+
108
+ class ArgBase
109
+
110
+ def initialize( arg )
111
+ @arg = arg
112
+ end
113
+
114
+ attr_reader :arg
115
+ end
116
+
117
+
118
+ class ArgDef < ArgBase
119
+ def text(param)
120
+ p = @arg.text.dup
121
+ offset = 0
122
+ IsValidDef.check(@arg.text).each { |index|
123
+ p[offset + index] = param
124
+ offset = offset + param.size - 1
125
+ }
126
+ #puts @arg.text + ' -> ' + p
127
+ p
128
+ end
129
+ end
130
+
131
+
132
+ class ArgValue < ArgBase
133
+ def text(i)
134
+ i + ' == ' + @arg.inspect
135
+ end
136
+ end
137
+
138
+
139
+ class ArgRegexp < ArgBase
140
+ def text(i)
141
+ i + '.class == String && ' + @arg.inspect + '.match(' + i +')'
142
+ end
143
+ end
144
+
145
+
146
+ class ArgClass < ArgBase
147
+ def text(i)
148
+ i + '.is_a?(' + @arg.to_s + ')'
149
+ end
150
+
151
+ def is_superclass?(p)
152
+ s = @arg
153
+ pClass = p.arg
154
+ while s != nil
155
+ return true if s == pClass
156
+ s = s.superclass
157
+ end
158
+ false
159
+ end
160
+
161
+ def compare_by_superclass(p)
162
+ return -1 if is_superclass?(p) == true
163
+ return 1 if p.is_superclass?(self) == true
164
+ 0
165
+ end
166
+ end
167
+
168
+
169
+ class Pattern
170
+
171
+ @@blocks_map = {}
172
+ @@args = [ ArgValue, ArgRegexp, ArgDef, ArgClass ]
173
+
174
+ def self.blocks_map
175
+ @@blocks_map
176
+ end
177
+
178
+
179
+ def cond_code
180
+ r = ''
181
+ i = 0
182
+ @a.each{ |arg|
183
+ p = 'p_' + i.to_s
184
+ r = r + (i == 0 ? '' : ' and ') + arg.text( p )
185
+ i = i + 1
186
+ }
187
+ r
188
+ end
189
+
190
+ def block
191
+ @b
192
+ end
193
+
194
+ def initialize(args,block)
195
+ @a = []
196
+ args.each{|a|
197
+ aClass = a.class
198
+ if aClass == Class then
199
+ @a << ArgClass.new( a )
200
+ elsif aClass == Regexp then
201
+ @a << ArgRegexp.new( a )
202
+ elsif aClass == Def then
203
+ @a << ArgDef.new( a )
204
+ else
205
+ @a << ArgValue.new( a )
206
+ end
207
+
208
+ }
209
+ @b = block
210
+ @@blocks_map[ block.__id__ ] = block
211
+ end
212
+
213
+ def array
214
+ @a
215
+ end
216
+
217
+ @@compare_table = {}
218
+
219
+ def make_compare_(p,m,c,c2)
220
+ g = @@args.index(c)
221
+ g2 = @@args.index(c2)
222
+ Proc.new{ |a,b| [p.call(a,b) * m,g,g2] }
223
+ end
224
+
225
+ def pow(n,k)
226
+ return 1 if k == 0
227
+ return n if k == 1
228
+ return n * pow(n,k-1)
229
+ end
230
+
231
+ def priority_of(a)
232
+ return pow(100,@@args.index(a))
233
+ end
234
+
235
+ def reg_compare_(a,b,p)
236
+ aP = priority_of(a)
237
+ bP = priority_of(b)
238
+ m = 1
239
+ if aP > bP then
240
+ #t = a
241
+ #a = b
242
+ #b = t
243
+ m = -1
244
+ end
245
+ #@@compare_table[ [a,b] ] = make_compare_( p, 1, b, a )
246
+ #@@compare_table[ [b,a] ] = make_compare_( p, -1, b, a )
247
+ @@compare_table[ [a,b] ] = make_compare_( p, m, a, b )
248
+ @@compare_table[ [b,a] ] = make_compare_( p, -m, b, a )
249
+ end
250
+
251
+ def reg_compare_single_(a,p)
252
+ @@compare_table[ [a,a] ] = make_compare_( p, 1, a, a )
253
+ end
254
+
255
+ def compare_table_init
256
+ byId = Proc.new { |a,b| a.__id__ <=> b.__id__ }
257
+ cc = Proc.new { |a,b| a.compare_by_superclass(b) }
258
+ m1 = Proc.new { |a,b| -1 }
259
+
260
+ reg_compare_single_ ArgValue, byId
261
+ reg_compare_single_ ArgRegexp, byId
262
+ reg_compare_single_ ArgDef, byId
263
+ reg_compare_single_ ArgClass, cc
264
+
265
+ reg_compare_( ArgValue, ArgClass, m1 )
266
+ reg_compare_( ArgValue, ArgDef, m1 )
267
+ reg_compare_( ArgValue, ArgRegexp, m1 )
268
+ reg_compare_( ArgDef, ArgRegexp, m1 )
269
+ reg_compare_( ArgRegexp, ArgClass, m1 )
270
+ reg_compare_( ArgDef, ArgClass, m1 )
271
+
272
+ end
273
+
274
+
275
+ def compare_(a,b)
276
+ compare_table_init if @@compare_table.size == 0
277
+ return @@compare_table[ [a.class,b.class] ].call(a,b)
278
+ end
279
+
280
+ def compare(other)
281
+ return 0 if self.equal?(other)
282
+
283
+ i = 0
284
+ maxg = [-1,-1,-1]
285
+ total = Array.new(@@args.size,0)
286
+ totalOther = Array.new(@@args.size,0)
287
+
288
+ other.array.each{ |otherE|
289
+ myE = @a[i]
290
+ cr = compare_( myE, otherE )
291
+ myG = cr[1]
292
+ otherG = cr[2]
293
+ maxG = myG < otherG ? otherG : myG
294
+ total[myG] = total[myG] + 1
295
+ totalOther[otherG] = totalOther[otherG] + 1
296
+ if maxG > maxg[0] && cr[0] != 0 then
297
+ maxg[0] = maxG
298
+ maxg[1] = i
299
+ maxg[2] = cr[0]
300
+ end
301
+ i = i + 1
302
+ }
303
+
304
+ i = total.size
305
+ while i >= 0
306
+ i = i - 1
307
+ return -1 if total[i] < totalOther[i]
308
+ return 1 if total[i] > totalOther[i]
309
+ end
310
+
311
+
312
+ return -1 if maxg[2] < 0
313
+ return 1 if maxg[2] > 0
314
+ return 0
315
+
316
+ end
317
+
318
+ end
319
+
320
+
321
+ class Data
322
+
323
+ def initialize( obj, method_name )
324
+ @obj = obj
325
+ @method_name = method_name
326
+ @args = []
327
+ end
328
+
329
+
330
+ def add( args, block )
331
+ argsCount = args.size
332
+ if @args.size <= argsCount then
333
+ i = @args.size
334
+ while i <= argsCount
335
+ @args << []
336
+ i = i + 1
337
+ end
338
+ end
339
+
340
+ @args[ argsCount ] << Pattern.new( args, block )
341
+ gen( argsCount )
342
+ end
343
+
344
+ def print_args
345
+ @args.each { |a| p a }
346
+ end
347
+
348
+
349
+ def gen_i( argsCount, t )
350
+ args = @args[argsCount]
351
+
352
+ return if args.empty?
353
+
354
+ t << $/ << 'when ' << argsCount.to_s << $/
355
+ argsCount.times { |k|
356
+ t << 'p_' << k.to_s << ' = args[' << k.to_s << ']; '
357
+ }
358
+
359
+ t << 'vlxBlockIndex = nil '
360
+
361
+ callText = ''
362
+ argsCount.times { |i|
363
+ callText << 'p_' << i.to_s
364
+ callText << ', ' if i < argsCount - 1
365
+ }
366
+
367
+ first = true
368
+ args.each do |arg|
369
+ t << $/ << (first ? 'if ' : 'elsif ') << arg.cond_code << ' then ' << $/ <<
370
+ 'vlxBlockIndex = ' << arg.block.__id__.to_s
371
+ first = false
372
+ end
373
+ t << $/ << 'end ' << $/ << 'vlxB = vlxmmBlocksMap[vlxBlockIndex]' << $/
374
+ t << 'if self.class == Module then return vlxB.call(*args) else return vlxB.bind(self)[*args] end'
375
+
376
+ end
377
+
378
+
379
+ def parents(c)
380
+ r = []
381
+ while c != nil
382
+ r << c
383
+ c = c.modspace
384
+ break if c == Object
385
+ end
386
+ r
387
+ end
388
+
389
+ def gen( argsCount )
390
+ args = @args[argsCount]
391
+ args.sort! do |x,y|
392
+ x.compare(y)
393
+ end
394
+
395
+ prefix = ''
396
+ postfix = ''
397
+ selfText = 'self.'
398
+ if @obj.__id__ == @@vlx_multi_methods_hook.__id__
399
+ ;
400
+ elsif @obj.class == Class
401
+ a = parents(@obj).reverse
402
+ prefix = ''
403
+ a.each{ |e|
404
+ prefix << 'class ' if e.class == Class
405
+ prefix << 'module ' if e.class == Module
406
+ prefix << e.basename << $/
407
+ postfix << 'end '
408
+ }
409
+
410
+ selfText = ''
411
+
412
+ elsif @obj.class == Module
413
+ a = []
414
+ @obj.name.each('::') { |e|
415
+ a << e.delete('::')
416
+ }
417
+ prefix = ''
418
+ a.each { |e|
419
+ prefix << 'module ' << e.to_s << $/
420
+ postfix << 'end '
421
+ }
422
+ else
423
+ throw 'VlxMultiNethods register code generation failed ' + @obj.inspect
424
+ end
425
+
426
+ t = ''
427
+ t << prefix << $/
428
+ t << 'def ' << selfText << @method_name.to_s << '( *args )' << $/
429
+ t << 'vlxmmBlocksMap = Vlx::MultiMethods::Pattern.blocks_map' << $/
430
+
431
+ i = 0
432
+ t << 'case args.size'
433
+ @args.each { |argList|
434
+ gen_i( i, t )
435
+ i = i + 1
436
+ }
437
+ t << $/ << 'else ' << $/ << ' end' << $/
438
+ t << ' throw "unknown pattern " + args.inspect + ' << " ' for method " << @method_name.to_s << "'" << $/
439
+ t << 'end' << $/
440
+ t << postfix << $/
441
+ puts t if Vlx::MultiMethods.debug? == true
442
+
443
+
444
+ #p @@vlx_multi_methods_hook
445
+ @@vlx_multi_methods_hook.send( :eval, t, TOPLEVEL_BINDING )
446
+
447
+ end
448
+
449
+ end
450
+
451
+ def self.reg( obj, method_name, args, block )
452
+ key = [ obj, method_name ]
453
+ data = @@keys_map.fetch( key ) { d = Data.new( obj, method_name ); @@keys_map[key] = d; d }
454
+ data.add( args, block )
455
+ end
456
+
457
+
458
+ end # MultiMethods
459
+ end # Vlx
460
+
461
+
462
+ def vlxm( symbol, *args, &block )
463
+ Vlx::MultiMethods.reg( self, symbol, args, block )
464
+ end
465
+
466
+ def vlxmd(text)
467
+ Vlx::MultiMethods::Def.new(text)
468
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vlx-multi
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Kornyushenko Eugene
8
+ autorequire: vlx-multi
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-14 00:00:00 +04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: facets
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: kornyushenko@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - vlx_multi.rb
35
+ - sample.rb
36
+ has_rdoc: false
37
+ homepage: http://rubyforge.org/projects/vlx-multi/
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - .
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project: vlx-multi
58
+ rubygems_version: 1.2.0
59
+ signing_key:
60
+ specification_version: 2
61
+ summary: Multiple Dispatch/Pattern Matching for Ruby
62
+ test_files: []
63
+