vlx-multi 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+