rmtools 1.0.0 → 1.1.0

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 (110) hide show
  1. data/History.txt +5 -0
  2. data/Manifest.txt +84 -26
  3. data/Rakefile +7 -4
  4. data/ext/extconf.rb +1 -1
  5. data/ext/rmtools.cpp +27 -12
  6. data/ext/rmtools.h +6 -5
  7. data/lib/rmtools/b.rb +18 -0
  8. data/lib/rmtools/console/coloring.rb +72 -0
  9. data/lib/rmtools/console/highlight.rb +13 -0
  10. data/lib/rmtools/{printing.rb → console/printing.rb} +17 -2
  11. data/lib/rmtools/console.rb +1 -0
  12. data/lib/rmtools/conversions/enum.rb +23 -0
  13. data/lib/rmtools/conversions/int.rb +47 -0
  14. data/lib/rmtools/conversions/string.rb +26 -0
  15. data/lib/rmtools/conversions.rb +1 -0
  16. data/lib/rmtools/core/arguments.rb +52 -0
  17. data/lib/rmtools/{boolean.rb → core/boolean.rb} +0 -13
  18. data/lib/rmtools/core/class.rb +41 -0
  19. data/lib/rmtools/core/js.rb +45 -0
  20. data/lib/rmtools/core/kernel.rb +28 -0
  21. data/lib/rmtools/{module.rb → core/module.rb} +0 -41
  22. data/lib/rmtools/core/numeric.rb +35 -0
  23. data/lib/rmtools/{object.rb → core/object.rb} +2 -23
  24. data/lib/rmtools/core/proc.rb +18 -0
  25. data/lib/rmtools/core/regexp.rb +11 -0
  26. data/lib/rmtools/core/string_compliance.rb +31 -0
  27. data/lib/rmtools/core.rb +1 -0
  28. data/lib/rmtools/db/active_record.rb +54 -0
  29. data/lib/rmtools/db.rb +7 -0
  30. data/lib/rmtools/debug/binding.rb +56 -0
  31. data/lib/rmtools/debug/highlight.rb +23 -0
  32. data/lib/rmtools/debug/logging.rb +176 -0
  33. data/lib/rmtools/debug/present.rb +38 -0
  34. data/lib/rmtools/debug/timer.rb +19 -0
  35. data/lib/rmtools/debug/traceback.rb +92 -0
  36. data/lib/rmtools/debug.rb +1 -0
  37. data/lib/rmtools/debug_notrace.rb +1 -0
  38. data/lib/rmtools/enumerable/array.rb +134 -0
  39. data/lib/rmtools/enumerable/array_iterators.rb +33 -0
  40. data/lib/rmtools/enumerable/common.rb +49 -0
  41. data/lib/rmtools/{hash.rb → enumerable/hash.rb} +8 -8
  42. data/lib/rmtools/enumerable/object_space.rb +19 -0
  43. data/lib/rmtools/enumerable/range.rb +201 -0
  44. data/lib/rmtools/enumerable.rb +1 -0
  45. data/lib/rmtools/experimental/blackhole.rb +12 -0
  46. data/lib/rmtools/experimental/deprecation.rb +36 -0
  47. data/lib/rmtools/experimental/dumps.rb +28 -0
  48. data/lib/rmtools/{numeric.rb → experimental/numeric.rb} +22 -51
  49. data/lib/rmtools/experimental/rails_backtrace.rb +29 -0
  50. data/lib/rmtools/experimental/string.rb +56 -0
  51. data/lib/rmtools/{tree.rb → experimental/tree.rb} +0 -0
  52. data/lib/rmtools/experimental.rb +1 -0
  53. data/lib/rmtools/fs/dir.rb +89 -0
  54. data/lib/rmtools/fs/file.rb +104 -0
  55. data/lib/rmtools/fs/io.rb +58 -0
  56. data/lib/rmtools/fs/tools.rb +49 -0
  57. data/lib/rmtools/fs.rb +1 -0
  58. data/lib/rmtools/functional/fold.rb +32 -0
  59. data/lib/rmtools/{string_to_proc.rb → functional/string_to_proc.rb} +2 -22
  60. data/lib/rmtools/functional/unfold.rb +16 -0
  61. data/lib/rmtools/functional.rb +1 -0
  62. data/lib/rmtools/ip/numeric.rb +35 -0
  63. data/lib/rmtools/ip/string.rb +45 -0
  64. data/lib/rmtools/ip.rb +1 -0
  65. data/lib/rmtools/lang/ansi.rb +17 -0
  66. data/lib/rmtools/lang/cyrillic.rb +106 -0
  67. data/lib/rmtools/lang/regexp.rb +8 -0
  68. data/lib/rmtools/lang/shortcuts.rb +20 -0
  69. data/lib/rmtools/lang.rb +1 -0
  70. data/lib/rmtools/rand/array.rb +39 -0
  71. data/lib/rmtools/rand/enum.rb +26 -0
  72. data/lib/rmtools/rand/range.rb +13 -0
  73. data/lib/rmtools/{random.rb → rand/string.rb} +13 -107
  74. data/lib/rmtools/rand.rb +1 -0
  75. data/lib/rmtools/require.rb +13 -0
  76. data/lib/rmtools/setup.rb +6 -5
  77. data/lib/rmtools/text/string_parse.rb +60 -0
  78. data/lib/rmtools/{stringscanner.rb → text/string_scanner.rb} +3 -2
  79. data/lib/rmtools/text/string_simple.rb +75 -0
  80. data/lib/rmtools/text/string_split.rb +148 -0
  81. data/lib/rmtools/text/textilize.rb +44 -0
  82. data/lib/rmtools/text.rb +1 -0
  83. data/lib/rmtools/time/global.rb +17 -0
  84. data/lib/rmtools/time/russian.rb +47 -0
  85. data/lib/rmtools/time.rb +1 -32
  86. data/lib/rmtools/xml/document.rb +28 -0
  87. data/lib/rmtools/xml/finders.rb +84 -0
  88. data/lib/rmtools/xml/libxml.rb +11 -0
  89. data/lib/rmtools/xml/node.rb +196 -0
  90. data/lib/rmtools/xml/string.rb +43 -0
  91. data/lib/rmtools/xml/xpath.rb +32 -0
  92. data/lib/rmtools/xml.rb +7 -0
  93. data/lib/rmtools.rb +8 -44
  94. metadata +97 -72
  95. data/lib/rmtools/arguments.rb +0 -24
  96. data/lib/rmtools/array.rb +0 -189
  97. data/lib/rmtools/binding.rb +0 -23
  98. data/lib/rmtools/coloring.rb +0 -82
  99. data/lib/rmtools/cyr-time.rb +0 -49
  100. data/lib/rmtools/cyrilic.rb +0 -124
  101. data/lib/rmtools/dumps.rb +0 -192
  102. data/lib/rmtools/enum.rb +0 -90
  103. data/lib/rmtools/io.rb +0 -303
  104. data/lib/rmtools/js.rb +0 -25
  105. data/lib/rmtools/limited_string.rb +0 -17
  106. data/lib/rmtools/logging.rb +0 -158
  107. data/lib/rmtools/proc.rb +0 -25
  108. data/lib/rmtools/range.rb +0 -100
  109. data/lib/rmtools/string.rb +0 -276
  110. data/lib/rmtools/traceback.rb +0 -106
@@ -0,0 +1,20 @@
1
+ require_with_path 'lang/ansi'
2
+
3
+ class String
4
+ # Actually, for short strings and 1251<->65001 it's much faster to use predefined ANSI2UTF and UTF2ANSI procs
5
+ def utf(from_encoding='WINDOWS-1251')
6
+ Iconv.new('UTF-8', from_encoding).iconv(self)
7
+ end
8
+
9
+ def utf!(from_encoding='WINDOWS-1251')
10
+ replace utf from_encoding
11
+ end
12
+
13
+ def ansi(from_encoding='UTF-8')
14
+ Iconv.new('WINDOWS-1251', from_encoding).iconv(self)
15
+ end
16
+
17
+ def ansi!(from_encoding='UTF-8')
18
+ replace ansi from_encoding
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ require_with_path __FILE__, '*'
@@ -0,0 +1,39 @@
1
+ require_with_path 'rand/enum'
2
+
3
+ module RMTools
4
+
5
+ def randarr(len, &b)
6
+ a = (0...len).to_a.shuffle
7
+ block_given? ? a.map!(&b) : a
8
+ end
9
+
10
+ module_function :randarr
11
+ end
12
+
13
+ class Array
14
+
15
+ def self.rand(len)
16
+ RMTools.randarr(len)
17
+ end
18
+
19
+ def rand!
20
+ delete_at Kernel.rand size
21
+ end
22
+
23
+ def randdiv(int)
24
+ dup.randdiv!(int)
25
+ end
26
+
27
+ def randdiv!(int)
28
+ len = 2*int.to_i+1
29
+ return [self] if len <= 1
30
+ newarr = []
31
+ while size > 0
32
+ lenn = Kernel.rand(len)
33
+ next if lenn < 1
34
+ newarr << slice!(0, lenn)
35
+ end
36
+ newarr
37
+ end
38
+
39
+ end
@@ -0,0 +1,26 @@
1
+ module Enumerable
2
+
3
+ def rand
4
+ if block_given?
5
+ h, ua = {}, to_a.uniq
6
+ size = ua.size
7
+ loop {
8
+ i = Kernel.rand size
9
+ if h[i]
10
+ return if h.size == s
11
+ elsif yield(e = ua[i])
12
+ return e
13
+ else h[i] = true
14
+ end
15
+ }
16
+ else to_a[Kernel.rand(size)]
17
+ end
18
+ end
19
+
20
+ def randsample(qty=Kernel.rand(size))
21
+ a, b = [], to_a.dup
22
+ qty.times {a << b.rand!}
23
+ a
24
+ end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ require_with_path 'rand/enum'
2
+
3
+ class Range
4
+
5
+ def rand
6
+ self.begin + Kernel.rand(size)
7
+ end
8
+
9
+ def randseg
10
+ (a = rand) > (b = rand) ? b..a : a..b
11
+ end
12
+
13
+ end
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ require_with_path 'lang/ansi'
3
+
2
4
  module RMTools
3
5
  begin
4
6
  require 'securerandom'
@@ -11,8 +13,8 @@ module RMTools
11
13
  Chars = 'abcdefghijklmnopqrstuvwxyz'
12
14
  Alphanum = Chars + Chars.upcase + Numbers
13
15
  ASCII_readable = '!"#$%&\'()*+,-./[\]^_`{|}~:;<=>?@ ' + Alphanum
14
- RuChars = UTF2ANSI[RU_LETTERS[0]]
15
- RuAlphanum = UTF2ANSI[RU_LETTERS.join] + Numbers
16
+ RuChars = UTF2ANSI[Cyrillic::RU_LETTERS[0]]
17
+ RuAlphanum = UTF2ANSI[Cyrillic::RU_LETTERS.join] + Numbers
16
18
 
17
19
  def randstr(len=8, what=:alphanum)
18
20
  s = ''
@@ -75,111 +77,7 @@ module RMTools
75
77
  res[0...len]
76
78
  end
77
79
 
78
- if RUBY_VERSION >= "1.8.7"
79
- def randarr(len, &b)
80
- a = (0...len).to_a.shuffle
81
- block_given? ? a.map!(&b) : a
82
- end
83
- else
84
- def randarr(len, &b)
85
- d = (0...len).to_a
86
- a = Array.new(len) {d.rand!}
87
- block_given? ? a.map!(&b) : a
88
- end
89
- end
90
-
91
- module_function :randstr, :randarr
92
- end
93
-
94
- module Enumerable
95
-
96
- def randsample(qty=Kernel.rand(size))
97
- a, b = [], to_a.dup
98
- qty.times {a << b.rand!}
99
- a
100
- end
101
-
102
- def rand(&cond)
103
- if cond
104
- a, b, s = Set.new, to_a, size
105
- loop {
106
- i = Kernel.rand s
107
- if i.in a
108
- return if a.size == s
109
- elsif !cond[e = b[i]]
110
- a << i
111
- else return e
112
- end
113
- }
114
- else to_a[Kernel.rand(size)]
115
- end
116
- end
117
-
118
- end
119
-
120
- class Range
121
-
122
- def rand
123
- self.begin + Kernel.rand(size)
124
- end
125
-
126
- def randseg
127
- (a = rand) > (b = rand) ? b..a : a..b
128
- end
129
-
130
- end
131
-
132
- class Array
133
-
134
- def self.rand(len)
135
- RMTools.randarr(len)
136
- end
137
-
138
- def rand(&cond)
139
- if cond
140
- a, s = [], size
141
- loop {
142
- i = Kernel.rand s
143
- if i.in a
144
- return if a.size == s
145
- elsif !cond[e = self[i]]
146
- a << i
147
- else return e
148
- end
149
- }
150
- else self[Kernel.rand(size)]
151
- end
152
- end
153
-
154
- def rand!
155
- delete_at Kernel.rand size
156
- end
157
-
158
- def randdiv(int)
159
- len = 2*int.to_i+1
160
- return [self] if len <= 1
161
- newarr = []
162
- arr = dup
163
- while arr.size > 0
164
- lenn = Kernel.rand(len)
165
- next if lenn < 1
166
- newarr << arr.slice!(0, lenn)
167
- end
168
- newarr
169
- end
170
-
171
- def randdiv!(int)
172
- len = 2*int.to_i+1
173
- return [self] if len <= 1
174
- newarr = []
175
- while size > 0
176
- lenn = Kernel.rand(len)
177
- next if lenn < 1
178
- newarr << slice!(0, lenn)
179
- end
180
- newarr
181
- end
182
-
80
+ module_function :randstr
183
81
  end
184
82
 
185
83
  class String
@@ -191,5 +89,13 @@ class String
191
89
  def rand(chsize=1)
192
90
  self[Kernel.rand(size*chsize), chsize]
193
91
  end
92
+
93
+ def randsubstr(chsize=1)
94
+ (a = Kernel.rand(size*chsize)) > (b = Kernel.rand(size*chsize)) ? self[b..a] : self[a..b]
95
+ end
96
+
97
+ def randsample(qty=Kernel.rand(size))
98
+ split('').randsample(qty)
99
+ end
194
100
 
195
101
  end
@@ -0,0 +1 @@
1
+ require_with_path __FILE__, '*'
@@ -0,0 +1,13 @@
1
+ module Kernel
2
+ # ` require_with_path __FILE__, "*" ' requires all ruby files from dir named as file
3
+ # ` require_with_path "folder", "file" ' requires file.rb from dir `folder' in working directory
4
+ # `require_with_path "file" ' requires 'file.rb' from working directory
5
+ def require_with_path(location, mask=nil)
6
+ if !mask
7
+ location, mask = File.dirname(__FILE__), location # /path/to/gems/rmtools
8
+ end
9
+ mask += '.rb' unless mask['.']
10
+ location = File.expand_path(location).chomp('.rb')
11
+ Dir.glob(File.join location, mask) {|file| require file}
12
+ end
13
+ end
data/lib/rmtools/setup.rb CHANGED
@@ -1,17 +1,18 @@
1
1
  # encoding: utf-8
2
- Dir.chdir(File.expand_path File.dirname __FILE__) {require 'io'; require 'boolean'}
2
+ require File.expand_path('require', File.dirname(__FILE__))
3
+ require_with_path 'fs'
3
4
  require 'digest/md5'
4
5
 
5
- def ext_files_not_modified(ext_name='rmtools')
6
+ def ext_files_not_modified(ext_name='rmtools', version='\d')
6
7
  return unless name = Gem.source_index.gems.keys.find {|n|
7
- n =~ /^#{ext_name}-\d/
8
+ n =~ /^#{ext_name}-#{version}/
8
9
  }
9
10
  gemspec = Gem.source_index.gems[name]
10
11
  full_path = gemspec.full_gem_path
11
12
  ext_files = gemspec.files.grep(/^ext\//)
12
13
  ext_files.each {|f|
13
- insalled = File.join(full_path, f)
14
- return unless File.file? insalled and Digest::SHA256.file(f) == Digest::SHA256.file(insalled)
14
+ installed = File.join(full_path, f)
15
+ return unless File.file? installed and Digest::SHA256.file(f) == Digest::SHA256.file(installed)
15
16
  }
16
17
  end
17
18
 
@@ -0,0 +1,60 @@
1
+ require_with_path 'conversions/string'
2
+
3
+ class String
4
+ CALLER_RE = %r{^\(?(.*?([^/\\]+?))#{ # ( path ( file ) )
5
+ }\)?:(\d+)(?::in #{ # :( line )[ :in
6
+ }[`<]([^'>]+)[>']#{ # `( closure )' ]
7
+ })?$}
8
+ URL_RE = %r{^((?:([^:]+)://)#{ # ( protocol
9
+ }([^/:]*(?::(\d+))?))?#{ # root[:port] )
10
+ }((/[^?#]*?(?:\.(\w+))?)#{ # ( path[.( fileext )]
11
+ }(?:\?(.*?))?)?#{ # [?( query params )] )
12
+ }(?:#(.+))?#{ # [ #( anchor ) ]
13
+ }$}
14
+ IP_RE = /\d+\.\d+\.\d+\.\d+(?::\d+)?/
15
+ IP_RANGE_RE = /(\d+\.\d+\.\d+\.\d+)\s*-\s*(\d+\.\d+\.\d+\.\d+)/
16
+
17
+ def parse(as)
18
+ case as
19
+ when :uri
20
+ m = match URL_RE
21
+ !m || m[0].empty? ?
22
+ { 'href' => self } :
23
+ { 'href' => self,
24
+ 'root' => m[1],
25
+ 'protocol' => m[2],
26
+ 'host' => m[3],
27
+ 'port' => m[4] ? m[4].to_i : 80,
28
+ 'fullpath' => m[5] || '/',
29
+ 'pathname' => m[5] || '/',
30
+ 'path' => m[6] || '',
31
+ 'ext' => m[7],
32
+ 'query' => m[8] && m[8].to_hash(false),
33
+ 'anchor' => m[9] }
34
+ when :caller
35
+ m = match CALLER_RE
36
+ m || m[0].empty? ? nil :
37
+ { 'path' => m[1],
38
+ 'file' => m[2],
39
+ 'line' => m[3].to_i,
40
+ 'func' => m[4],
41
+ 'fullpath' =>
42
+ m[1]['('] ? m[1] :
43
+ File.expand_path(m[1]) }
44
+ when :ip; self[IP_RE]
45
+ when :ip_range; (m = match IP_RANGE_RE) && m[1]..m[2]
46
+ else raise ArgumentError, "Incorrect flag. Correct flags: :uri, :caller, :ip, :ip_range"
47
+ end
48
+ end
49
+
50
+ def parseuri
51
+ deprecation "Use String#parse(:uri) instead."
52
+ parse :uri
53
+ end
54
+
55
+ def parseip(range=nil)
56
+ deprecation "Use String#parse(:ip#{'_range' if range}) instead."
57
+ parse :"ip#{'_range' if range}"
58
+ end
59
+
60
+ end
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require 'strscan'
2
3
 
3
4
  class StringScanner
4
5
  attr_reader :last
@@ -7,7 +8,7 @@ class StringScanner
7
8
  @last = 0
8
9
  res = scan_until re
9
10
  if cbs
10
- if cbs[0].kinda Integer
11
+ if cbs.keys.compact[0].is Fixnum
11
12
  while res
12
13
  if cb = cbs[matched.ord]
13
14
  cb[self]
@@ -18,7 +19,7 @@ class StringScanner
18
19
  end
19
20
  else
20
21
  while res
21
- if cb = cbs.find {|pattern, proc| pattern.in matched}
22
+ if cb = cbs.find {|pattern, proc| pattern and pattern.in matched}
22
23
  # patterns must be as explicit as possible
23
24
  cb[1][self]
24
25
  @last = pos
@@ -0,0 +1,75 @@
1
+ class String
2
+ if !method_defined? :/
3
+ alias :/ :split
4
+ end
5
+
6
+ def inline
7
+ count("\n") == 0
8
+ end
9
+
10
+ def lchomp(match)
11
+ if index(match) == 0
12
+ self[match.size..-1]
13
+ else
14
+ self.dup
15
+ end
16
+ end
17
+
18
+ def lchomp!(match)
19
+ if index(match) == 0
20
+ self[0...match.size] = ''
21
+ self
22
+ end
23
+ end
24
+
25
+ def until(splitter=$/)
26
+ split(splitter, 2)[0]
27
+ end
28
+ alias :till :until
29
+
30
+ def after(splitter=$/)
31
+ split(splitter, 2)[1]
32
+ end
33
+
34
+ # %{blah blah
35
+ # wall of text in the interpreter
36
+ # oh it's too bulky; may be we should
37
+ # save this text into variable
38
+ # blah blah} >> (str='')
39
+ # saved!
40
+ def >>(str)
41
+ str.replace(self + str)
42
+ end
43
+
44
+ # Fast search for highlighting purposes
45
+ def find_with_offsets text, offset
46
+ index = index(text)
47
+ start = [0, index - offset].max
48
+ _end = index + text.size
49
+ [self[start...index], text, self[_end, offset]]
50
+ end
51
+
52
+ # 'filename.txt'.bump!.bump!
53
+ # => "filename.txt.2"
54
+ # 'filename.txt'.bump!.bump!.bump!('_')
55
+ # => "filename.txt.2_1"
56
+ # 'filename.txt'.bump!.bump!.bump!('_').bump!
57
+ # => "filename.txt.2_1.1"
58
+ def bump!(splt='.')
59
+ replace bump_version splt
60
+ end
61
+
62
+ def bump_version(splt='.')
63
+ re = /(?:(\d*)#{Regexp.escape splt})?/
64
+ s = File.split self
65
+ s[0] == '.' ?
66
+ s[1].reverse.sub(re) {$1?"#{$1.to_i+1}#{splt}":"1#{splt}"}.reverse :
67
+ File.join(s[0], s[1].reverse.sub(re) {$1?"#{$1.to_i+1}#{splt}":"1#{splt}"}.reverse)
68
+ end
69
+ alias :next_version :bump_version
70
+
71
+ def to_re(esc=false)
72
+ Regexp.new(esc ? Regexp.escape(self) : self)
73
+ end
74
+
75
+ end
@@ -0,0 +1,148 @@
1
+ require_with_path 'text/string_simple'
2
+ require_with_path 'enumerable/array_iterators'
3
+
4
+ class String
5
+
6
+ def rsplit(splitter=$/, qty=0)
7
+ reverse.split(splitter, qty).reverse.reverses
8
+ end
9
+
10
+ # Same as split, but without :reject_splitter option keeps splitters on the left of parts
11
+ # with :report_headers option collects all regexp'ed splitters along with result array
12
+ def sharp_split(splitter, *args)
13
+ count, opts = args.fetch_opts [0, :flags], :include_splitter => true
14
+ if !opts[:report_headers] and opts[:include_splitter] and splitter.is Regexp
15
+ return split(/(?=#{splitter.source})/, count)
16
+ end
17
+ a = split(splitter, count)
18
+ return a if !opts[:include_splitter] and !opts[:report_headers]
19
+ skan = nil
20
+ case splitter
21
+ when String
22
+ skan = ([splitter]*a.size).unshift ''
23
+ a = (1...a.size).map {|i| splitter+a[i]}.unshift a[0] if opts[:include_splitter]
24
+ when Regexp
25
+ skan = scan(splitter).unshift ''
26
+ a = (0...a.size).map {|i| skan[i].to_s+a[i]} if opts[:include_splitter]
27
+ end
28
+ opts[:report_headers] ? [a, skan] : a
29
+ end
30
+
31
+ # Same as sharp_split, but without keeps splitters on the *right* of parts
32
+ def sharp_splitr(splitter, *args)
33
+ count, opts = args.fetch_opts [0, :flags], :include_splitter => true
34
+ a = split(splitter, count)
35
+ return a if !opts[:include_splitter] and !opts[:report_headers]
36
+ skan = nil
37
+ case splitter
38
+ when String
39
+ skan = [splitter]*a.size << ''
40
+ a = (0...a.size-1).map {|i| a[i]+splitter} << a[i] if opts[:include_splitter]
41
+ when Regexp
42
+ skan = scan(splitter) << ''
43
+ a = (0...a.size).map {|i| a[i]+skan[i]} if opts[:include_splitter]
44
+ end
45
+ opts[:report_headers] ? [a, skan] : a
46
+ end
47
+
48
+ def div(len, *)
49
+ if !len.is Fixnum
50
+ deprecation "Use #sharp_split instead."
51
+ return sharp_split len
52
+ end
53
+ return [self] if len <= 0
54
+ str = dup
55
+ arr = []
56
+ while str.b
57
+ arr << str.slice!(0, len)
58
+ end
59
+ arr
60
+ end
61
+
62
+ private
63
+ def split_by_syntax(str, maxlen, buflen=0)
64
+ len, add = maxlen - buflen, nil
65
+ [/[^.?!]+\z/, /[^;]+\z/, /[^\n]+/, /\S+\z/, /[^。]+z/, /[^、]+z/].each {|t|
66
+ if !(add = str[t]) or add.size <= len
67
+ return add
68
+ end
69
+ }
70
+ add
71
+ end
72
+
73
+ def sanitize_blocks!(blocks, opts)
74
+ blocks.reject! {|b| b.empty?} if opts[:no_blanks]
75
+ blocks.strips! if opts[:strips]
76
+ blocks.each {|b| raise Exception, "can't split string by #{terminator} to blocks with max length = #{maxlen}" if b.size > maxlen} if opts[:strict_overhead]
77
+ blocks
78
+ end
79
+
80
+ public
81
+ # Base smart-split method
82
+ # Keep in mind that cyrrilic in 1.8 is 2-byte long as method doesn't use cyrillic lib to not decrease speed.
83
+ def split_to_blocks(maxlen, *opts)
84
+ raise Exception, "Can't split text with maxlen = #{maxlen}" if maxlen < 1
85
+ return [self] if size <= maxlen
86
+ terminator, opts = opts.fetch_opts [nil, :flags], :strict_overhead => true, :no_blanks => true
87
+ blocks = []
88
+ term_re = /[^#{terminator}]+\z/ if terminator and terminator != :syntax
89
+ words, buf = split(opts[:strips] ? ' ' : / /), nil
90
+ while words.b or buf.b
91
+ if terminator and blocks.b and (
92
+ buf_add = if terminator == :syntax
93
+ split_by_syntax blocks[-1], maxlen, buf.size
94
+ else blocks[-1][term_re]
95
+ end.b)
96
+ if buf_add == blocks[-1]
97
+ blocks.pop
98
+ else blocks[-1] = blocks[-1][0...-buf_add.size]
99
+ end
100
+ buf = buf_add + buf
101
+ end
102
+ if blocks.size == opts[:lines]
103
+ return sanitize_blocks! blocks, opts
104
+ end
105
+ blocks << ''
106
+ if buf
107
+ blocks[-1] << buf
108
+ buf = nil
109
+ end
110
+ while words.b
111
+ buf = words.shift + ' '
112
+ break if blocks[-1].size + buf.size - 1 > maxlen
113
+ blocks[-1] << buf
114
+ buf = nil
115
+ end
116
+ end
117
+ sanitize_blocks! blocks, opts
118
+ end
119
+
120
+ # 'An elegant way to factor duplication out of options passed to a series of method calls. Each method called in the block, with the block variable as the receiver, will have its options merged with the default options hash provided. '.cut_line 100
121
+ # => "An elegant way to factor duplication out of options passed to a series of method calls..."
122
+ def cut_line(maxlen, *opts)
123
+ terminator, opts = opts.fetch_opts [:syntax, :flags]
124
+ opts[:charsize] ||= RUBY_VERSION < '1.9' && a[0].cyr? ? 2 : 1
125
+ return self if size <= maxlen
126
+ maxlen -= 3
127
+ split_to_blocks(maxlen*opts[:charsize], terminator, :strips => true, :strict_overhead => false, :lines => 1)[0][0, maxlen].chomp('.') + '...'
128
+ end
129
+
130
+ # puts 'An elegant way to factor duplication out of options passed to a series of method calls. Each method called in the block, with the block variable as the receiver, will have its options merged with the default options hash provided. '.split_to_lines 50
131
+ # produces:
132
+ # An elegant way to factor duplication out of
133
+ # options passed to a series of method calls. Each
134
+ # method called in the block, with the block
135
+ # variable as the receiver, will have its options
136
+ # merged with the default options hash provided.
137
+ #
138
+ # This method is use cyrillic lib only to detect char byte-length
139
+ # options: charsize, no_blanks, strips
140
+ def split_to_lines(maxlen, *opts)
141
+ raise Exception, "Can't break text with maxlen = #{maxlen}" if maxlen < 1
142
+ opts = opts.fetch_opts :flags, :strips=>true
143
+ a = split("\n")
144
+ opts[:charsize] ||= RUBY_VERSION < '1.9' && a[0].cyr? ? 2 : 1
145
+ a.map {|string| string.strip.split_to_blocks(maxlen*opts[:charsize], opts.merge(:strict_overhead => false))}.flatten*"\n"
146
+ end
147
+
148
+ end
@@ -0,0 +1,44 @@
1
+ module RMTools
2
+
3
+ def dump_recurse(obj, depth, maxdepth)
4
+ res = ''
5
+ case obj
6
+ when Hash
7
+ if depth <= maxdepth
8
+ res = "{\n"
9
+ obj.each { |i, j|
10
+ i = i.inspect unless i.is_a? String
11
+ childinfo = dump_recurse(j,depth+1,maxdepth)
12
+ res << "%s %s => %s、\n"%[(" "*depth), i, childinfo]
13
+ }
14
+ res << " "*depth+" }"
15
+ else
16
+ res = obj.inspect
17
+ end
18
+ res
19
+ when Array
20
+ if depth <= maxdepth
21
+ res = "[\n"
22
+ obj.each_with_index { |j, i|
23
+ childinfo = dump_recurse(j,depth+1,maxdepth)
24
+ res << "%s %0*d: %s、\n"%[(" "*depth), (obj.size-1).to_s.size, i, childinfo]
25
+ }
26
+ res << " "*depth+" ]"
27
+ else
28
+ res = obj.inspect
29
+ end
30
+ res
31
+ when String then obj
32
+ else obj.inspect
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ module Enumerable
39
+
40
+ def dump(depth=5)
41
+ RMTools.dump_recurse self, 0, depth
42
+ end
43
+
44
+ end
@@ -0,0 +1 @@
1
+ require_with_path __FILE__, '*'
@@ -0,0 +1,17 @@
1
+ module RMTools
2
+
3
+ def puttime(ms=nil)
4
+ t = Time.now
5
+ if ms
6
+ t.strftime("%H:%M:%S")+sprintf(".%03d ", t.usec/1000)
7
+ else
8
+ t.strftime("%d.%m.%y %H:%M:%S ")
9
+ end
10
+ end
11
+
12
+ def putdate
13
+ Time.now.strftime("%d.%m.%y")
14
+ end
15
+
16
+ module_function :puttime, :putdate
17
+ end