rdoba 0.0.2

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/lib/rdoba.rb ADDED
@@ -0,0 +1,1145 @@
1
+ #!/usr/bin/ruby -KU
2
+
3
+ require 'strscan'
4
+ require 'timeout'
5
+
6
+ class Object
7
+ attr_reader :debug
8
+
9
+ eval "$debug_#{__FILE__.gsub(/[\/\.]/,'_')} = 0"
10
+ @debug = nil
11
+ @@debug = nil
12
+ eval "$debug_#{self.class} = 0"
13
+
14
+ public
15
+
16
+ def self.debug=(level)
17
+ @@debug = level
18
+ end
19
+
20
+ def debug=(level)
21
+ @debug = level
22
+ end
23
+
24
+ def dbc(level)
25
+ level = level.to_i
26
+ if level > 0
27
+ clevel = (
28
+ @debug || @@debug ||
29
+ begin; eval "$debug_#{self.class}"; rescue; nil; end ||
30
+ begin; eval "$debug"; rescue; nil; end
31
+ ).to_i
32
+ (clevel & level) == level
33
+ else
34
+ false
35
+ end
36
+ end
37
+
38
+ def dbp(level, text)
39
+ Kernel.puts text if dbc(level)
40
+ end
41
+
42
+ def dbg(level, code, vars = {})
43
+ if dbc(level)
44
+ if vars
45
+ vars.each_pair do |var, value|
46
+ instance_variable_set(var, value)
47
+ end
48
+ end
49
+ eval code
50
+ end
51
+ end
52
+
53
+ def dbp11(text)
54
+ dbp(0x11,text)
55
+ end
56
+
57
+ def dbp12(text)
58
+ dbp(0x12,text)
59
+ end
60
+
61
+ def dbp14(text)
62
+ dbp(0x14,text)
63
+ end
64
+
65
+ def dbp18(text)
66
+ dbp(0x18,text)
67
+ end
68
+
69
+ def dbp1C(text)
70
+ dbp(0x1C,text)
71
+ end
72
+
73
+ def dbp1F(text)
74
+ dbp(0x1F,text)
75
+ end
76
+
77
+ def dbp21(text)
78
+ dbp(0x21,text)
79
+ end
80
+
81
+ def dbp22(text)
82
+ dbp(0x22,text)
83
+ end
84
+
85
+ def dbp24(text)
86
+ dbp(0x24,text)
87
+ end
88
+
89
+ def dbp26(text)
90
+ dbp(0x26,text)
91
+ end
92
+
93
+ def dbp28(text)
94
+ dbp(0x28,text)
95
+ end
96
+
97
+ def dbp2C(text)
98
+ dbp(0x2C,text)
99
+ end
100
+
101
+ def dbp2F(text)
102
+ dbp(0x2F,text)
103
+ end
104
+
105
+ def dbp41(text)
106
+ dbp(0x41,text)
107
+ end
108
+
109
+ def dbp42(text)
110
+ dbp(0x42,text)
111
+ end
112
+
113
+ def dbp44(text)
114
+ dbp(0x44,text)
115
+ end
116
+
117
+ def dbp48(text)
118
+ dbp(0x48,text)
119
+ end
120
+
121
+ def dbp4F(text)
122
+ dbp(0x4F,text)
123
+ end
124
+
125
+ def dbg44(code, vars)
126
+ dbg(0x44,code,vars)
127
+ end
128
+
129
+ def dbc2F
130
+ dbc(0x2F)
131
+ end
132
+
133
+ alias :__method_missing__ :method_missing
134
+ def method_missing(symbol, *args)
135
+ if symbol.id2name =~ /^dbc([0-9a-fA-F]+)$/
136
+ dbc($1.to_i(16))
137
+ elsif not args.empty?
138
+ if symbol.id2name =~ /^dbg([0-9a-fA-F]+)$/
139
+ dbg($1.to_i(16), args.shift, args.shift)
140
+ elsif symbol.id2name =~ /^dbp([0-9a-fA-F]+)$/
141
+ dbp($1.to_i(16), args.join(','))
142
+ else __method_missing__(symbol, *args); end
143
+ else __method_missing__(symbol, *args); end
144
+ end
145
+
146
+ def xor(val1)
147
+ val0 = (not not self)
148
+ ((val0) and (not val1)) or ((not val0) and (val1))
149
+ end
150
+
151
+ def co(method, *args) #calls any method
152
+ eval "#{method}(*args)"
153
+ end
154
+
155
+ def to_sym
156
+ to_s.to_sym
157
+ end
158
+
159
+ P = [
160
+ 'слово',
161
+ 'язык',
162
+ 'часть речи',
163
+ 'время',
164
+ 'род',
165
+ 'лицо',
166
+ 'число',
167
+ 'падеж',
168
+ 'имя',
169
+ 'залог',
170
+ 'зрак',
171
+ 'разряд',
172
+ 'полнота',
173
+ 'изменчивость',
174
+ 'ограничение',
175
+ 'притяжение',
176
+ 'исток',
177
+ 'образа',
178
+ 'формы',
179
+ 'близь',
180
+ 'соответствия',
181
+ 'наборы',
182
+ 'чада',
183
+ 'осмысления',
184
+ 'примеры',
185
+ 'значения',
186
+ 'смысл',
187
+ 'писмя',
188
+ 'перевод',
189
+ 'пояснение',
190
+ 'отсылка',
191
+ 'ссылки',
192
+ 'сравнение',
193
+ ]
194
+
195
+ def to_yml(level = 0)
196
+ res = ''
197
+ res += '---' if level == 0
198
+ res += case self.class.to_s.to_sym
199
+ when :Hash
200
+ rs = ''
201
+ self.keys.sort do |x,y|
202
+ ix = P.index(x) #TODO workaround
203
+ iy = P.index(y)
204
+ (ix and iy) ? ix <=> iy : (ix ? -1 : (iy ? 1 : x <=> y))
205
+ end.each do |key|
206
+ value = self[key]
207
+ rs += "\n" + ' ' * level * 2 + key.to_yml(level + 1)
208
+ rs += ': ' + value.to_yml(level + 1)
209
+ end
210
+ rs
211
+ when :Array
212
+ rs = ''
213
+ self.each do |value|
214
+ rs += "\n" + ' ' * level * 2 + '- ' + value.to_yml(level + 1)
215
+ end
216
+ rs
217
+ when :Fixnum
218
+ self.to_s
219
+ when :String
220
+ if self =~ /[-:\s]/
221
+ "\"#{self.gsub('"','\"')}\""
222
+ else
223
+ self
224
+ end
225
+ when :NilClass
226
+ ''
227
+ else
228
+ begin
229
+ value.to_yaml
230
+ rescue NameError
231
+ raise "Unsupported class #{self.class}"
232
+ end
233
+ end
234
+ res
235
+ end
236
+ end
237
+
238
+ module Kernel
239
+ private
240
+ def require_dir(dir, name)
241
+ dbp11 "[require_dir] <<< dir = #{dir}, name = #{name}"
242
+ begin
243
+ rdir = File.join(dir, name)
244
+ return false unless File.directory?(rdir)
245
+ rdir = File.join(dir, name)
246
+ $: << rdir unless $:.include?(rdir)
247
+ dbp14 "[require_dir]> Found dir #{rdir}"
248
+ Dir.foreach(rdir) do |file|
249
+ next unless file =~ /(.*)\.(rb|so)$/
250
+ dbp14 "[require_dir]> Loading ... #{$1}"
251
+ require $1
252
+ end
253
+ true
254
+ rescue
255
+ false
256
+ end
257
+ end
258
+
259
+ def sub_require(name)
260
+ dbp11 "[sub_require] <<< name = #{name} "
261
+ $:.each do |dir|
262
+ begin
263
+ Dir.foreach(dir) do |file|
264
+ next unless file =~ /^#{name}\.(rb|so)$/
265
+ dbp14 "[sub_require]> Require Dir #{dir}/#{name} for #{file}"
266
+ r1 = require_dir(dir, name + '.modules')
267
+ r2 = require_dir(dir, name)
268
+ dbp14 "[sub_require]> Require Dir #{(r1 || r2) && 'passed' || 'failed'} ... #{name}"
269
+ end
270
+ rescue
271
+ end
272
+ end unless $".include?(name)
273
+ true
274
+ end
275
+
276
+ public
277
+
278
+ alias :__require__ :require
279
+ def require(name, options = {})
280
+ dbp11 "[require] <<< name = #{name}"
281
+ begin
282
+ res = __require__ name
283
+ rescue => bang
284
+ puts "Lib internal error: #{$!.class} -> #{$!}\n\t#{$@.join("\n\t")}"
285
+ exit
286
+ end
287
+ dbp14 "[require]> Loaded? #{name}... #{res}"
288
+ res = sub_require(name) if res and options[:recursive]
289
+ res
290
+ end
291
+
292
+ alias :__sprintf__ :sprintf
293
+ def sprintf(format, *args)
294
+ nargs = []
295
+ nformat = ''
296
+
297
+ fmt = format.split('%')
298
+ nformat = fmt.shift
299
+
300
+ while (not fmt.empty?)
301
+ part = fmt.shift
302
+ part = '%' + fmt.shift unless part
303
+ if part =~ /([0-9 #+\-*.]*)([bcdEefGgiopsuXx])(.*)/ and $2 == 'c'
304
+ keys = $1 || ''
305
+ str = $3 || ''
306
+ if keys =~ /(-)?([0-9*]*)(?:\.([0-9*]+)(\+))?/
307
+ value = args.shift
308
+ indent = ' ' * ($2 == '*' ? args.shift : $2).to_i
309
+ plain = value && value.to_p(($3 == '*' ? args.shift : $3 ? $3 : 1).to_i, $4) || ''
310
+ nformat += ($1 ? plain + indent : indent + plain) + str
311
+ else
312
+ nformat += '%' + keys + 'c' + str
313
+ nargs.push args.shift
314
+ end
315
+ else
316
+ nformat += '%' + part
317
+ l = $1 =~ /\*/ ? 2 : 1
318
+ while l > 0
319
+ nargs.push args.shift
320
+ l -= 1
321
+ end
322
+ end
323
+ end
324
+ __sprintf__(nformat, *nargs).to_p
325
+ end
326
+
327
+ def wait_if(timeout = 30)
328
+ begin
329
+ Timeout::timeout(timeout) do
330
+ while yield(); end
331
+ end
332
+ true
333
+ rescue Timeout::Error
334
+ false
335
+ end
336
+ end
337
+ end
338
+
339
+ class Class
340
+ =begin
341
+ @@inherited = {}
342
+
343
+ def self.inherited(child)
344
+ @@inherited[self] = [] unless @@inherited.key? self
345
+ @@inherited[self] << child
346
+ end
347
+
348
+ def new(*args, &block)
349
+ def match_inherited(cls, args)
350
+ @@inherited[cls].class != Array ? nil : (@@inherited[cls].each do |child|
351
+ begin
352
+ mm = child.method(:__match__)
353
+ return match_inherited(child, args) || child if mm.call(*args)
354
+ rescue
355
+ end
356
+ end; cls)
357
+ end
358
+ cls = match_inherited(self, args) || self
359
+ i = cls.allocate
360
+ i.method(:initialize).call(*args, &block)
361
+ i
362
+ end
363
+ =end
364
+ end
365
+
366
+ class NilClass
367
+ def =~(value)
368
+ value == nil
369
+ end
370
+
371
+ def +(value)
372
+ value
373
+ end
374
+
375
+ def <<(value)
376
+ [ value ]
377
+ end
378
+
379
+ def empty?
380
+ true
381
+ end
382
+
383
+ def to_i
384
+ 0
385
+ end
386
+ alias :ord :to_i
387
+
388
+ def size
389
+ 0
390
+ end
391
+
392
+ def <=>(value)
393
+ -1
394
+ end
395
+ end
396
+
397
+
398
+ class Array
399
+
400
+ private
401
+
402
+ def __comby(i, size)
403
+ s = "0#{sprintf("%.*b", size, i)}0"
404
+ v = { :res => [], :c0 => 0, :c1 => 0, :j => 0}
405
+
406
+ def up1(v)
407
+ sub_j = v[:j] + v[:c1] + 1
408
+ v[:res] << self[v[:j]...sub_j]
409
+ v[:j] = sub_j
410
+ v[:c1] = 0
411
+ end
412
+
413
+ def up0(v)
414
+ sub_j = v[:j] + v[:c0] - 1
415
+ self[v[:j]...sub_j].each do |x| v[:res] << [x] end
416
+ v[:j] = sub_j
417
+ end
418
+
419
+ s.each_char do |c|
420
+ if c == '1'
421
+ v[:c1] += 1
422
+ up0(v) if v[:c0] > 1
423
+ v[:c0] = 0
424
+ else
425
+ v[:c0] += 1
426
+ up1(v) if v[:c1] > 0
427
+ end
428
+ end
429
+ up0(v) if v[:c0] > 1
430
+ v[:res]
431
+ end
432
+
433
+ public
434
+
435
+ def purge
436
+ self.compact.delete_if {|x| x.empty? }
437
+ end
438
+
439
+ def >>(value = nil)
440
+ value ? delete(value) : shift
441
+ end
442
+
443
+ def each_comby(*args)
444
+ return self if self.empty? or not block_given?
445
+ if args.include?(:backward)
446
+ yield [ self.dup ]
447
+ ((1 << (self.size - 1)) - 2).downto(0) do |i|
448
+ c = __comby(i, self.size - 1)
449
+ yield c
450
+ end
451
+ else
452
+ 0.upto((1 << (self.size - 1)) - 2) do |i|
453
+ c = __comby(i, self.size - 1)
454
+ yield c
455
+ end
456
+ yield [ self.dup ]
457
+ end
458
+
459
+ return self
460
+ end
461
+
462
+ alias :__get__ :[]
463
+ def [](index, *args)
464
+ return __get__(index.to_i, *args) if index.class == String and index =~ /^\d+$/
465
+ __get__(index, *args)
466
+ end
467
+
468
+ alias :__set__ :[]=
469
+ def []=(index, value, *args)
470
+ return __set__(index.to_i, value, *args) if index.class == String and index =~ /^\d+$/
471
+ __set__(index, value, *args)
472
+ end
473
+
474
+ def geta(index, options = {}) #TODO => [] + class Index
475
+ dbp11 "[geta] <<< array = #{self.inspect}, index = #{index.inspect}, options = #{options.inspect}"
476
+ options[:сокр] ||= @сокр
477
+
478
+ if index.class == Array
479
+ return self if index == [] or index == ['']
480
+ index = index.clone
481
+ value = self[index.shift]
482
+ (value.class == Hash or value.class == Array) ? value.geta(index, options) : value
483
+ else
484
+ geta_value(index, options)
485
+ end
486
+ end
487
+
488
+ end
489
+
490
+ class String
491
+ def -(str)
492
+ #TODO make smart search for match in the 'str', when only last subpart matched to 'self'
493
+ len = self.size
494
+ bc = ec = nil
495
+ (0...len).each do |idx|
496
+ break bc = idx if self[idx] == str[0]
497
+ end
498
+ ((bc + 1)...len).each do |idx|
499
+ break ec = idx if self[idx] != str[idx - bc]
500
+ end if bc
501
+ (not bc) ? self.clone : (not ec) ? self[0, bc] : self[0, bc] + self[ec, len - ec]
502
+ end
503
+
504
+ alias :__match__ :=~
505
+ def =~(value)
506
+ if value.class == String
507
+ self == value
508
+ elsif value.class == Regexp
509
+ value =~ self
510
+ else
511
+ __match__(value)
512
+ end
513
+ end
514
+
515
+ def rmatch(value)
516
+ self == value || self =~ /^\/([^\/]+)/ && value =~ /#{$1}/
517
+ end
518
+
519
+ FirstChar = 0
520
+ alias :__set__ :[]=
521
+ def []=(*args)
522
+ index = args[0]
523
+ str = args[args.size > 2 ? 2 : 1]
524
+ if index.class == Fixnum
525
+ if str.class == String
526
+ a = self.split(//u)
527
+ if str.size == 1
528
+ a[index] = str
529
+ else
530
+ a[index] = str.split(//u)
531
+ a.flatten!
532
+ end
533
+ return self.replace(a.join)
534
+ end
535
+ end
536
+ __set__(*args)
537
+ end
538
+
539
+ def get(*args)
540
+ index = args[0]
541
+ index.class == Fixnum ? self.split(//u)[index] : self[*args]
542
+ end
543
+
544
+ def ord
545
+ a = nil
546
+ self.each_byte do |b|
547
+ c = b & 0xC0
548
+ case c
549
+ when 0xc0
550
+ a = (b & 0x3F)
551
+ when 0x80
552
+ return (a << 6) + (b & 0x3F)
553
+ else
554
+ return b
555
+ end
556
+ end
557
+ end unless self.instance_methods(false).include?(:ord)
558
+
559
+ def setbyte(*args)
560
+ __set__(*args)
561
+ end unless self.instance_methods(false).include?(:setbyte)
562
+
563
+ def upcase_char(char)
564
+ chr = char.class == String ? char.ord : char.to_i
565
+ if chr >= 0x430 and chr < 0x450
566
+ chr -= 0x20
567
+ elsif chr >= 0x400 and chr < 0x410 or
568
+ chr >= 0x450 and chr < 0x482 or
569
+ chr >= 0x48A and chr < 0x524 or
570
+ chr >= 0xA642 and chr < 0xA668 or
571
+ chr >= 0xA680 and chr < 0xA698
572
+ chr -= 1 if (chr % 1) == 1
573
+ else
574
+ return chr.chr.__upcase__
575
+ end
576
+ chr.chr
577
+ end
578
+
579
+ alias :__upcase__ :upcase
580
+ def upcase(option = nil)
581
+ if option == FirstChar
582
+ r = self.dup
583
+ r[0] = upcase_char(self.ord)
584
+ r
585
+ elsif self.match(/[Ѐ-ҁҊ-ԣꙀ-ꙧꚀꚗ]/u)
586
+ self.split(//u).map do |chr| upcase_char(chr) end.join
587
+ else; __upcase__ end
588
+ end
589
+
590
+ def downcase_char(char)
591
+ chr = (char.class == String) ? char.ord : char.to_i
592
+ if chr >= 0x410 and chr < 0x430
593
+ chr += 0x20
594
+ elsif chr >= 0x400 and chr < 0x410 or
595
+ chr >= 0x450 and chr < 0x482 or
596
+ chr >= 0x48A and chr < 0x524 or
597
+ chr >= 0xA642 and chr < 0xA668 or
598
+ chr >= 0xA680 and chr < 0xA698
599
+ chr += 1 if (chr % 1) == 0
600
+ else
601
+ return chr.chr.__downcase__
602
+ end
603
+ chr.chr
604
+ end
605
+
606
+ alias :__downcase__ :downcase
607
+ def downcase(option = nil)
608
+ if option == FirstChar
609
+ r = self.dup
610
+ r[0] = downcase_char(self.ord)
611
+ r
612
+ elsif self.match(/[Ѐ-ҁҊ-ԣꙀ-ꙧꚀꚗ]/u)
613
+ self.split(//u).map do |chr| downcase_char(chr) end.join
614
+ else; __downcase__ end
615
+ end
616
+
617
+ alias :to_p :to_s
618
+ =begin
619
+ def to_p
620
+ force_encoding('BINARY')
621
+ end
622
+
623
+ def force_encoding(*args)
624
+ self
625
+ end unless self.instance_methods(false).include?(:force_encoding)
626
+
627
+ def encode(*args)
628
+ self
629
+ end unless self.instance_methods(false).include?(:encode)
630
+
631
+ def toutf8
632
+ return self if self.encoding.to_s == 'UTF-8'
633
+ res = ''.encode('UTF-8')
634
+
635
+ ss = StringScanner.new(self)
636
+ while ss.scan_until(/[\x80-\xFF]+/x)
637
+ same = (' ' * ss.matched_size).encode('UTF-8')
638
+ i = 0
639
+ ss.matched.each_byte do |byte|
640
+ same.setbyte(i, byte)
641
+ i += 1
642
+ end
643
+ self res += ss.pre_match[pos..-1].encode('UTF-8') + same
644
+
645
+ ss.pos += ss.matched_size + 1
646
+ end
647
+
648
+ res + ss.rest.encode('UTF-8')
649
+ end unless self.instance_methods(false).include?(:toutf8)
650
+ =end
651
+
652
+ ByteByByte = 0
653
+ alias :__reverse__ :reverse
654
+ def reverse(step = 1)
655
+ case step
656
+ when ByteByByte
657
+ arr = []
658
+ self.each_byte do |byte| arr << byte.chr end
659
+ arr.reverse.join
660
+ when 1
661
+ __reverse__
662
+ else
663
+ res = ''
664
+ offset = (self.size + 1) / step * step - step
665
+ (0..offset).step(step) do |shift|
666
+ res += self[offset - shift..offset - shift + 1]
667
+ end
668
+ res
669
+ end
670
+ end
671
+
672
+ BE = 0
673
+ LE = 1
674
+
675
+ alias :__to_i__ :to_i
676
+ def to_i(base = 10, be = true)
677
+ # TODO make a conversion of negative numbers
678
+ str = case base
679
+ when BE
680
+ self.reverse(ByteByByte)
681
+ when LE
682
+ self
683
+ else
684
+ return __to_i__(base)
685
+ end
686
+
687
+ mul = 1
688
+ res = 0
689
+ str.each_byte do |byte|
690
+ res += byte * mul
691
+ mul *= 256
692
+ end
693
+
694
+ res.to_i
695
+ end
696
+
697
+ def to_res
698
+ ostr = self.dup
699
+ res = ''
700
+ while true
701
+ m = ostr.match(/(?:([+\[\]\\().*?{}^$\/|])|«([^«]*)»)/u)
702
+ break unless m
703
+ res += m.pre_match + (m[2] || m[1] && ('\\' + m[1]))
704
+ ostr = m.post_match
705
+ end
706
+
707
+ res + ostr
708
+ end
709
+
710
+ def to_re
711
+ /#{to_res}/i
712
+ end
713
+
714
+ def scanf_re(format)
715
+ fss = StringScanner.new(format) # TODO remove scanner in favor of match
716
+ nformat = ''
717
+
718
+ pos = 0
719
+ argfs = []
720
+ while fss.scan_until(/%([0-9 #+\-*]*)(?:\.([0-9]+)(\+)?)?([bcdefgiosux])/)
721
+ argfs << [ fss[1], fss[2], fss[3], fss[4] ]
722
+ # TODO add performing the special case in fss[1]
723
+ nformat += fss.pre_match[pos..-1].to_res + case fss[4]
724
+ when 'x'
725
+ '(?:0[xX])?([a-fA-F0-9]+)'
726
+ when 'i'
727
+ '([+\-]?[0-9]+)'
728
+ when 'u'
729
+ '([0-9]+)'
730
+ when 'e'
731
+ '([+\-]?[0-9]+[eE][+\-]?[0-9]+)'
732
+ when 'f'
733
+ '([+\-]?[0-9]+\.[0-9]*)'
734
+ when 'g'
735
+ '([+\-]?[0-9]+(?:[eE][+\-]?[0-9]+|\.[0-9]*))'
736
+ when 'c'
737
+ fss[2] ? "(.{1,#{fss[2]}})" : "(.)"
738
+ when 'b'
739
+ '([01]+)b?'
740
+ when 'o'
741
+ '0([0-9]+)'
742
+ when 'd'
743
+ '([+\-]?(?:0X)?[A-F0-9.+]+)'
744
+ when 's'
745
+ '(.+)'
746
+ end
747
+
748
+ pos = fss.pos
749
+ end
750
+
751
+ nformat += fss.rest
752
+
753
+ [ /#{nformat}/, argfs ]
754
+ end
755
+
756
+ (alias :__scanf__ :scanf) if self.instance_methods(false).include?(:scanf)
757
+ def scanf(format, &block)
758
+ (re, argfs) = scanf_re(format)
759
+
760
+ ss = StringScanner.new(self)
761
+ res = []
762
+ rline = []
763
+ while ss.scan_until(re)
764
+ argfs.each_index do |i|
765
+ argf = argfs[i]
766
+ value = ss[i + 1]
767
+ rline << case argf[3]
768
+ when 'x'
769
+ value.to_i(16)
770
+ when /[diu]/
771
+ value.to_i
772
+ when /[efg]/
773
+ value.to_f
774
+ when 'c'
775
+ value.to_i(argf[2] ? BE : LE)
776
+ when 'b'
777
+ value.to_i(2)
778
+ when 'o'
779
+ value.to_i(8)
780
+ when 's'
781
+ value
782
+ end
783
+ end
784
+
785
+ if block_given?
786
+ pass = []
787
+ (1..block.arity).each do |i| pass << "rline[#{i}]" end
788
+ eval "yield(#{pass.join(', ')})"
789
+ end
790
+
791
+ res << rline
792
+ end
793
+
794
+ res
795
+ end
796
+
797
+ def consolize
798
+ ss = StringScanner.new(self)
799
+ res = ''
800
+ ostr = ''
801
+ pos = 0
802
+
803
+ while ss.scan_until(/\r/)
804
+ ostr[0...ss.pre_match.size - pos] = ss.pre_match[pos..-1]
805
+ pos = ss.pos
806
+
807
+ if ss.post_match[0] == "\n"[0]
808
+ res = ostr
809
+ pos += 1
810
+ ostr = ''
811
+ end
812
+
813
+ end
814
+
815
+ ostr[0...ss.rest.size] = ss.rest
816
+ res + ostr
817
+ end
818
+
819
+ def hexdump
820
+ res= ''
821
+ i = 0
822
+ self.each_byte do |byte|
823
+ res << sprintf("%.2X ", byte)
824
+ i += 1
825
+ res << "\n" if i % 16 == 0
826
+ end
827
+ res
828
+ end
829
+
830
+ alias :__compare__ :<=>
831
+ def <=>(value)
832
+ compare(value)
833
+ end
834
+
835
+ def compare(value, *opts)
836
+ if opts.include? :compare_diacritics
837
+ __compare__(value)
838
+ else
839
+ # TODO verify composite range
840
+ def crop_diacritics(x)
841
+ (x < 0x300 or
842
+ x > 0x36f and x < 0x483 or
843
+ x > 0x487 and x < 0xa57c or
844
+ x > 0xa67d) && x || nil
845
+ end
846
+
847
+ (self.unpack('U*').map do |x| crop_diacritics(x)
848
+ end.compact) <=> (value.unpack('U*').map do |x| crop_diacritics(x)
849
+ end.compact)
850
+ end
851
+ end
852
+ end
853
+
854
+ class Hash
855
+
856
+ protected
857
+
858
+ def geta_value(cid, options = {})
859
+ res = ((not cid) || cid.empty?) && self || self[cid] ||
860
+ (options[:сокр] && (self[options[:сокр][cid]] || self[options[:сокр].reverse[cid]]))
861
+
862
+ if not res and options[:try_regexp]
863
+ self.keys.each do |key|
864
+ break res = self[key] if key.rmatch(cid)
865
+ if options[:сокр]
866
+ options[:сокр].each_pair do |val1, val2|
867
+ break res = self[key] if key.rmatch(cid.gsub(/#{val1}/, val2)) or
868
+ key.rmatch(cid.gsub(/#{val2}/, val1))
869
+ end
870
+ end
871
+ end
872
+ end
873
+
874
+ res
875
+ end
876
+
877
+ public
878
+
879
+ def geta(index, options = {}) #TODO => [] + class Index
880
+ dbp11 "[geta] <<< hash = #{self.inspect}, index = #{index.inspect}, options = #{options.inspect}"
881
+ options[:сокр] ||= @сокр
882
+
883
+ if index.class == Array
884
+ return self if index == [] or index == ['']
885
+ index = index.clone
886
+ value = geta_value(index.shift, options)
887
+ (value.class == Hash or value.class == Array) ? value.geta(index, options) : value
888
+ else
889
+ geta_value(index, options)
890
+ end
891
+ end
892
+
893
+ def seta(index, value, options = {}) #TODO => [] + class Index
894
+ dbp11 "[seta] <<< index: #{index.inspect}, value: #{value.inspect}, options: #{options.inspect}"
895
+ options[:сокр] ||= @сокр
896
+
897
+ return self[index] = value if index.class != Array # TODO spec index
898
+
899
+ back = 0
900
+ index = index.reverse.map do |x|
901
+ if x.empty?
902
+ back += 1
903
+ nil
904
+ elsif back > 0
905
+ back -= 1
906
+ nil
907
+ else
908
+ x
909
+ end
910
+ end.compact.reverse
911
+ dbp12 "[seta]> result index: #{index.inspect}"
912
+
913
+ obj = nil
914
+ o = self
915
+ dbp14 "[seta]>> self: #{o.inspect}"
916
+ set_idx = index.pop
917
+ par_class = set_idx =~ /^\d+$/ ? Array : Hash
918
+ par_idx = nil
919
+ index.each do |idx|
920
+ unless o
921
+ dbp14 "[seta]>> parent idx: #{par_idx.inspect}, idx: #{idx.inspect}, parent obj: #{o.inspect}"
922
+ o = idx =~ /^\d+$/ && [] || {}
923
+ obj[par_idx] = o
924
+ end
925
+ obj = o
926
+ o = (obj.class == Hash) ? obj.geta_value(idx, options) : obj[idx]
927
+ dbp14 "[seta]>> cur idx: #{idx.inspect}, parent obj: #{obj.inspect}, obj: #{o.inspect}"
928
+ unless o
929
+ if idx == index.last
930
+ o = par_class.new
931
+ obj[idx] = o
932
+ else
933
+ par_idx = idx =~ /^\d+$/ && idx.to_i || idx
934
+ end
935
+ end
936
+ end
937
+
938
+ raise "Invalid path" unless o # TODO special exception
939
+
940
+ o[set_idx] = value
941
+ end
942
+
943
+ def |(inval)
944
+ res = self.dup
945
+ inval.each_pair do |key, val|
946
+ if val.class == res[key].class
947
+ if val.class == Hash
948
+ res[key] |= inval[key]
949
+ elsif val.class == Array
950
+ res[key].concat val
951
+ else
952
+ res[key] = val
953
+ end
954
+ else
955
+ res[key] = val
956
+ end
957
+ end
958
+ res
959
+ end
960
+
961
+ def deploy!(vars = {})
962
+ self.replace deploy(vars)
963
+ # TODO add variable copy
964
+ end
965
+
966
+ def deploy(vars = {})
967
+ res = {}
968
+
969
+ self.keys.sort do |x,y|
970
+ if x =~ /=$/
971
+ y =~ /=$/ ? x <=> y : -1
972
+ else
973
+ y !~ /=$/ ? x <=> y : 1
974
+ end
975
+ end.each do |key|
976
+
977
+ if key =~ /(.*)=$/
978
+ vars[$1] = self[key]
979
+ next
980
+
981
+ elsif key =~ /(.*)@$/
982
+ sym = $1
983
+ eval "res.class.co( :attr_accessor, :#{sym})"
984
+ eval "res.#{sym} = self[key]"
985
+ next
986
+
987
+ elsif key =~ /^%([^%].*)/
988
+ var = vars[$1].dup
989
+ if var.class == Hash
990
+ res |= var.deploy(vars)
991
+ elsif var.class == String
992
+ res[var] = nil
993
+ else
994
+ raise "Undeployable hash #{$1} value class #{var.class}"
995
+ end
996
+ next
997
+
998
+ elsif key =~ /^%%(.*)/
999
+ key.replace $1.to_s
1000
+ end
1001
+
1002
+ def deploy_value(value, vars)
1003
+ case value.class.to_sym
1004
+ when :String
1005
+ if value =~ /^%([^%].*)/
1006
+ begin; vars[$1].deploy(vars); rescue; nil end
1007
+ elsif value =~ /(.*)%([A-Za-z0-9_А-я]+)(.*)/
1008
+ a = [ $1.to_s, $2.to_s, $3.to_s ]
1009
+ a[1] = begin; vars[a[1]].deploy(vars).to_s; rescue; vars[a[1]] end
1010
+ a.join
1011
+ else
1012
+ value
1013
+ end
1014
+ when :Hash
1015
+ value.deploy(vars)
1016
+ when :Array
1017
+ value.map do |sub|
1018
+ deploy_value(sub, vars)
1019
+ end
1020
+ else
1021
+ value
1022
+ end
1023
+ end
1024
+
1025
+ value = self[key]
1026
+ res[key] = deploy_value(value, vars)
1027
+ end
1028
+ res
1029
+ end
1030
+
1031
+ def reverse!
1032
+ replace(reverse)
1033
+ end
1034
+
1035
+ def reverse
1036
+ h = {}
1037
+ self.each_pair do |key, value|
1038
+ if h.key? value
1039
+ if h[value].class == Array
1040
+ h[value] << key
1041
+ else
1042
+ h[value] = [ h[value], key ]
1043
+ end
1044
+ else
1045
+ h[value] = key
1046
+ end
1047
+ end
1048
+ h
1049
+ end
1050
+ end
1051
+
1052
+ class Numeric
1053
+ Nums = { 1 => 'I', 4 => 'IV', 5 => 'V', 9 => 'IX', 10 => 'X', 40 => 'XL', 50 => 'L',
1054
+ 90 => 'XC', 100 => 'C', 400 => 'CD', 500 => 'D', 900 => 'CM', 1000 => 'M' }
1055
+ Numi = Nums.keys.sort
1056
+
1057
+ def to_rom
1058
+ res = ''
1059
+ num = self
1060
+ i = Numi.size - 1
1061
+
1062
+ while num > 0
1063
+ if num >= Numi[i]
1064
+ res << Nums[Numi[i]]
1065
+ num -= Numi[i]
1066
+ else
1067
+ i -= 1
1068
+ end
1069
+ end
1070
+ res
1071
+ end
1072
+
1073
+ def to_s(base = 10, padding_count = 1, style_formatting = false)
1074
+ raise "Base of number can't be equal or less then zero" if base <= 0
1075
+ raise "Padding count numberr can't be equal or less then zero" if padding_count <= 0
1076
+ value = self
1077
+ minus = if value < 0
1078
+ value = -value
1079
+ true
1080
+ end
1081
+ res = ''
1082
+ while value != 0
1083
+ value, rem = value.divmod(base)
1084
+ rem += 0x40 - 0x39 if rem >= 10
1085
+ res += (0x30 + rem).chr
1086
+ end
1087
+ res += "0" * (padding_count - res.size) if res.size < padding_count
1088
+ res += 'x0' if style_formatting and base == 16
1089
+ res += '-' if minus
1090
+ res.reverse
1091
+ end
1092
+
1093
+ def to_p(padding_count = 1, big_endian = true)
1094
+ value = self
1095
+ minus = if value < 0
1096
+ value = -value
1097
+ true
1098
+ end
1099
+ res = ''
1100
+ while value != 0
1101
+ value, rem = value.divmod(256)
1102
+ res += rem.chr
1103
+ end
1104
+
1105
+ pad_char = if minus
1106
+ negres += ''
1107
+ over = 1
1108
+ res.each_byte do |byte|
1109
+ negbyte = 255 - byte + over
1110
+ negres += if negbyte > 255
1111
+ over = 1
1112
+ 0
1113
+ else
1114
+ over = 0
1115
+ negbyte
1116
+ end
1117
+ end
1118
+ res = negres
1119
+ "\xFF"
1120
+ else
1121
+ "\0"
1122
+ end
1123
+
1124
+ res += pad_char * (padding_count - res.size) if res.size < padding_count
1125
+
1126
+ (big_endian ? res.reverse(String::ByteByByte) : res).to_p
1127
+ end
1128
+ end
1129
+
1130
+ class Fixnum
1131
+ alias :__chr__ :chr
1132
+ def chr
1133
+ if self >= 256
1134
+ num = self; s = "\0"; byte = 0x80; a = []
1135
+ while num >= 0x40
1136
+ s.setbyte(0, byte + (num & 0x3F))
1137
+ a << s.dup; num >>= 6; byte = 0x40
1138
+ end
1139
+ s.setbyte(0, 0xC0 + (num & 0x3F))
1140
+ a << s
1141
+ a.reverse.join
1142
+ else; __chr__ end
1143
+ end
1144
+ end
1145
+