rmtools 1.0.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.
- data/History.txt +4 -0
- data/License.txt +15 -0
- data/Manifest.txt +37 -0
- data/README.txt +10 -0
- data/Rakefile +39 -0
- data/ext/extconf.rb +12 -0
- data/ext/rmtools.cpp +529 -0
- data/ext/rmtools.h +161 -0
- data/lib/rmtools.rb +53 -0
- data/lib/rmtools/arguments.rb +24 -0
- data/lib/rmtools/array.rb +189 -0
- data/lib/rmtools/binding.rb +23 -0
- data/lib/rmtools/boolean.rb +57 -0
- data/lib/rmtools/coloring.rb +82 -0
- data/lib/rmtools/cyr-time.rb +49 -0
- data/lib/rmtools/cyrilic.rb +124 -0
- data/lib/rmtools/dumps.rb +192 -0
- data/lib/rmtools/enum.rb +90 -0
- data/lib/rmtools/hash.rb +40 -0
- data/lib/rmtools/io.rb +303 -0
- data/lib/rmtools/js.rb +25 -0
- data/lib/rmtools/limited_string.rb +17 -0
- data/lib/rmtools/logging.rb +158 -0
- data/lib/rmtools/module.rb +113 -0
- data/lib/rmtools/numeric.rb +82 -0
- data/lib/rmtools/object.rb +74 -0
- data/lib/rmtools/printing.rb +41 -0
- data/lib/rmtools/proc.rb +25 -0
- data/lib/rmtools/random.rb +195 -0
- data/lib/rmtools/range.rb +100 -0
- data/lib/rmtools/setup.rb +21 -0
- data/lib/rmtools/string.rb +276 -0
- data/lib/rmtools/string_to_proc.rb +113 -0
- data/lib/rmtools/stringscanner.rb +58 -0
- data/lib/rmtools/time.rb +32 -0
- data/lib/rmtools/traceback.rb +106 -0
- data/lib/rmtools/tree.rb +71 -0
- metadata +191 -0
data/lib/rmtools/enum.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Enumerable
|
3
|
+
|
4
|
+
def import(arr, index)
|
5
|
+
self[index] = arr[index]
|
6
|
+
end
|
7
|
+
|
8
|
+
def export(arr, index)
|
9
|
+
arr[index] = self[index]
|
10
|
+
end
|
11
|
+
|
12
|
+
def foldl(o, m=nil)
|
13
|
+
block_given? ?
|
14
|
+
reduce(m ? yield(m) : nil) {|m, i| m ? m.send(o, yield(i)) : yield(i)} :
|
15
|
+
reduce(m) {|m, i| m ? m.send(o, i) : i}
|
16
|
+
end
|
17
|
+
|
18
|
+
def foldr(o, m=nil)
|
19
|
+
block_given? ?
|
20
|
+
reverse.reduce(m ? yield(m) : nil) {|m, i| m ? yield(i).send(o, m) : yield(i)} :
|
21
|
+
reverse.reduce(m) {|m, i| m ? i.send(o, m) : i}
|
22
|
+
end
|
23
|
+
|
24
|
+
if RUBY_VERSION < "1.8.7"
|
25
|
+
def xprod(obj, inverse=false)
|
26
|
+
size = self.size
|
27
|
+
if obj.kinda Array or obj.is Set
|
28
|
+
objsize = obj.size
|
29
|
+
raise ArgumentError, "can't complement #{self.class} with void container" if objsize == 0
|
30
|
+
if size == 1
|
31
|
+
case objsize
|
32
|
+
when 1 then inverse ? [[obj.first, first]] : [[first, obj.first]]
|
33
|
+
else obj.xprod_one first, !inverse
|
34
|
+
end
|
35
|
+
else
|
36
|
+
case objsize
|
37
|
+
when 1 then xprod_one obj.first, inverse
|
38
|
+
else xprod_many obj, inverse
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else xprod_one obj, inverse
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
def xprod_one(obj, inverse)
|
47
|
+
inverse ? map {|te| [obj, te]} : map {|te| [te, obj]}
|
48
|
+
end
|
49
|
+
|
50
|
+
def xprod_many(obj, inverse)
|
51
|
+
a = []
|
52
|
+
inverse ?
|
53
|
+
obj.each {|oe| each {|te| a << [oe, te]}} :
|
54
|
+
each {|te| obj.each {|oe| a << [te, oe]}}
|
55
|
+
a
|
56
|
+
end
|
57
|
+
else
|
58
|
+
def xprod(obj, inverse=false)
|
59
|
+
obj = obj.to_a if obj.is Set
|
60
|
+
obj = [obj] if !obj.kinda(Array)
|
61
|
+
inverse ? obj.to_a.product(self) : product(obj)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
module ObjectSpace
|
68
|
+
extend Enumerable
|
69
|
+
|
70
|
+
def self.each(&b) self.each_object(&b) end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class Object
|
75
|
+
|
76
|
+
# block must return a pair
|
77
|
+
def unfold(break_if=lambda{|x|x==0}, &splitter)
|
78
|
+
obj, container = self, []
|
79
|
+
until begin
|
80
|
+
result = splitter[obj]
|
81
|
+
container.unshift result[1]
|
82
|
+
break_if[result[0]]
|
83
|
+
end
|
84
|
+
obj = result[0]
|
85
|
+
end
|
86
|
+
container
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
data/lib/rmtools/hash.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Hash
|
3
|
+
|
4
|
+
def +(other_hash)
|
5
|
+
merge(other_hash || {})
|
6
|
+
end
|
7
|
+
|
8
|
+
def concat(other_hash)
|
9
|
+
merge!(other_hash || {})
|
10
|
+
end
|
11
|
+
|
12
|
+
def unify_strs
|
13
|
+
each {|k, v|
|
14
|
+
if k.is String
|
15
|
+
sk = k.to_sym
|
16
|
+
self[sk] = v if !self[sk]
|
17
|
+
elsif k.is Symbol
|
18
|
+
sk = k.to_s
|
19
|
+
self[sk] = v if !self[sk]
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def max; [(m = keys.max), self[m]] end
|
25
|
+
|
26
|
+
def min; [(m = keys.min), self[m]] end
|
27
|
+
|
28
|
+
# should be overriden by extension maps
|
29
|
+
def map2
|
30
|
+
h = {}
|
31
|
+
each {|k, v| h[k] = yield(k,v)}
|
32
|
+
h
|
33
|
+
end
|
34
|
+
|
35
|
+
def map!
|
36
|
+
each {|k, v| self[k] = yield(k,v)}
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/rmtools/io.rb
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Dir
|
3
|
+
|
4
|
+
def include?(name)
|
5
|
+
#content.map {|f| File.split(f)[1]}.include? name
|
6
|
+
entries.include? name
|
7
|
+
end
|
8
|
+
|
9
|
+
def recursive_content(flat=true)
|
10
|
+
list = []
|
11
|
+
cont = content.map {|f|
|
12
|
+
if File.directory?(f)
|
13
|
+
rc = Dir.new(f).recursive_content.map {|f| f.sub(/^\.\//, '')}
|
14
|
+
flat ? list.concat(rc) : rc
|
15
|
+
else flat ? (list << f) : f
|
16
|
+
end
|
17
|
+
}
|
18
|
+
(flat ? list : cont)
|
19
|
+
end
|
20
|
+
|
21
|
+
def content
|
22
|
+
Dir["#{path}/**"].b || to_a[2..-1].sort.map {|c| File.join path, c}
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent
|
26
|
+
newpath = File.dirname(path)
|
27
|
+
Dir.new(newpath) if newpath != path
|
28
|
+
end
|
29
|
+
|
30
|
+
def child(idx)
|
31
|
+
df = content[idx]
|
32
|
+
if File.file?(df)
|
33
|
+
File.new(df)
|
34
|
+
elsif File.directory?(df)
|
35
|
+
Dir.new(df)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def children
|
40
|
+
content.map {|df|
|
41
|
+
if File.file?(df)
|
42
|
+
File.new(df)
|
43
|
+
elsif File.directory?(df)
|
44
|
+
Dir.new(df)
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def refresh
|
50
|
+
return if !File.directory?(path)
|
51
|
+
Dir.new(path)
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
displaypath = case path
|
56
|
+
when /^(\/|\w:)/ then path
|
57
|
+
when /^\./ then File.join(Dir.pwd, path[1..-1])
|
58
|
+
else File.join(Dir.pwd, path)
|
59
|
+
end
|
60
|
+
"<#Dir \"#{displaypath}\" #{to_a.size - 2} elements>"
|
61
|
+
end
|
62
|
+
|
63
|
+
def name
|
64
|
+
File.basename(path)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Fixing windoze path problems
|
68
|
+
# requires amatch gem for better performance
|
69
|
+
def real_name
|
70
|
+
n, p, count = name, parent, []
|
71
|
+
return n if !p
|
72
|
+
pp, pc, sc = parent.path, parent.to_a[2..-1], to_a
|
73
|
+
if defined? Amatch
|
74
|
+
ms = pc.sizes.max
|
75
|
+
count = [:hamming_similar, :levenshtein_similar, :jaro_similar].sum {|m| pc.group_by {|_| _.upcase.ljust(ms).send(m, n)}.max[1]}.count.to_a
|
76
|
+
max = count.lasts.max
|
77
|
+
res = count.find {|c|
|
78
|
+
c[1] == max and File.directory?(df=File.join(pp, c[0])) and Dir.new(df).to_a == sc
|
79
|
+
}
|
80
|
+
return res[0] if res
|
81
|
+
end
|
82
|
+
(pc - count).find {|c|
|
83
|
+
File.directory?(df=File.join(pp, c)) and Dir.new(df).to_a == sc
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
class File
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
"<#File \"#{path}\" #{closed? ? 'closed' : stat.size.bytes}>"
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.include?(name, str)
|
96
|
+
f = new name, 'r'
|
97
|
+
incl = f.include? str
|
98
|
+
f.close
|
99
|
+
incl
|
100
|
+
end
|
101
|
+
|
102
|
+
def include?(str)
|
103
|
+
while s = gets do return true if s.include? str end
|
104
|
+
end
|
105
|
+
|
106
|
+
def parent
|
107
|
+
newpath = File.dirname(path)
|
108
|
+
Dir.new(newpath) if newpath != path
|
109
|
+
end
|
110
|
+
|
111
|
+
def name
|
112
|
+
File.basename(path)
|
113
|
+
end
|
114
|
+
|
115
|
+
def ext
|
116
|
+
name[/[^.]+$/]
|
117
|
+
end
|
118
|
+
|
119
|
+
def refresh
|
120
|
+
return if !File.file?(path)
|
121
|
+
close
|
122
|
+
File.new(path,'r')
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.modify(file, bak=true)
|
126
|
+
orig_text = read file
|
127
|
+
text = yield orig_text
|
128
|
+
rename file, file+'.bak' if bak
|
129
|
+
RMTools.rw(file, text.is(String) ? text : orig_text)
|
130
|
+
end
|
131
|
+
|
132
|
+
def cp(df)
|
133
|
+
dir = File.dirname df
|
134
|
+
FileUtils.mkpath dir unless File.directory? dir
|
135
|
+
FileUtils.cp path, df
|
136
|
+
end
|
137
|
+
|
138
|
+
def mv(df)
|
139
|
+
dir = File.dirname df
|
140
|
+
FileUtils.mkpath dir unless File.directory? dir
|
141
|
+
rename df
|
142
|
+
end
|
143
|
+
|
144
|
+
# Fixing windoze path problems
|
145
|
+
# requires amatch gem for better performance
|
146
|
+
def real_name
|
147
|
+
n, p, count = name, parent, []
|
148
|
+
pp, pc, ss = parent.path, parent.to_a[2..-1], stat
|
149
|
+
ms = pc.sizes.max
|
150
|
+
n, ext = n.rsplit('.', 2)
|
151
|
+
if ext
|
152
|
+
re = /\.#{ext}$/i
|
153
|
+
pc.reject! {|f| !f[re]}
|
154
|
+
end
|
155
|
+
if defined? Amatch
|
156
|
+
count = [:hamming_similar, :levenshtein_similar, :jaro_similar].sum {|m| pc.group_by {|f| (ext ? f[0..-(ext.size+2)] : f).upcase.ljust(ms).send(m, n)}.max[1]}.count.to_a
|
157
|
+
max = count.lasts.max
|
158
|
+
res = count.find {|c|
|
159
|
+
c[1] == max and File.file?(df=File.join(pp, c[0])) and File.stat(df) == ss
|
160
|
+
}
|
161
|
+
return res[0] if res
|
162
|
+
end
|
163
|
+
(pc - count).find {|c|
|
164
|
+
File.file?(df=File.join(pp, c)) and File.stat(df) == ss
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
PathMemo = {} if !defined? PathMemo
|
169
|
+
def self.real_path path, memo=1
|
170
|
+
a = expand_path(path).split(/[\/\\]/)
|
171
|
+
a.each_index {|i|
|
172
|
+
if a[j=-(i+1)]['~']
|
173
|
+
n = i+2>a.size ? a[j] : join(a[0..-(i+2)], a[j])
|
174
|
+
a[j] = PathMemo[n] || real_name(n)
|
175
|
+
PathMemo[n] = a[j] if memo
|
176
|
+
else break
|
177
|
+
end
|
178
|
+
}
|
179
|
+
a*'/'
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.real_name(df)
|
183
|
+
if file?(df)
|
184
|
+
new(df).real_name
|
185
|
+
elsif directory?(df)
|
186
|
+
Dir.new(df).real_name
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
class IO
|
193
|
+
|
194
|
+
def gets2
|
195
|
+
str = ''
|
196
|
+
str << (c = read 1) until c and "\r\n\b".include? c or eof?
|
197
|
+
str
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
module RMTools
|
203
|
+
|
204
|
+
def tick!
|
205
|
+
print %W{|\b /\b -\b \\\b +\b X\b}.rand
|
206
|
+
end
|
207
|
+
|
208
|
+
def executing? file
|
209
|
+
caller(0)[0] =~ /^#{file}:/
|
210
|
+
end
|
211
|
+
|
212
|
+
def rw(df, value=nil)
|
213
|
+
return false if value.nil?
|
214
|
+
df.gsub!('\\', '/')
|
215
|
+
path = File.dirname(df)
|
216
|
+
FileUtils.mkpath(path) if !File.directory?(path)
|
217
|
+
mode = RUBY_VERSION > '1.9' ? :wb : 'wb'
|
218
|
+
File.open(df, mode) {|f| f << value}
|
219
|
+
value.size
|
220
|
+
end
|
221
|
+
|
222
|
+
def write(df, value='', pos=0)
|
223
|
+
return false if value.nil?
|
224
|
+
df.gsub!('\\', '/')
|
225
|
+
path = File.dirname(df)
|
226
|
+
FileUtils.mkpath(path) if !File.directory?(path)
|
227
|
+
if pos == 0
|
228
|
+
mode = RUBY_VERSION > '1.9' ? :ab : 'ab'
|
229
|
+
File.open(df, mode) {|f| f << value}
|
230
|
+
else
|
231
|
+
if pos < 0
|
232
|
+
raise IndexError, "file #{df} does not exist, can't write from position #{pos}" if !File.file?(df)
|
233
|
+
raise IndexError, "file #{df} is shorter than #{(-pos).bytes}, can't write from position #{pos}" if (size = File.size(df)) < -pos
|
234
|
+
pos = size + pos
|
235
|
+
end
|
236
|
+
File.open(df, 'r+') {|f| f.pos = pos; f << value}
|
237
|
+
end
|
238
|
+
value.size
|
239
|
+
end
|
240
|
+
|
241
|
+
def read(df, mode='rb')
|
242
|
+
df.gsub!('\\', '/')
|
243
|
+
if !File.file?(df)
|
244
|
+
$log.debug "#{df} is missed!"
|
245
|
+
else
|
246
|
+
File.open(df, mode) {|f| f.read}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def read_lines(df, *lines)
|
251
|
+
return if !lines or lines.empty?
|
252
|
+
str = ""
|
253
|
+
last = lines.max
|
254
|
+
if !File.file?(df)
|
255
|
+
puts "#{df} is missed!"
|
256
|
+
else
|
257
|
+
File.open(df, 'r') {|f|
|
258
|
+
f.each {|line|
|
259
|
+
no = f.lineno
|
260
|
+
str << line if no.in lines
|
261
|
+
break if no == last
|
262
|
+
}}
|
263
|
+
str
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def highlighted_line(file, line)
|
268
|
+
if defined? SCRIPT_LINES__
|
269
|
+
" >> #{Painter.green SCRIPT_LINES__[file][line.to_i - 1].chop}" if SCRIPT_LINES__[file]
|
270
|
+
else
|
271
|
+
file = Readline::TEMPLOG if file == '(irb)' and defined? Readline::TEMPLOG
|
272
|
+
" >> #{Painter.green read_lines(file, line.to_i).chop}" if File.file? file
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def tail(file, bytes=1000)
|
277
|
+
if !File.file?(file)
|
278
|
+
puts "#{file} is missed!"
|
279
|
+
else
|
280
|
+
IO.read(file, bytes, File.size(file)-bytes)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def tail_n(file, qty=10)
|
285
|
+
if !File.file?(file)
|
286
|
+
return puts "#{file} is missed!"
|
287
|
+
end
|
288
|
+
size = File.size(file)
|
289
|
+
lines = []
|
290
|
+
strlen = 0
|
291
|
+
step = qty*100
|
292
|
+
while qty > 0 and (offset = size-strlen-step) >= 0 and (str = IO.read(file, step, offset)).b
|
293
|
+
i = str.index("\n") || str.size
|
294
|
+
strlen += step - i
|
295
|
+
new_lines = str[i+1..-1]/"\n"
|
296
|
+
qty -= new_lines.size
|
297
|
+
lines = new_lines.concat(lines)
|
298
|
+
end
|
299
|
+
lines[-qty..-1]
|
300
|
+
end
|
301
|
+
|
302
|
+
module_function :tick!, :executing?, :rw, :write, :read, :read_lines, :highlighted_line, :tail, :tail_n
|
303
|
+
end
|
data/lib/rmtools/js.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class Hash
|
3
|
+
|
4
|
+
def method_missing(met, *args)
|
5
|
+
str = met.id2name
|
6
|
+
if str[/=$/]
|
7
|
+
self[str[0..-2]] = args[0]
|
8
|
+
else
|
9
|
+
raise NoMethodError, "undefined method `#{str}' for #{self}:#{(self.class)}" if !args.empty?
|
10
|
+
a = self[str]
|
11
|
+
(a == default) ? self[met] : a
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class String
|
18
|
+
if !method_defined? :plus
|
19
|
+
alias :plus :+ end
|
20
|
+
|
21
|
+
def +(str)
|
22
|
+
plus str.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|