rmtools 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/Manifest.txt +84 -26
- data/Rakefile +7 -4
- data/ext/extconf.rb +1 -1
- data/ext/rmtools.cpp +27 -12
- data/ext/rmtools.h +6 -5
- data/lib/rmtools/b.rb +18 -0
- data/lib/rmtools/console/coloring.rb +72 -0
- data/lib/rmtools/console/highlight.rb +13 -0
- data/lib/rmtools/{printing.rb → console/printing.rb} +17 -2
- data/lib/rmtools/console.rb +1 -0
- data/lib/rmtools/conversions/enum.rb +23 -0
- data/lib/rmtools/conversions/int.rb +47 -0
- data/lib/rmtools/conversions/string.rb +26 -0
- data/lib/rmtools/conversions.rb +1 -0
- data/lib/rmtools/core/arguments.rb +52 -0
- data/lib/rmtools/{boolean.rb → core/boolean.rb} +0 -13
- data/lib/rmtools/core/class.rb +41 -0
- data/lib/rmtools/core/js.rb +45 -0
- data/lib/rmtools/core/kernel.rb +28 -0
- data/lib/rmtools/{module.rb → core/module.rb} +0 -41
- data/lib/rmtools/core/numeric.rb +35 -0
- data/lib/rmtools/{object.rb → core/object.rb} +2 -23
- data/lib/rmtools/core/proc.rb +18 -0
- data/lib/rmtools/core/regexp.rb +11 -0
- data/lib/rmtools/core/string_compliance.rb +31 -0
- data/lib/rmtools/core.rb +1 -0
- data/lib/rmtools/db/active_record.rb +54 -0
- data/lib/rmtools/db.rb +7 -0
- data/lib/rmtools/debug/binding.rb +56 -0
- data/lib/rmtools/debug/highlight.rb +23 -0
- data/lib/rmtools/debug/logging.rb +176 -0
- data/lib/rmtools/debug/present.rb +38 -0
- data/lib/rmtools/debug/timer.rb +19 -0
- data/lib/rmtools/debug/traceback.rb +92 -0
- data/lib/rmtools/debug.rb +1 -0
- data/lib/rmtools/debug_notrace.rb +1 -0
- data/lib/rmtools/enumerable/array.rb +134 -0
- data/lib/rmtools/enumerable/array_iterators.rb +33 -0
- data/lib/rmtools/enumerable/common.rb +49 -0
- data/lib/rmtools/{hash.rb → enumerable/hash.rb} +8 -8
- data/lib/rmtools/enumerable/object_space.rb +19 -0
- data/lib/rmtools/enumerable/range.rb +201 -0
- data/lib/rmtools/enumerable.rb +1 -0
- data/lib/rmtools/experimental/blackhole.rb +12 -0
- data/lib/rmtools/experimental/deprecation.rb +36 -0
- data/lib/rmtools/experimental/dumps.rb +28 -0
- data/lib/rmtools/{numeric.rb → experimental/numeric.rb} +22 -51
- data/lib/rmtools/experimental/rails_backtrace.rb +29 -0
- data/lib/rmtools/experimental/string.rb +56 -0
- data/lib/rmtools/{tree.rb → experimental/tree.rb} +0 -0
- data/lib/rmtools/experimental.rb +1 -0
- data/lib/rmtools/fs/dir.rb +89 -0
- data/lib/rmtools/fs/file.rb +104 -0
- data/lib/rmtools/fs/io.rb +58 -0
- data/lib/rmtools/fs/tools.rb +49 -0
- data/lib/rmtools/fs.rb +1 -0
- data/lib/rmtools/functional/fold.rb +32 -0
- data/lib/rmtools/{string_to_proc.rb → functional/string_to_proc.rb} +2 -22
- data/lib/rmtools/functional/unfold.rb +16 -0
- data/lib/rmtools/functional.rb +1 -0
- data/lib/rmtools/ip/numeric.rb +35 -0
- data/lib/rmtools/ip/string.rb +45 -0
- data/lib/rmtools/ip.rb +1 -0
- data/lib/rmtools/lang/ansi.rb +17 -0
- data/lib/rmtools/lang/cyrillic.rb +106 -0
- data/lib/rmtools/lang/regexp.rb +8 -0
- data/lib/rmtools/lang/shortcuts.rb +20 -0
- data/lib/rmtools/lang.rb +1 -0
- data/lib/rmtools/rand/array.rb +39 -0
- data/lib/rmtools/rand/enum.rb +26 -0
- data/lib/rmtools/rand/range.rb +13 -0
- data/lib/rmtools/{random.rb → rand/string.rb} +13 -107
- data/lib/rmtools/rand.rb +1 -0
- data/lib/rmtools/require.rb +13 -0
- data/lib/rmtools/setup.rb +6 -5
- data/lib/rmtools/text/string_parse.rb +60 -0
- data/lib/rmtools/{stringscanner.rb → text/string_scanner.rb} +3 -2
- data/lib/rmtools/text/string_simple.rb +75 -0
- data/lib/rmtools/text/string_split.rb +148 -0
- data/lib/rmtools/text/textilize.rb +44 -0
- data/lib/rmtools/text.rb +1 -0
- data/lib/rmtools/time/global.rb +17 -0
- data/lib/rmtools/time/russian.rb +47 -0
- data/lib/rmtools/time.rb +1 -32
- data/lib/rmtools/xml/document.rb +28 -0
- data/lib/rmtools/xml/finders.rb +84 -0
- data/lib/rmtools/xml/libxml.rb +11 -0
- data/lib/rmtools/xml/node.rb +196 -0
- data/lib/rmtools/xml/string.rb +43 -0
- data/lib/rmtools/xml/xpath.rb +32 -0
- data/lib/rmtools/xml.rb +7 -0
- data/lib/rmtools.rb +8 -44
- metadata +97 -72
- data/lib/rmtools/arguments.rb +0 -24
- data/lib/rmtools/array.rb +0 -189
- data/lib/rmtools/binding.rb +0 -23
- data/lib/rmtools/coloring.rb +0 -82
- data/lib/rmtools/cyr-time.rb +0 -49
- data/lib/rmtools/cyrilic.rb +0 -124
- data/lib/rmtools/dumps.rb +0 -192
- data/lib/rmtools/enum.rb +0 -90
- data/lib/rmtools/io.rb +0 -303
- data/lib/rmtools/js.rb +0 -25
- data/lib/rmtools/limited_string.rb +0 -17
- data/lib/rmtools/logging.rb +0 -158
- data/lib/rmtools/proc.rb +0 -25
- data/lib/rmtools/range.rb +0 -100
- data/lib/rmtools/string.rb +0 -276
- 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
|
data/lib/rmtools/lang.rb
ADDED
@@ -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
|
@@ -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
|
-
|
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
|
data/lib/rmtools/rand.rb
ADDED
@@ -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
|
-
|
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}
|
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
|
-
|
14
|
-
return unless File.file?
|
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].
|
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
|
data/lib/rmtools/text.rb
ADDED
@@ -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
|