rdoba 0.0.2

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