riel 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +0 -0
- data/lib/riel/ansicolor.rb +93 -0
- data/lib/riel/array.rb +20 -0
- data/lib/riel/command.rb +30 -0
- data/lib/riel/date.rb +16 -0
- data/lib/riel/dir.rb +90 -0
- data/lib/riel/enumerable.rb +66 -0
- data/lib/riel/env.rb +49 -0
- data/lib/riel/file.rb +212 -0
- data/lib/riel/filetype.rb +189 -0
- data/lib/riel/hash.rb +12 -0
- data/lib/riel/io.rb +20 -0
- data/lib/riel/log.rb +548 -0
- data/lib/riel/matchdata.rb +13 -0
- data/lib/riel/optproc.rb +369 -0
- data/lib/riel/pathname.rb +16 -0
- data/lib/riel/rcfile.rb +35 -0
- data/lib/riel/regexp.rb +152 -0
- data/lib/riel/setdiff.rb +53 -0
- data/lib/riel/size_converter.rb +62 -0
- data/lib/riel/string.rb +81 -0
- data/lib/riel/tempfile.rb +28 -0
- data/lib/riel/text.rb +408 -0
- data/lib/riel/timer.rb +52 -0
- data/lib/riel.rb +13 -0
- data/test/riel/array_test.rb +22 -0
- data/test/riel/command_test.rb +28 -0
- data/test/riel/date_test.rb +17 -0
- data/test/riel/dir_test.rb +98 -0
- data/test/riel/enumerable_test.rb +27 -0
- data/test/riel/env_test.rb +52 -0
- data/test/riel/file_test.rb +242 -0
- data/test/riel/filetype_test.rb +32 -0
- data/test/riel/hash_test.rb +12 -0
- data/test/riel/io_test.rb +22 -0
- data/test/riel/log_test.rb +184 -0
- data/test/riel/matchdata_test.rb +15 -0
- data/test/riel/optproc_test.rb +233 -0
- data/test/riel/pathname_test.rb +36 -0
- data/test/riel/rcfile_test.rb +44 -0
- data/test/riel/regexp_test.rb +24 -0
- data/test/riel/setdiff_test.rb +26 -0
- data/test/riel/size_converter_test.rb +64 -0
- data/test/riel/string_test.rb +58 -0
- data/test/riel/tempfile_test.rb +16 -0
- data/test/riel/text_test.rb +102 -0
- data/test/riel/timer_test.rb +43 -0
- metadata +134 -0
data/lib/riel/optproc.rb
ADDED
@@ -0,0 +1,369 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'riel/env'
|
5
|
+
require 'riel/log'
|
6
|
+
require 'riel/text'
|
7
|
+
require 'riel/enumerable'
|
8
|
+
|
9
|
+
|
10
|
+
module OptProc
|
11
|
+
|
12
|
+
class Option
|
13
|
+
include Loggable
|
14
|
+
|
15
|
+
attr_reader :md, :tags, :res
|
16
|
+
|
17
|
+
ARG_INTEGER = %r{^ ([\-\+]?\d+) $ }x
|
18
|
+
ARG_FLOAT = %r{^ ([\-\+]?\d* (?:\.\d+)?) $ }x
|
19
|
+
ARG_STRING = %r{^ [\"\']? (.*?) [\"\']? $ }x
|
20
|
+
ARG_BOOLEAN = %r{^ (yes|true|on|no|false|off) $ }ix
|
21
|
+
|
22
|
+
ARG_TYPES = Array.new
|
23
|
+
ARG_TYPES << [ :integer, ARG_INTEGER ]
|
24
|
+
ARG_TYPES << [ :float, ARG_FLOAT ]
|
25
|
+
ARG_TYPES << [ :string, ARG_STRING ]
|
26
|
+
ARG_TYPES << [ :boolean, ARG_BOOLEAN ]
|
27
|
+
|
28
|
+
def initialize(args = Hash.new, &blk)
|
29
|
+
@tags = args[:tags] || Array.new
|
30
|
+
@rc = args[:rc]
|
31
|
+
@rc = [ @rc ] if @rc.kind_of?(String)
|
32
|
+
@md = nil
|
33
|
+
@set = blk || args[:set]
|
34
|
+
|
35
|
+
@type = nil
|
36
|
+
@valuere = nil
|
37
|
+
|
38
|
+
@argtype = nil
|
39
|
+
|
40
|
+
@res = args[:res]
|
41
|
+
@res = [ @res ] if @res.kind_of?(Regexp)
|
42
|
+
|
43
|
+
if args[:arg]
|
44
|
+
# log { "args.class: #{args[:arg].class}" }
|
45
|
+
demargs = args[:arg].dup
|
46
|
+
while arg = demargs.shift
|
47
|
+
# log { "arg: #{arg}" }
|
48
|
+
case arg
|
49
|
+
when :required
|
50
|
+
@type = "required"
|
51
|
+
when :optional
|
52
|
+
@type = "optional"
|
53
|
+
when :none
|
54
|
+
@type = nil
|
55
|
+
when :regexp
|
56
|
+
@valuere = demargs.shift
|
57
|
+
else
|
58
|
+
if re = ARG_TYPES.assoc(arg)
|
59
|
+
# log { "re: #{re}" }
|
60
|
+
@valuere = re[1]
|
61
|
+
@argtype = arg
|
62
|
+
@type ||= "required"
|
63
|
+
else
|
64
|
+
# log { "no expression for arg #{arg}" }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# log { "valuere: #{@valuere}" }
|
71
|
+
# log { "type: #{@type}" }
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
'[' + @tags.collect { |t| t.inspect }.join(" ") + ']'
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_str
|
79
|
+
to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_s
|
83
|
+
@tags.join(" ")
|
84
|
+
end
|
85
|
+
|
86
|
+
def match_rc?(field)
|
87
|
+
@rc && @rc.include?(field)
|
88
|
+
end
|
89
|
+
|
90
|
+
def match_value(val)
|
91
|
+
# log { "valuere: #{@valuere.inspect}; val: #{val}" }
|
92
|
+
@md = @valuere && @valuere.match(val)
|
93
|
+
# log { "md: #{@md.inspect}" }
|
94
|
+
@md && @md[1]
|
95
|
+
end
|
96
|
+
|
97
|
+
def match_tag(tag)
|
98
|
+
stack { "@rc: #{@rc.inspect}; @tags: #{@tags.inspect}" }
|
99
|
+
|
100
|
+
if tm = @tags.detect do |t|
|
101
|
+
log { "t: #{t}; tag: #{tag}; idx: #{t.index(tag)}" }
|
102
|
+
t.index(tag) == 0 && tag.length <= t.length
|
103
|
+
end
|
104
|
+
|
105
|
+
log { "tm: #{tm}" }
|
106
|
+
if tag.length == tm.length
|
107
|
+
1.0
|
108
|
+
else
|
109
|
+
len = tag.length.to_f * 0.01 # / tm.length
|
110
|
+
log { "len: #{len}" }
|
111
|
+
len
|
112
|
+
end
|
113
|
+
else
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def match(args, opt = args[0])
|
119
|
+
return nil unless %r{^-}.match(opt)
|
120
|
+
|
121
|
+
# log { "opt: #{opt.inspect}; args: #{args.inspect}" }
|
122
|
+
# log { "@rc: #{@rc.inspect}; @re: #{@re.inspect}; @tags: #{@tags.inspect}" }
|
123
|
+
|
124
|
+
tag, val = opt.split('=', 2)
|
125
|
+
tag ||= opt
|
126
|
+
|
127
|
+
# log { "opt: #{opt}; opt: #{opt.class}; tag: #{tag}; tags: #{@tags.inspect}" }
|
128
|
+
# log { "res: #{@res.inspect}" }
|
129
|
+
|
130
|
+
@md = nil
|
131
|
+
|
132
|
+
if @res && (@md = @res.collect { |re| re.match(opt) }.detect)
|
133
|
+
# log { "matched: #{@md}" }
|
134
|
+
1.0
|
135
|
+
else
|
136
|
+
match_tag(tag)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_value(args, opt = args[0])
|
141
|
+
tag, val = opt.split('=', 2)
|
142
|
+
args.shift
|
143
|
+
|
144
|
+
# log { "opt : #{opt}" }
|
145
|
+
# log { "tag : #{tag}" }
|
146
|
+
# log { "tags: #{@tags.inspect}" }
|
147
|
+
# log { "val : #{val.inspect}" }
|
148
|
+
# log { "md : #{@md.inspect}" }
|
149
|
+
|
150
|
+
if @md
|
151
|
+
# log { "already have match data" }
|
152
|
+
elsif @type == "required"
|
153
|
+
if val
|
154
|
+
# already have value
|
155
|
+
# log { "already have value: #{val}" }
|
156
|
+
elsif args.size > 0
|
157
|
+
val = args.shift
|
158
|
+
# log { "got next value: #{val}" }
|
159
|
+
else
|
160
|
+
$stderr.puts "value expected"
|
161
|
+
end
|
162
|
+
|
163
|
+
if val
|
164
|
+
match_value(val)
|
165
|
+
end
|
166
|
+
elsif @type == "optional"
|
167
|
+
if val
|
168
|
+
# log { "already have value: #{val}" }
|
169
|
+
match_value(val)
|
170
|
+
elsif args.size > 0
|
171
|
+
if %r{^-}.match(args[0])
|
172
|
+
# log { "skipping next value; apparently option" }
|
173
|
+
elsif match_value(args[0])
|
174
|
+
# log { "value matches: #{val}" }
|
175
|
+
args.shift
|
176
|
+
else
|
177
|
+
# log { "value does not match" }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
else
|
181
|
+
# log { "no type" }
|
182
|
+
end
|
183
|
+
|
184
|
+
value = value_from_match
|
185
|
+
|
186
|
+
set(value, opt, args)
|
187
|
+
end
|
188
|
+
|
189
|
+
def value_from_match
|
190
|
+
if @md
|
191
|
+
if @argtype.nil? || @argtype == :regexp
|
192
|
+
@md
|
193
|
+
else
|
194
|
+
convert_value(@md[1])
|
195
|
+
end
|
196
|
+
elsif @argtype == :boolean
|
197
|
+
true
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def convert_value(val)
|
202
|
+
if val
|
203
|
+
case @argtype
|
204
|
+
when :string
|
205
|
+
val
|
206
|
+
when :integer
|
207
|
+
val.to_i
|
208
|
+
when :float
|
209
|
+
val.to_f
|
210
|
+
when :boolean
|
211
|
+
to_boolean(val)
|
212
|
+
when :regexp
|
213
|
+
val
|
214
|
+
when nil
|
215
|
+
val
|
216
|
+
else
|
217
|
+
log { "unknown argument type: #{@type.inspect}" }
|
218
|
+
end
|
219
|
+
elsif @argtype == :boolean
|
220
|
+
true
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_boolean(val)
|
225
|
+
%w{ yes true on soitenly }.include?(val.downcase)
|
226
|
+
end
|
227
|
+
|
228
|
+
def set(val, opt = nil, args = nil)
|
229
|
+
# log { "argtype: #{@argtype}; md: #{@md.inspect}" }
|
230
|
+
|
231
|
+
setargs = [ val, opt, args ].select_with_index { |x, i| i < @set.arity }
|
232
|
+
# log "val: #{val}"
|
233
|
+
@set.call(*setargs)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
class OptionSet
|
239
|
+
include Loggable
|
240
|
+
|
241
|
+
attr_reader :options
|
242
|
+
|
243
|
+
def initialize(data)
|
244
|
+
@options = Array.new
|
245
|
+
@shortopts = Array.new
|
246
|
+
@longopts = Array.new
|
247
|
+
@regexps = Hash.new
|
248
|
+
|
249
|
+
data.each do |optdata|
|
250
|
+
opt = OptProc::Option.new(optdata)
|
251
|
+
@options << opt
|
252
|
+
|
253
|
+
opt.tags.each do |tag|
|
254
|
+
ch = tag[0]
|
255
|
+
if ch == 45 # 45 = '-'
|
256
|
+
ch = tag[1]
|
257
|
+
assocopts = nil
|
258
|
+
if ch == tag
|
259
|
+
ch = tag[2]
|
260
|
+
assocopts = @longopts
|
261
|
+
else
|
262
|
+
assocopts = @shortopts
|
263
|
+
end
|
264
|
+
|
265
|
+
(assocopts[ch] ||= Array.new) << opt
|
266
|
+
end
|
267
|
+
|
268
|
+
if res = opt.res
|
269
|
+
res.each do |re|
|
270
|
+
(@regexps[re] ||= Array.new) << opt
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
if false
|
277
|
+
[ @longopts, @shortopts ].each do |list|
|
278
|
+
list.each_with_index do |v, idx|
|
279
|
+
log { "#{idx} => #{v.inspect}" }
|
280
|
+
end
|
281
|
+
end
|
282
|
+
[ @regexps ].each do |map|
|
283
|
+
map.each do |k, v|
|
284
|
+
log { "#{k} => #{v.inspect}" }
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
COMBINED_OPTS_RES = [
|
292
|
+
# -number non-num, then anything
|
293
|
+
Regexp.new('^ ( - \d+ ) ( \D+.* ) $ ', Regexp::EXTENDED),
|
294
|
+
# -letter anything
|
295
|
+
Regexp.new('^ ( - [a-z] ) ( .+ ) $ ', Regexp::EXTENDED)
|
296
|
+
]
|
297
|
+
|
298
|
+
def process_option(args)
|
299
|
+
opt = args[0]
|
300
|
+
|
301
|
+
# log { "processing option #{opt}" }
|
302
|
+
|
303
|
+
if md = COMBINED_OPTS_RES.collect { |re| re.match(opt) }.detect
|
304
|
+
lhs = md[1]
|
305
|
+
rhs = "-" + md[2]
|
306
|
+
|
307
|
+
# log { "lhs, rhs: #{lhs.inspect}, #{rhs.inspect}" }
|
308
|
+
|
309
|
+
args[0, 1] = lhs, rhs
|
310
|
+
|
311
|
+
return process_option(args)
|
312
|
+
elsif opt[0] == 45
|
313
|
+
ch = opt[1]
|
314
|
+
assocopts = if ch == 45 # 45 = '-'
|
315
|
+
ch = opt[2]
|
316
|
+
@longopts[ch]
|
317
|
+
elsif ch.nil?
|
318
|
+
nil
|
319
|
+
else
|
320
|
+
@shortopts[ch]
|
321
|
+
end
|
322
|
+
|
323
|
+
# log { "opts: #{assocopts.inspect}" }
|
324
|
+
if assocopts && x = set_option(assocopts, args)
|
325
|
+
return x
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
if x = set_option(@options, args)
|
330
|
+
return x
|
331
|
+
elsif @bestmatch
|
332
|
+
# what's the best match here ...?
|
333
|
+
log { "bestmatch: #{@bestmatch}" }
|
334
|
+
log { "bestopts : #{@bestopts.inspect}" }
|
335
|
+
if @bestopts.size == 1
|
336
|
+
@bestopts[0].set_value(args)
|
337
|
+
return @bestopts[0]
|
338
|
+
else
|
339
|
+
optstr = @bestopts.collect { |x| '(' + x.tags.join(', ') + ')' }.join(', ')
|
340
|
+
$stderr.puts "ERROR: ambiguous match of '#{args[0]}'; matches options: #{optstr}"
|
341
|
+
exit 2
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
nil
|
346
|
+
end
|
347
|
+
|
348
|
+
def set_option(optlist, args)
|
349
|
+
@bestmatch = nil
|
350
|
+
@bestopts = Array.new
|
351
|
+
|
352
|
+
optlist.each do |option|
|
353
|
+
if mv = option.match(args)
|
354
|
+
if mv >= 1.0
|
355
|
+
# exact match:
|
356
|
+
option.set_value(args)
|
357
|
+
return option
|
358
|
+
elsif !@bestmatch || @bestmatch <= mv
|
359
|
+
@bestmatch = mv
|
360
|
+
@bestopts << option
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
nil
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'riel/string'
|
6
|
+
|
7
|
+
|
8
|
+
class Pathname
|
9
|
+
|
10
|
+
# a compliment to the +dirname+, +basename+, and +extname+ family, this returns
|
11
|
+
# the basename without the extension, e.g. "foo" from "/usr/share/lib/foo.bar".
|
12
|
+
def rootname
|
13
|
+
basename.to_s - extname.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/riel/rcfile.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
|
5
|
+
# Represents a resource file, where '#' is used to comment to end of lines, and
|
6
|
+
# name/value pairs are separated by '=' or ':'.
|
7
|
+
|
8
|
+
class RCFile
|
9
|
+
|
10
|
+
attr_reader :settings
|
11
|
+
|
12
|
+
# Reads the RC file, if it exists, and if a block is passed, calls the block
|
13
|
+
# with each name/value pair, which are also accessible via
|
14
|
+
# <code>settings</code>.
|
15
|
+
|
16
|
+
def initialize(fname, &blk)
|
17
|
+
@settings = Array.new
|
18
|
+
|
19
|
+
if File.exists?(fname)
|
20
|
+
IO.readlines(fname).each do |line|
|
21
|
+
line.sub!(/\s*#.*/, "")
|
22
|
+
line.chomp!
|
23
|
+
name, value = line.split(/\s*[=:]\s*/)
|
24
|
+
if name && value
|
25
|
+
name.strip!
|
26
|
+
value.strip!
|
27
|
+
@settings << [ name, value ]
|
28
|
+
if blk
|
29
|
+
blk.call(name, value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/riel/regexp.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
# Negates the given expression.
|
5
|
+
class NegatedRegexp < Regexp
|
6
|
+
|
7
|
+
def match(str)
|
8
|
+
!super
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class Regexp
|
14
|
+
|
15
|
+
# shell expressions to Ruby regular expression sequences
|
16
|
+
SH2RE = Hash[
|
17
|
+
'*' => '.*',
|
18
|
+
'?' => '.',
|
19
|
+
# '[' => '\[',
|
20
|
+
# ']' => '\]',
|
21
|
+
'.' => '\.',
|
22
|
+
'$' => '\$',
|
23
|
+
'/' => '\/',
|
24
|
+
'(' => '\(',
|
25
|
+
')' => '\)',
|
26
|
+
]
|
27
|
+
|
28
|
+
# Returns a regular expression for the given Unix file system expression.
|
29
|
+
|
30
|
+
def self.unixre_to_string(pat)
|
31
|
+
pat.gsub(%r{(\\.)|(.)}) do
|
32
|
+
$1 || SH2RE[$2] || $2
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
WORD_START_RE = Regexp.new('^ # start of word
|
37
|
+
[\[\(]* # parentheses or captures, maybe
|
38
|
+
(?: \\\w | \\w) # literal \w, or what \w matches
|
39
|
+
',
|
40
|
+
Regexp::EXTENDED)
|
41
|
+
|
42
|
+
WORD_END_RE = Regexp.new('(?: # one of the following:
|
43
|
+
\\\w # - \w for regexp
|
44
|
+
| #
|
45
|
+
\w # - a literal A-Z, a-z, 0-9, or _
|
46
|
+
| #
|
47
|
+
(?: # - one of the following:
|
48
|
+
\[[^\]]* # LB, with no RB until:
|
49
|
+
(?: # - either of:
|
50
|
+
\\w # - "\w"
|
51
|
+
| #
|
52
|
+
\w # - a literal A-Z, a-z, 0-9, or _
|
53
|
+
) #
|
54
|
+
[^\]]*\] # - anything (except RB) to the next RB
|
55
|
+
) #
|
56
|
+
) #
|
57
|
+
(?: # optionally, one of the following:
|
58
|
+
\* # - "*"
|
59
|
+
| #
|
60
|
+
\+ # - "+"
|
61
|
+
| #
|
62
|
+
\? # - "?"
|
63
|
+
| #
|
64
|
+
\{\d*,\d*\} # - "{3,4}", "{,4}, "{,123}" (also matches the invalid {,})
|
65
|
+
)? #
|
66
|
+
$ # fin
|
67
|
+
',
|
68
|
+
Regexp::EXTENDED)
|
69
|
+
|
70
|
+
# Handles negation, whole words, and ignore case (Ruby no longer supports
|
71
|
+
# Rexexp.new(/foo/i), as of 1.8).
|
72
|
+
|
73
|
+
def self.create(pat, args = Hash.new)
|
74
|
+
negated = args[:negated]
|
75
|
+
ignorecase = args[:ignorecase]
|
76
|
+
wholewords = args[:wholewords]
|
77
|
+
wholelines = args[:wholelines]
|
78
|
+
extended = args[:extended]
|
79
|
+
multiline = args[:multiline]
|
80
|
+
|
81
|
+
pattern = pat.dup
|
82
|
+
|
83
|
+
# we handle a ridiculous number of possibilities here:
|
84
|
+
# /foobar/ -- "foobar"
|
85
|
+
# /foo/bar/ -- "foo", then slash, then "bar"
|
86
|
+
# /foo\/bar/ -- same as above
|
87
|
+
# /foo/bar/i -- same as above, case insensitive
|
88
|
+
# /foo/bari -- "/foo/bari" exactly
|
89
|
+
# /foo/bar\/i -- "/foo/bar/i" exactly
|
90
|
+
# foo/bar/ -- "foo/bar/" exactly
|
91
|
+
# foo/bar/ -- "foo/bar/" exactly
|
92
|
+
|
93
|
+
if pattern.sub!(%r{ ^ !(?=/) }x, "")
|
94
|
+
negated = true
|
95
|
+
end
|
96
|
+
|
97
|
+
if pattern.sub!(%r{ ^ \/ (.*[^\\]) \/ ([mix]+) $ }x) { $1 }
|
98
|
+
modifiers = $2
|
99
|
+
|
100
|
+
multiline ||= modifiers.index('m')
|
101
|
+
ignorecase ||= modifiers.index('i')
|
102
|
+
extended ||= modifiers.index('x')
|
103
|
+
else
|
104
|
+
pattern.sub!(%r{ ^\/ (.*[^\\]) \/ $ }x) { $1 }
|
105
|
+
end
|
106
|
+
|
107
|
+
if wholewords
|
108
|
+
# sanity check:
|
109
|
+
|
110
|
+
errs = [
|
111
|
+
[ WORD_START_RE, "start" ],
|
112
|
+
[ WORD_END_RE, "end" ]
|
113
|
+
].collect do |ary|
|
114
|
+
re, err = *ary
|
115
|
+
re.match(pattern) ? nil : err
|
116
|
+
end.compact
|
117
|
+
|
118
|
+
if errs.length > 0
|
119
|
+
Log.warn "pattern '#{pattern}' does not " + errs.join(" and ") + " on a word boundary"
|
120
|
+
end
|
121
|
+
pattern = '\b' + pattern + '\b'
|
122
|
+
elsif wholelines
|
123
|
+
pattern = '^' + pattern + '$' # ' for emacs
|
124
|
+
end
|
125
|
+
|
126
|
+
reclass = negated ? NegatedRegexp : Regexp
|
127
|
+
|
128
|
+
flags = [
|
129
|
+
[ ignorecase, Regexp::IGNORECASE ],
|
130
|
+
[ extended, Regexp::EXTENDED ],
|
131
|
+
[ multiline, Regexp::MULTILINE ]
|
132
|
+
].inject(0) do |tot, ary|
|
133
|
+
val, flag = *ary
|
134
|
+
tot | (val ? flag : 0)
|
135
|
+
end
|
136
|
+
|
137
|
+
reclass.new(pattern, flags)
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.matches_word_start?(pat)
|
141
|
+
WORD_START_RE.match(pat)
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.matches_word_end?(pat)
|
145
|
+
WORD_END_RE.match(pat)
|
146
|
+
end
|
147
|
+
|
148
|
+
# applies Perl-style substitution (s/foo/bar/).
|
149
|
+
def self.perl_subst(pat)
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
data/lib/riel/setdiff.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
# Compares two enumerables, treating them as sets, showing whether they are
|
5
|
+
# identical, A contains B, B contains A, or A and B contain common elements.
|
6
|
+
|
7
|
+
class SetDiff
|
8
|
+
def SetDiff.new(a, b)
|
9
|
+
allitems = a | b
|
10
|
+
|
11
|
+
a_and_b = Array.new
|
12
|
+
a_not_in_b = Array.new
|
13
|
+
b_not_in_a = Array.new
|
14
|
+
|
15
|
+
allitems.each do |it|
|
16
|
+
if a.include?(it)
|
17
|
+
if b.include?(it)
|
18
|
+
a_and_b
|
19
|
+
else
|
20
|
+
a_not_in_b
|
21
|
+
end
|
22
|
+
else
|
23
|
+
b_not_in_a
|
24
|
+
end << it
|
25
|
+
end
|
26
|
+
|
27
|
+
super(a_and_b, a_not_in_b, b_not_in_a)
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :a_and_b, :a_not_in_b, :b_not_in_a
|
31
|
+
|
32
|
+
def initialize(a_and_b, a_not_in_b, b_not_in_a)
|
33
|
+
@a_and_b = a_and_b
|
34
|
+
@a_not_in_b = a_not_in_b
|
35
|
+
@b_not_in_a = b_not_in_a
|
36
|
+
end
|
37
|
+
|
38
|
+
def diff_type
|
39
|
+
@diff_type ||= if @a_and_b.empty?
|
40
|
+
:no_common
|
41
|
+
elsif @a_not_in_b.empty?
|
42
|
+
if @b_not_in_a.empty?
|
43
|
+
:identical
|
44
|
+
else
|
45
|
+
:b_contains_a
|
46
|
+
end
|
47
|
+
elsif @b_not_in_a.empty?
|
48
|
+
:a_contains_b
|
49
|
+
else
|
50
|
+
:common
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
class SizeConverter
|
5
|
+
# http://www.gnu.org/software/coreutils/manual/html_node/Block-size.html
|
6
|
+
|
7
|
+
# don't round to closest -- just convert
|
8
|
+
def self.convert_to_kilobytes(size, decimal_places = 1)
|
9
|
+
### SizeConverter._convert(Human::CONVERSIONS, 2, size, decimal_places)
|
10
|
+
end
|
11
|
+
|
12
|
+
class Human
|
13
|
+
CONVERSIONS = [
|
14
|
+
[ 12, "T" ],
|
15
|
+
[ 9, "G" ],
|
16
|
+
[ 6, "M" ],
|
17
|
+
[ 3, "K" ]
|
18
|
+
]
|
19
|
+
|
20
|
+
# returns a string representation of the size. Note that K, G, M are
|
21
|
+
# gibibytes, etc., that is, powers of 10.
|
22
|
+
|
23
|
+
def self.convert(size, decimal_places = 1)
|
24
|
+
SizeConverter._convert(CONVERSIONS, 10, size, decimal_places)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SI
|
29
|
+
# http://physics.nist.gov/cuu/Units/binary.html
|
30
|
+
CONVERSIONS = [
|
31
|
+
[ 40, "TiB" ],
|
32
|
+
[ 30, "GiB" ],
|
33
|
+
[ 20, "MiB" ],
|
34
|
+
[ 10, "KiB" ]
|
35
|
+
]
|
36
|
+
|
37
|
+
# returns a string representation of the size. Note that K, G, M are
|
38
|
+
# gigabytes, etc.
|
39
|
+
|
40
|
+
def self.convert(size, decimal_places = 1)
|
41
|
+
SizeConverter._convert(CONVERSIONS, 2, size, decimal_places)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# legacy:
|
46
|
+
|
47
|
+
def self.convert(size, decimal_places = 1)
|
48
|
+
Human::convert(size, decimal_places)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self._convert(conversions, base, size, decimal_places)
|
52
|
+
sizef = size.to_f
|
53
|
+
conversions.each do |conv|
|
54
|
+
sz = sizef / (base ** conv[0])
|
55
|
+
if sz >= 1.0
|
56
|
+
return sprintf("%.*f%s", decimal_places, sz, conv[1])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
sprintf("%.*f", decimal_places, size)
|
61
|
+
end
|
62
|
+
end
|