riel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README +0 -0
  2. data/lib/riel/ansicolor.rb +93 -0
  3. data/lib/riel/array.rb +20 -0
  4. data/lib/riel/command.rb +30 -0
  5. data/lib/riel/date.rb +16 -0
  6. data/lib/riel/dir.rb +90 -0
  7. data/lib/riel/enumerable.rb +66 -0
  8. data/lib/riel/env.rb +49 -0
  9. data/lib/riel/file.rb +212 -0
  10. data/lib/riel/filetype.rb +189 -0
  11. data/lib/riel/hash.rb +12 -0
  12. data/lib/riel/io.rb +20 -0
  13. data/lib/riel/log.rb +548 -0
  14. data/lib/riel/matchdata.rb +13 -0
  15. data/lib/riel/optproc.rb +369 -0
  16. data/lib/riel/pathname.rb +16 -0
  17. data/lib/riel/rcfile.rb +35 -0
  18. data/lib/riel/regexp.rb +152 -0
  19. data/lib/riel/setdiff.rb +53 -0
  20. data/lib/riel/size_converter.rb +62 -0
  21. data/lib/riel/string.rb +81 -0
  22. data/lib/riel/tempfile.rb +28 -0
  23. data/lib/riel/text.rb +408 -0
  24. data/lib/riel/timer.rb +52 -0
  25. data/lib/riel.rb +13 -0
  26. data/test/riel/array_test.rb +22 -0
  27. data/test/riel/command_test.rb +28 -0
  28. data/test/riel/date_test.rb +17 -0
  29. data/test/riel/dir_test.rb +98 -0
  30. data/test/riel/enumerable_test.rb +27 -0
  31. data/test/riel/env_test.rb +52 -0
  32. data/test/riel/file_test.rb +242 -0
  33. data/test/riel/filetype_test.rb +32 -0
  34. data/test/riel/hash_test.rb +12 -0
  35. data/test/riel/io_test.rb +22 -0
  36. data/test/riel/log_test.rb +184 -0
  37. data/test/riel/matchdata_test.rb +15 -0
  38. data/test/riel/optproc_test.rb +233 -0
  39. data/test/riel/pathname_test.rb +36 -0
  40. data/test/riel/rcfile_test.rb +44 -0
  41. data/test/riel/regexp_test.rb +24 -0
  42. data/test/riel/setdiff_test.rb +26 -0
  43. data/test/riel/size_converter_test.rb +64 -0
  44. data/test/riel/string_test.rb +58 -0
  45. data/test/riel/tempfile_test.rb +16 -0
  46. data/test/riel/text_test.rb +102 -0
  47. data/test/riel/timer_test.rb +43 -0
  48. metadata +134 -0
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'riel/text'
5
+
6
+ class String
7
+
8
+ def ends_with(substr)
9
+ return rindex(substr) == (length - substr.length)
10
+ end
11
+
12
+ # Returns the string, as a number if it is one, and nil otherwise.
13
+ def num
14
+ begin
15
+ Integer(self)
16
+ rescue ArgumentError => ae
17
+ nil
18
+ end
19
+ end
20
+
21
+ # returns a string based on this instance, with the first occurrance of
22
+ # +other+ removed. +other+ may be a string or regular expression.
23
+ def -(other)
24
+ sub(other, '')
25
+ end
26
+
27
+ Infinity = (1.0 / 0)
28
+
29
+ # from (maybe to this)
30
+ RANGE_REGEXP = %r{^ \s* (\d*) (?: \s* (\-|\.\.) \s* (\d*) )? \s* $ }x
31
+
32
+ # splits num into array of ranges.
33
+ # handles
34
+ def self.to_ranges(str, args = Hash.new)
35
+ min = args[:min] || -Infinity
36
+ max = args[:max] || Infinity
37
+ collapse = args[:collapse]
38
+
39
+ ranges = Array.new
40
+ str.split(%r{\s*,\s*}).each do |section|
41
+ md = section.match(RANGE_REGEXP)
42
+ next unless md
43
+
44
+ from = _matchdata_to_number(md, 1, min)
45
+ to = _has_matchdata?(md, 2) ? _matchdata_to_number(md, 3, max) : from
46
+
47
+ prevrange = ranges[-1]
48
+
49
+ if collapse && prevrange && prevrange.include?(from - 1) && prevrange.include?(to - 1)
50
+ ranges[-1] = (prevrange.first .. to)
51
+ else
52
+ ranges << (from .. to)
53
+ end
54
+ end
55
+
56
+ ranges
57
+ end
58
+
59
+ def self._has_matchdata?(md, idx)
60
+ md && md[idx] && !md[idx].empty?
61
+ end
62
+
63
+ def self._matchdata_to_number(md, idx, default)
64
+ _has_matchdata?(md, idx) ? md[idx].to_i : default
65
+ end
66
+
67
+ def to_ranges
68
+ String.to_ranges(self)
69
+ end
70
+
71
+ HIGHLIGHTER = ::Text::ANSIHighlighter.new
72
+
73
+ # returns a highlighted (colored) version of the string, applying the regular
74
+ # expressions in the array, which are paired with the desired color.
75
+ def highlight(re, color)
76
+ gsub(re) do |match|
77
+ HIGHLIGHTER.color(color, match)
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'tempfile'
5
+
6
+
7
+ class Tempfile
8
+
9
+ class << self
10
+
11
+ alias_method :original_open, :open
12
+
13
+ # this works around the behavior (fixed in 1.9) so that open returns
14
+ # the new temporary file instead of nil.
15
+
16
+ def open(*args, &blk)
17
+ tempname = nil
18
+ original_open(*args) do |tf|
19
+ tempname = tf.path
20
+
21
+ blk.call(tf) if blk
22
+ end
23
+
24
+ tempname
25
+ end
26
+ end
27
+
28
+ end
data/lib/riel/text.rb ADDED
@@ -0,0 +1,408 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ module Text
5
+
6
+ # Highlights text using either ANSI terminal codes, or HTML.
7
+
8
+ # Note that the foreground and background sections can have modifiers
9
+ # (attributes).
10
+ #
11
+ # Examples:
12
+ # black
13
+ # blue on white
14
+ # bold green on yellow
15
+ # underscore bold magenta on cyan
16
+ # underscore red on cyan
17
+
18
+ class Highlighter
19
+
20
+ VERSION = "1.0.4"
21
+
22
+ ATTRIBUTES = %w{
23
+ none
24
+ reset
25
+ bold
26
+ underscore
27
+ underline
28
+ blink
29
+ negative # not reverse, which is already defined for strings.
30
+ concealed
31
+ black
32
+ red
33
+ green
34
+ yellow
35
+ blue
36
+ magenta
37
+ cyan
38
+ white
39
+ on_black
40
+ on_red
41
+ on_green
42
+ on_yellow
43
+ on_blue
44
+ on_magenta
45
+ on_cyan
46
+ on_white
47
+ }
48
+
49
+ NONE = Object.new
50
+ HTML = Object.new
51
+ ANSI = Object.new
52
+
53
+ COLORS = %w{ black red green yellow blue magenta cyan white }
54
+ DECORATIONS = %w{ none reset bold underscore underline blink negative concealed }
55
+
56
+ BACKGROUND_COLORS = COLORS.collect { |color| "on_#{color}" }
57
+ FOREGROUND_COLORS = COLORS
58
+
59
+ COLORS_RE = Regexp.new('(?: ' +
60
+ # background will be in capture 0
61
+ 'on(?:\s+|_) ( ' + COLORS.join(' | ') + ' ) | ' +
62
+ # foreground will be in capture 1
63
+ '( ' + (COLORS + DECORATIONS).join(' | ') + ' ) ' +
64
+ ')', Regexp::EXTENDED);
65
+
66
+ DEFAULT_COLORS = [
67
+ "black on yellow",
68
+ "black on green",
69
+ "black on magenta",
70
+ "yellow on black",
71
+ "magenta on black",
72
+ "green on black",
73
+ "cyan on black",
74
+ "blue on yellow",
75
+ "blue on magenta",
76
+ "blue on green",
77
+ "blue on cyan",
78
+ "yellow on blue",
79
+ "magenta on blue",
80
+ "green on blue",
81
+ "cyan on blue",
82
+ ]
83
+
84
+ attr_reader :colors
85
+
86
+ def self.parse_colors(str)
87
+ str.scan(Regexp.new(COLORS_RE)).collect do |color|
88
+ color[0] ? "on_" + color[0] : color[1]
89
+ end
90
+ end
91
+
92
+ # returns a list of all color combinations.
93
+ def self.all_colors
94
+ all_colors = Array.new
95
+ ([ nil ] + DECORATIONS).each do |dec|
96
+ ([ nil ] + FOREGROUND_COLORS).each do |fg|
97
+ ([ nil ] + BACKGROUND_COLORS).each do |bg|
98
+ name = [ dec, fg, bg ].compact.join("_")
99
+ all_colors << name if name && name.length > 0
100
+ end
101
+ end
102
+ end
103
+ all_colors
104
+ end
105
+
106
+ all_colors.each do |name|
107
+ meth = Array.new
108
+ meth << "def #{name}(&blk)"
109
+ meth << " color(\"#{name}\", &blk)"
110
+ meth << "end"
111
+
112
+ self.class_eval meth.join("\n")
113
+ end
114
+
115
+ def initialize(colors)
116
+ @colors = colors
117
+ end
118
+
119
+ def highlight(str)
120
+ # implemented by subclasses
121
+ end
122
+
123
+ def to_s
124
+ (@colors || '').join(' ')
125
+ end
126
+
127
+ def ==(other)
128
+ return @colors.sort == other.colors.sort
129
+ end
130
+
131
+ # Colorizes the given object. If a block is passed, its return value is used
132
+ # and the stream is reset. If a String is provided as the object, it is
133
+ # colorized and the stream is reset. Otherwise, only the code for the given
134
+ # color name is returned.
135
+
136
+ def color(colorstr, obj = self, &blk)
137
+ # ^^^^ this is the Module self
138
+
139
+ colornames = self.class.parse_colors(colorstr)
140
+ result = names_to_code(colornames)
141
+
142
+ if blk
143
+ result << blk.call
144
+ result << names_to_code("reset")
145
+ elsif obj.kind_of?(String)
146
+ result << obj
147
+ result << names_to_code("reset")
148
+ end
149
+ result
150
+ end
151
+
152
+ # returns the code for the given color string, which is in the format:
153
+ # foreground* [on background]?
154
+ #
155
+ # Note that the foreground and background sections can have modifiers
156
+ # (attributes).
157
+ #
158
+ # Examples:
159
+ # black
160
+ # blue on white
161
+ # bold green on yellow
162
+ # underscore bold magenta on cyan
163
+ # underscore red on cyan
164
+
165
+ def code(str)
166
+ fg, bg = str.split(/\s*\bon_?\s*/)
167
+ (fg ? foreground(fg) : "") + (bg ? background(bg) : "")
168
+ end
169
+
170
+ # Returns the code for the given background color(s).
171
+ def background(bgcolor)
172
+ names_to_code("on_" + bgcolor)
173
+ end
174
+
175
+ # Returns the code for the given foreground color(s).
176
+ def foreground(fgcolor)
177
+ fgcolor.split(/\s+/).collect { |fg| names_to_code(fg) }.join("")
178
+ end
179
+
180
+ end
181
+
182
+ # Highlights using ANSI escape sequences.
183
+
184
+ class ANSIHighlighter < Highlighter
185
+
186
+ ATTRIBUTES = Hash[
187
+ 'none' => '0',
188
+ 'reset' => '0',
189
+ 'bold' => '1',
190
+ 'underscore' => '4',
191
+ 'underline' => '4',
192
+ 'blink' => '5',
193
+ 'negative' => '7',
194
+ 'concealed' => '8',
195
+ 'black' => '30',
196
+ 'red' => '31',
197
+ 'green' => '32',
198
+ 'yellow' => '33',
199
+ 'blue' => '34',
200
+ 'magenta' => '35',
201
+ 'cyan' => '36',
202
+ 'white' => '37',
203
+ 'on_black' => '40',
204
+ 'on_red' => '41',
205
+ 'on_green' => '42',
206
+ 'on_yellow' => '43',
207
+ 'on_blue' => '44',
208
+ 'on_magenta' => '45',
209
+ 'on_cyan' => '46',
210
+ 'on_white' => '47',
211
+ ]
212
+
213
+ RESET = "\e[0m"
214
+
215
+ def self.make(str)
216
+ colors = parse_colors(str)
217
+ ANSIHighlighter.new(colors)
218
+ end
219
+
220
+ def initialize(colors = DEFAULT_COLORS)
221
+ super
222
+ @code = nil
223
+ end
224
+
225
+ # Returns the escape sequence for the given names.
226
+
227
+ def names_to_code(names)
228
+ str = ""
229
+ names.each do |name|
230
+ code = ATTRIBUTES[name]
231
+ if code
232
+ str << "\e[#{code}m"
233
+ end
234
+ end
235
+ str
236
+ end
237
+
238
+ def highlight(str)
239
+ @code ||= begin
240
+ @code = @colors.collect do |color|
241
+ names_to_code(color)
242
+ end.join("")
243
+ end
244
+
245
+ @code + str + RESET
246
+ end
247
+
248
+ end
249
+
250
+ # Highlights using HTML. Fonts are highlighted using <span> tags, not <font>.
251
+ # Also note that negative is translated to white on black.
252
+ # According to http://www.w3.org/TR/REC-CSS2/syndata.html#value-def-color,
253
+ # valid color keywords are: aqua, black, blue, fuchsia, gray, green, lime,
254
+ # maroon, navy, olive, purple, red, silver, teal, white, and yellow.
255
+ # Thus, no magenta or cyan.
256
+
257
+ class HTMLHighlighter < Highlighter
258
+
259
+ def initialize
260
+ # we need to know what we're resetting from (bold, font, underlined ...)
261
+ @stack = []
262
+ end
263
+
264
+ # Returns the start tag for the given name.
265
+
266
+ def start_style(name)
267
+ case name
268
+ when "negative"
269
+ "<span style=\"color: white; background-color: black\">"
270
+ when /on_(\w+)/
271
+ colval = color_value($1)
272
+ "<span style=\"background-color: #{colval}\">"
273
+ else
274
+ colval = color_value(name)
275
+ "<span style=\"color: #{colval}\">"
276
+ end
277
+ end
278
+
279
+ # Returns the end tag ("</span>").
280
+
281
+ def end_style
282
+ "</span>"
283
+ end
284
+
285
+ def color_value(cname)
286
+ case cname
287
+ when "cyan"
288
+ "#00FFFF"
289
+ when "magenta"
290
+ "#FF00FF"
291
+ else
292
+ cname
293
+ end
294
+ end
295
+
296
+ # Returns the code for the given name.
297
+
298
+ def names_to_code(names)
299
+ str = ""
300
+
301
+ names.each do |name|
302
+ @stack << name
303
+
304
+ case name
305
+ when "none", "reset"
306
+ @stack.pop
307
+ if @stack.length > 0
308
+ begin
309
+ prev = @stack.pop
310
+ case prev
311
+ when "bold"
312
+ str << "</b>"
313
+ when "underscore", "underline"
314
+ str << "</u>"
315
+ when "blink"
316
+ str << "</blink>"
317
+ when "concealed"
318
+ str << " -->"
319
+ else
320
+ str << end_style
321
+ end
322
+ end while @stack.length > 0
323
+ end
324
+ str
325
+ when "bold"
326
+ str << "<b>"
327
+ when "underscore", "underline"
328
+ str << "<u>"
329
+ when "blink"
330
+ str << "<blink>"
331
+ when "concealed"
332
+ str << "<!-- "
333
+ else
334
+ str << start_style(name)
335
+ end
336
+ end
337
+
338
+ str
339
+ end
340
+ end
341
+
342
+ # Does no highlighting.
343
+
344
+ class NonHighlighter < Highlighter
345
+
346
+ def initialize
347
+ super(nil)
348
+ end
349
+
350
+ # Since the NonHighlighter does no highlighting, and thus its name, this
351
+ # returns an empty string.
352
+
353
+ def names_to_code(colorname)
354
+ ""
355
+ end
356
+
357
+ end
358
+
359
+
360
+ # An object that can be highlighted. This is used by the String class.
361
+
362
+ module Highlightable
363
+
364
+ # The highlighter for the class in which this module is included.
365
+
366
+ @@highlighter = ANSIHighlighter.new(Text::Highlighter::DEFAULT_COLORS)
367
+
368
+ Text::Highlighter::all_colors.each do |name|
369
+ meth = Array.new
370
+ meth << "def #{name}(&blk)"
371
+ meth << " @@highlighter.color(\"#{name}\", self, &blk)"
372
+ meth << "end"
373
+
374
+ self.class_eval meth.join("\n")
375
+ end
376
+
377
+ # Sets the highlighter for this class. This can be either by type or by
378
+ # String.
379
+
380
+ def highlighter=(hl)
381
+ $VERBOSE = false
382
+ @@highlighter = case hl
383
+ when Text::Highlighter
384
+ hl
385
+ when Text::Highlighter::NONE, "NONE", nil
386
+ Text::NonHighlighter.new # unless @@highlighter.kind_of?(Text::NonHighlighter)
387
+ when Text::Highlighter::HTML, "HTML"
388
+ Text::HTMLHighlighter.new # unless @@highlighter.kind_of?(Text::HTMLHighlighter)
389
+ when Text::Highlighter::ANSI, "ANSI"
390
+ Text::ANSIHighlighter.new
391
+ else
392
+ Text::NonHighlighter.new
393
+ end
394
+
395
+ end
396
+
397
+ end
398
+
399
+ $HAVE_TEXT_HIGHLIGHT = true
400
+
401
+ end
402
+
403
+ # String is extended to support highlighting.
404
+
405
+ class String
406
+ include Text::Highlightable
407
+ extend Text::Highlightable
408
+ end
data/lib/riel/timer.rb ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'riel/log'
5
+
6
+ class Timer
7
+
8
+ def initialize(what, args = Hash.new)
9
+ if args.kind_of?(Fixnum)
10
+ args = { :level => args }
11
+ end
12
+
13
+ @io = args[:io] || $stdout
14
+ @level = args[:level] || Log::DEBUG
15
+
16
+ stmsg = args.include?(:startmsg) ? args[:startmsg] : "#{what} start time"
17
+ endmsg = args.include?(:endmsg) ? args[:endmsg] : "#{what} end time"
18
+ elmsg = args.include?(:elmsg) ? args[:elmsg] : "#{what} elapsed "
19
+
20
+ sttime = Time.new
21
+ logmsg(stmsg, sttime)
22
+
23
+ yield
24
+
25
+ endtime = Time.new
26
+
27
+ logmsg(stmsg, sttime)
28
+ logmsg(endmsg, endtime)
29
+ logmsg(elmsg, endtime - sttime)
30
+ end
31
+
32
+ def logmsg(msg, value)
33
+ if msg
34
+ if @io
35
+ @io.puts "#{msg}: #{value}"
36
+ else
37
+ Log.log "#{msg}: #{value}", @level
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ def timethis(what)
45
+ sttime = Time.new
46
+ Log.log "#{what} start time: #{sttime}"
47
+ yield
48
+ endtime = Time.new
49
+ Log.log "#{what} start time: #{sttime}"
50
+ Log.log "#{what} end time : #{endtime}"
51
+ Log.log "#{what} elapsed : #{endtime - sttime}"
52
+ end
data/lib/riel.rb ADDED
@@ -0,0 +1,13 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module RIEL
5
+ VERSION = '0.0.1'
6
+ end
7
+
8
+ rbfiles = Dir[File.dirname(__FILE__) + "/riel/**/*.rb"]
9
+
10
+ rbfiles.sort.each do |rbfile|
11
+ rootname = rbfile.match(%r{.*/(\w+)\.rb})[1]
12
+ require "riel/" + rootname
13
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubyunit'
5
+ require 'riel/array'
6
+
7
+ class ArrayTestCase < RUNIT::TestCase
8
+
9
+ def test_to_s
10
+ a = %w{ this is a test }
11
+ assert_equal "[ this, is, a, test ]", a.to_s
12
+ end
13
+
14
+ def test_rand
15
+ a = %w{ this is a test }
16
+ 10.times do
17
+ r = a.rand
18
+ assert_not_nil r
19
+ assert a.include?(r)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubyunit'
5
+ require 'riel/command'
6
+
7
+ class CommandTestCase < RUNIT::TestCase
8
+
9
+ def test_all
10
+ assert_equal [ "/bin/ls\n" ], Command.run("ls", "/bin/ls")
11
+ assert_equal [ "/bin/grep\n", "/bin/ls\n" ], Command.run("ls", "/bin/ls", "/bin/grep" )
12
+
13
+ lnum = 0
14
+ expected = [ "/bin/grep\n", "/bin/ls\n" ]
15
+ lines = Command.run("ls", "/bin/ls", "/bin/grep" ) do |line|
16
+ assert_equals(expected[lnum], line)
17
+ lnum += 1
18
+ end
19
+ assert_equal expected, lines
20
+
21
+ expected = [ "/bin/grep\n", "/bin/ls\n" ]
22
+ lines = Command.run("ls", "/bin/ls", "/bin/grep" ) do |line, lnum|
23
+ assert_equals(expected[lnum], line)
24
+ end
25
+ assert_equal expected, lines
26
+ end
27
+
28
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubyunit'
5
+ require 'riel/date'
6
+
7
+ class DateTestCase < RUNIT::TestCase
8
+
9
+ def test
10
+ assert_equal 28, Date.days_in_month(2010, 2)
11
+ assert_equal 31, Date.days_in_month(2010, 1)
12
+ assert_equal 29, Date.days_in_month(2008, 2)
13
+ assert_equal 30, Date.days_in_month(2007, 6)
14
+ assert_equal 31, Date.days_in_month(2010, 12)
15
+ end
16
+
17
+ end