glark 1.9.0 → 1.10.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 (128) hide show
  1. data/bin/glark +2 -2
  2. data/lib/glark.rb +1 -1
  3. data/lib/glark/app/app.rb +48 -0
  4. data/lib/glark/app/help.rb +103 -0
  5. data/lib/glark/app/info/options.rb +84 -0
  6. data/lib/glark/app/options.rb +201 -0
  7. data/lib/glark/app/rcfile.rb +49 -0
  8. data/lib/glark/app/runner.rb +140 -0
  9. data/lib/glark/app/spec.rb +19 -0
  10. data/lib/glark/input/filter/criteria_opts.rb +41 -0
  11. data/lib/glark/input/filter/dir_criteria_opts.rb +37 -0
  12. data/lib/glark/input/filter/file_criteria_opts.rb +33 -0
  13. data/lib/glark/input/filter/filter.rb +59 -0
  14. data/lib/glark/input/filter/options.rb +171 -0
  15. data/lib/glark/input/options.rb +120 -0
  16. data/lib/glark/input/range.rb +104 -0
  17. data/lib/glark/input/spec.rb +39 -0
  18. data/lib/glark/io/file/archive_file.rb +64 -0
  19. data/lib/glark/io/file/binary_file.rb +19 -0
  20. data/lib/glark/io/file/file.rb +57 -0
  21. data/lib/glark/io/file/gz_file.rb +21 -0
  22. data/lib/glark/io/file/tar_file.rb +35 -0
  23. data/lib/glark/io/file/tar_gz_file.rb +52 -0
  24. data/lib/glark/io/file/zip_file.rb +39 -0
  25. data/lib/glark/match/and.rb +83 -0
  26. data/lib/glark/match/and_distance.rb +58 -0
  27. data/lib/glark/match/compound.rb +34 -0
  28. data/lib/glark/match/expression.rb +63 -0
  29. data/lib/glark/match/factory.rb +173 -0
  30. data/lib/glark/match/ior.rb +20 -0
  31. data/lib/glark/match/options.rb +74 -0
  32. data/lib/glark/match/or.rb +41 -0
  33. data/lib/glark/match/re.rb +81 -0
  34. data/lib/glark/match/re_factory.rb +44 -0
  35. data/lib/glark/match/spec.rb +59 -0
  36. data/lib/glark/match/xor.rb +20 -0
  37. data/lib/glark/output/binary_file_summary.rb +17 -0
  38. data/lib/glark/output/common.rb +43 -0
  39. data/lib/glark/output/context.rb +57 -0
  40. data/lib/glark/output/count.rb +26 -0
  41. data/lib/glark/output/file_header.rb +20 -0
  42. data/lib/glark/output/file_name_only.rb +35 -0
  43. data/lib/glark/output/formatted.rb +22 -0
  44. data/lib/glark/output/glark_count.rb +23 -0
  45. data/lib/glark/output/glark_format.rb +62 -0
  46. data/lib/glark/output/glark_lines.rb +36 -0
  47. data/lib/glark/output/grep_count.rb +18 -0
  48. data/lib/glark/output/grep_lines.rb +42 -0
  49. data/lib/glark/output/line_status.rb +46 -0
  50. data/lib/glark/output/lines.rb +100 -0
  51. data/lib/glark/output/match_list.rb +15 -0
  52. data/lib/glark/output/options.rb +103 -0
  53. data/lib/glark/output/results.rb +23 -0
  54. data/lib/glark/output/spec.rb +105 -0
  55. data/lib/glark/output/unfiltered_lines.rb +28 -0
  56. data/lib/glark/util/colors/options.rb +143 -0
  57. data/lib/glark/util/colors/spec.rb +21 -0
  58. data/lib/glark/util/highlight.rb +108 -0
  59. data/lib/glark/util/io/depth.rb +29 -0
  60. data/lib/glark/util/io/fileset.rb +162 -0
  61. data/lib/glark/util/io/filter/criteria.rb +49 -0
  62. data/lib/glark/util/io/filter/filter.rb +10 -0
  63. data/lib/glark/util/io/lines.rb +117 -0
  64. data/lib/glark/util/option.rb +34 -0
  65. data/lib/glark/util/options.rb +12 -0
  66. data/lib/glark/util/optutil.rb +69 -0
  67. data/lib/glark/util/timestamper.rb +18 -0
  68. data/man/glark.1 +1134 -0
  69. data/test/glark/app/and_test.rb +82 -0
  70. data/test/glark/app/compound_test.rb +33 -0
  71. data/test/glark/app/context_test.rb +43 -0
  72. data/test/glark/app/count_test.rb +89 -0
  73. data/test/glark/app/dump_test.rb +16 -0
  74. data/test/glark/app/expression_file_test.rb +22 -0
  75. data/test/glark/app/extended_regexp_test.rb +17 -0
  76. data/test/glark/app/extract_matches_test.rb +27 -0
  77. data/test/glark/app/files_with_match_test.rb +32 -0
  78. data/test/glark/app/files_without_match_test.rb +26 -0
  79. data/test/glark/app/filter_test.rb +118 -0
  80. data/test/glark/app/highlight_test.rb +78 -0
  81. data/test/glark/app/ignore_case_test.rb +22 -0
  82. data/test/glark/app/invert_test.rb +49 -0
  83. data/test/glark/app/ior_test.rb +21 -0
  84. data/test/glark/app/label_test.rb +28 -0
  85. data/test/glark/app/line_number_color_test.rb +42 -0
  86. data/test/glark/app/line_numbers_test.rb +42 -0
  87. data/test/glark/app/match_limit_test.rb +49 -0
  88. data/test/glark/app/options_test.rb +722 -0
  89. data/test/glark/app/range_test.rb +101 -0
  90. data/test/glark/app/rcfile_test.rb +113 -0
  91. data/test/glark/app/record_separator_test.rb +32 -0
  92. data/test/glark/app/regexp_test.rb +48 -0
  93. data/test/glark/app/tc.rb +92 -0
  94. data/test/glark/app/text_color_test.rb +31 -0
  95. data/test/glark/app/whole_lines_test.rb +17 -0
  96. data/test/glark/app/whole_words_test.rb +42 -0
  97. data/test/glark/app/xor_test.rb +19 -0
  98. data/test/glark/input/binary_file_test.rb +0 -0
  99. data/test/glark/input/directory_test.rb +202 -0
  100. data/test/glark/input/dirname_test.rb +69 -0
  101. data/test/glark/input/exclude_matching_test.rb +20 -0
  102. data/test/glark/input/ext_test.rb +65 -0
  103. data/test/glark/input/filter/criteria_test.rb +91 -0
  104. data/test/glark/input/filter/filter_spec_test.rb +27 -0
  105. data/test/glark/input/filter/filter_test.rb +21 -0
  106. data/test/glark/input/name_test.rb +75 -0
  107. data/test/glark/input/path_test.rb +72 -0
  108. data/test/glark/input/range_test.rb +82 -0
  109. data/test/glark/input/size_limit_test.rb +51 -0
  110. data/test/glark/input/split_as_path_test.rb +28 -0
  111. data/test/glark/match_test.rb +192 -0
  112. data/test/glark/resources.rb +21 -0
  113. data/test/glark/tc.rb +37 -0
  114. data/test/resources/add.rb +10 -0
  115. data/test/resources/echo.rb +2 -0
  116. data/test/resources/greet.rb +13 -0
  117. metadata +198 -28
  118. data/README +0 -0
  119. data/bin/jlark +0 -63
  120. data/lib/glark/expression.rb +0 -440
  121. data/lib/glark/exprfactory.rb +0 -248
  122. data/lib/glark/glark.rb +0 -297
  123. data/lib/glark/help.rb +0 -85
  124. data/lib/glark/input.rb +0 -183
  125. data/lib/glark/options.rb +0 -757
  126. data/lib/glark/output.rb +0 -266
  127. data/test/lib/glark/glark_test.rb +0 -317
  128. data/test/lib/glark/options_test.rb +0 -891
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ $rielold = false
5
+
6
+ require 'rubygems'
7
+ require 'rainbow'
8
+ require 'singleton'
9
+
10
+ if $rielold
11
+ require 'riel/ansicolor'
12
+ else
13
+ require 'riel/text/ansi/ansi_highlight'
14
+ end
15
+
16
+ module Highlight
17
+ RESET = "\x1b[0m"
18
+
19
+ def adorn hl, str
20
+ if $rielold
21
+ hl.highlight str
22
+ else
23
+ hl + str + RESET
24
+ end
25
+ end
26
+ end
27
+
28
+ module Sickill
29
+ module Rainbow
30
+ class AnsiColor
31
+ $-w = false
32
+ # includes the aberrant color name in the error message.
33
+ def validate_color_name #:nodoc:
34
+ color_names = TERM_COLORS.keys
35
+
36
+ unless color_names.include?(@color)
37
+ raise ArgumentError.new "Unknown color name: '#{@color}'; valid names: #{color_names.join(', ')}"
38
+ end
39
+ end
40
+ $-w = true
41
+ end
42
+ end
43
+ end
44
+
45
+ class RainbowHighlighter
46
+ include Singleton
47
+
48
+ COLORS = %w{ black red green yellow blue magenta cyan white [\dA-Fa-f]{6} }
49
+ DECORATIONS = %w{ none reset bold underscore underline blink reverse inverse negative concealed }
50
+
51
+ BACKGROUND_COLORS = COLORS.collect { |color| "on_#{color}" }
52
+ FOREGROUND_COLORS = COLORS
53
+
54
+ COLORS_RE = Regexp.new('(?: ' +
55
+ # background will be in capture 0
56
+ 'on(?:\s+|_) ( ' + COLORS.join(' | ') + ' ) | ' +
57
+ # foreground will be in capture 1
58
+ '( ' + (COLORS + DECORATIONS).join(' | ') + ' ) ' +
59
+ ')', Regexp::EXTENDED)
60
+
61
+ def get_code color, type
62
+ case color
63
+ when 'bold', 'bright'
64
+ Sickill::Rainbow::TERM_EFFECTS[:bright]
65
+ when 'reverse', 'negative', 'inverse'
66
+ Sickill::Rainbow::TERM_EFFECTS[:inverse]
67
+ when 'underline'
68
+ Sickill::Rainbow::TERM_EFFECTS[:underline]
69
+ when 'blink'
70
+ Sickill::Rainbow::TERM_EFFECTS[:blink]
71
+ when %r{^[\dA-Fa-f]{6}$}
72
+ ac = Sickill::Rainbow::AnsiColor.new type, color
73
+ ac.code
74
+ else
75
+ ac = Sickill::Rainbow::AnsiColor.new type, color.to_sym
76
+ ac.code
77
+ end
78
+ end
79
+
80
+ def to_codes color
81
+ codes = ""
82
+ return codes unless Sickill::Rainbow.enabled
83
+ color.scan(COLORS_RE).collect do |md|
84
+ color, type = md[0] ? [ md[0], :background ] : [ md[1], :foreground ]
85
+ code = get_code color, type
86
+ "\e[#{code}m"
87
+ end.join ''
88
+ end
89
+ end
90
+
91
+ class HlWrapper
92
+ def initialize
93
+ # @hl = $rielold ? Text::ANSIHighlighter : Text::ANSIHighlighter.instance
94
+ @hl = RainbowHighlighter.instance
95
+ end
96
+
97
+ def make_color color
98
+ if $rielold
99
+ result = @hl.make color
100
+ else
101
+ @hl.to_codes color
102
+ end
103
+ end
104
+
105
+ def make_rgb_color red, green, blue, fgbg
106
+ @hl.instance.to_rgb_code red, green, blue, fgbg
107
+ end
108
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ module Glark
6
+ # Depth for recursing directories.
7
+ class Depth
8
+ INFINITY = :infinity
9
+
10
+ attr_reader :value
11
+
12
+ def initialize value
13
+ @value = value
14
+ end
15
+
16
+ def infinity?
17
+ @value == INFINITY
18
+ end
19
+
20
+ def - num
21
+ return self if infinity? || @value.nil?
22
+ self.class.new @value - 1
23
+ end
24
+
25
+ def nonzero?
26
+ infinity? || @value.nil? || @value >= 0
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ require 'rubygems'
6
+ require 'glark/util/io/depth'
7
+ require 'riel/filetype'
8
+
9
+ module Glark
10
+ # Files and directories. And standard input, just for fun.
11
+ class FileSet
12
+ include Loggable, Enumerable
13
+
14
+ attr_reader :files
15
+
16
+ DEPTH_RE = Regexp.new '\.\.\.(\d*)$'
17
+
18
+ def initialize fnames, args
19
+ @max_depth = Depth.new args[:max_depth]
20
+ @binary_files = args[:binary_files] || 'skip'
21
+ @dir_criteria = args[:dir_criteria]
22
+ @file_criteria = args[:file_criteria]
23
+ @split_as_path = args[:split_as_path]
24
+
25
+ @dir_to_max_depth = Hash.new
26
+ @files = Array.new
27
+
28
+ if fnames.size == 0
29
+ @files << '-'
30
+ else
31
+ add_files fnames
32
+ end
33
+ end
34
+
35
+ def size
36
+ @files.size
37
+ end
38
+
39
+ def add_files fnames
40
+ fnames.each do |fname|
41
+ if @split_as_path
42
+ add_as_path fname
43
+ else
44
+ add_fd fname
45
+ end
46
+ end
47
+ end
48
+
49
+ # this is a path in the form /usr/bin:/home/me/projects
50
+ def add_as_path path
51
+ path.to_s.split(::File::PATH_SEPARATOR).each do |element|
52
+ add_fd element
53
+ end
54
+ end
55
+
56
+ def add_fd fname
57
+ pn = nil
58
+
59
+ if md = DEPTH_RE.match(fname)
60
+ val = md[1].empty? ? nil : md[1].to_i
61
+ fname.sub! DEPTH_RE, ''
62
+ fname = '.' if fname.empty?
63
+ pn = Pathname.new fname
64
+ @dir_to_max_depth[pn] = Depth.new val
65
+ else
66
+ pn = Pathname.new fname
67
+ end
68
+
69
+ return if pn.file? && @file_criteria.skipped?(pn)
70
+ @files << pn
71
+ end
72
+
73
+ def stdin?
74
+ @files.size == 1 && @files.first == '-'
75
+ end
76
+
77
+ def each &blk
78
+ # to keep from cycling through links:
79
+ @yielded_files = Array.new
80
+
81
+ (0 ... @files.size).each do |idx|
82
+ pn = @files[idx]
83
+ type = FileType.type pn.to_s
84
+
85
+ if stdin?
86
+ blk.call [ :text, '-' ]
87
+ next
88
+ end
89
+
90
+ unless pn.readable?
91
+ write "directory not readable: #{pn}"
92
+ next
93
+ end
94
+
95
+ dirmax = @dir_to_max_depth[pn] || @max_depth
96
+ handle_pathname pn, dirmax, &blk
97
+ end
98
+ end
99
+
100
+ def handle_pathname pn, depth, &blk
101
+ if pn.directory?
102
+ handle_directory pn, depth, &blk
103
+ elsif pn.file?
104
+ handle_file pn, &blk
105
+ else
106
+ write "unknown file type: #{pn}"
107
+ end
108
+ end
109
+
110
+ def handle_directory pn, depth, &blk
111
+ return if @dir_criteria.skipped? pn, depth
112
+
113
+ subdepth = depth - 1
114
+
115
+ pn.children.sort.each do |entry|
116
+ next if @yielded_files.include?(entry)
117
+ if entry.file?
118
+ type = FileType.type entry.to_s
119
+ next if type == FileType::BINARY && @binary_files == 'skip'
120
+ end
121
+ @yielded_files << entry
122
+ handle_pathname entry, subdepth, &blk
123
+ end
124
+ end
125
+
126
+ def handle_file pn, &blk
127
+ return if @file_criteria.skipped? pn
128
+
129
+ type = FileType.type pn.to_s
130
+ case type
131
+ when FileType::TEXT
132
+ handle_text pn, &blk
133
+ when FileType::BINARY
134
+ handle_binary pn, &blk
135
+ when FileType::NONE
136
+ write "no such file: #{pn}"
137
+ when FileType::UNKNOWN
138
+ write "unknown file type: #{pn}"
139
+ end
140
+ end
141
+
142
+ def handle_text pn, &blk
143
+ blk.call [ :text, pn ]
144
+ end
145
+
146
+ def handle_binary pn, &blk
147
+ type = case @binary_files
148
+ when 'binary'
149
+ :binary
150
+ when 'skip', 'without-match'
151
+ return
152
+ when 'decompress', 'read'
153
+ :read
154
+ when 'list'
155
+ :list
156
+ else
157
+ :text
158
+ end
159
+ blk.call [ type, pn ]
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ require 'glark/util/io/filter/filter'
6
+
7
+ module Glark
8
+ class Criteria
9
+ include Loggable
10
+
11
+ def initialize
12
+ # by type (hash) => by positive/negative (hash) => filter list (array)
13
+ @type_to_posneg = Hash.new
14
+ end
15
+
16
+ def add type, posneg, filter
17
+ posneg_to_filters = (@type_to_posneg[type] ||= Hash.new)
18
+ filters = (posneg_to_filters[posneg] ||= Array.new)
19
+ filters << filter
20
+ end
21
+
22
+ def get type, posneg
23
+ return nil unless posneg_to_filters = @type_to_posneg[type]
24
+ posneg_to_filters[posneg]
25
+ end
26
+
27
+ def find_by_class type, posneg, cls
28
+ return unless filters = get(type, posneg)
29
+ filters.detect { |filter| filter.kind_of? cls }
30
+ end
31
+
32
+ def skipped? pn
33
+ !match? pn
34
+ end
35
+
36
+ def match? pn
37
+ @type_to_posneg.values.each do |typefilters|
38
+ if (posf = typefilters[:positive]) && !posf.empty?
39
+ return false unless posf.detect { |fl| fl.match? pn }
40
+ end
41
+
42
+ if (negf = typefilters[:negative]) && !negf.empty?
43
+ return false if negf.detect { |fl| fl.match? pn }
44
+ end
45
+ end
46
+ true
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ module Glark
6
+ class Filter
7
+ def match? pn
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ module Glark
6
+ module IO
7
+ # Lines of input. Handles non-default ("\n") record separator.
8
+ class Lines
9
+ def initialize fname
10
+ @fname = fname
11
+ @count = nil
12
+ end
13
+
14
+ # Returns the given line for this file. For this method, a line ends with a
15
+ # CR, as opposed to the "lines" method, which ends with $/.
16
+ def get_line lnum
17
+ get_lines[lnum]
18
+ end
19
+
20
+ # this reads the entire file and returns the number of lines
21
+ def count
22
+ unless @count
23
+ @count = ::IO::readlines(@fname).size
24
+ end
25
+ @count
26
+ end
27
+ end
28
+
29
+ class LinesCR < Lines
30
+ def initialize fname, io
31
+ super fname
32
+ @lines = Array.new
33
+ @io = io
34
+ end
35
+
36
+ # Returns the lines for this file, separated by end of line sequences.
37
+ def get_lines
38
+ return @lines
39
+ end
40
+
41
+ def each_line &blk
42
+ while (line = @io.gets) && line.length > 0
43
+ @lines << line
44
+ blk.call line
45
+ end
46
+ @io.close
47
+ end
48
+
49
+ def get_region rnum
50
+ # easy case: range is the range number, unless it is out of range.
51
+ return rnum < @lines.length ? (rnum .. rnum) : nil
52
+ end
53
+ end
54
+
55
+ class LinesNonCR < Lines
56
+ # cross-platform end of line: DOS UNIX MAC
57
+ ANY_END_OF_LINE = Regexp.new '(?:\r\n|\n|\r)'
58
+
59
+ def initialize fname, io
60
+ super fname
61
+ @extracted = nil
62
+ @regions = nil
63
+ @lines = ::IO::readlines fname
64
+ end
65
+
66
+ def each_line &blk
67
+ @lines.each do |line|
68
+ blk.call line
69
+ end
70
+ end
71
+
72
+ # Returns the lines for this file, separated by end of line sequences.
73
+ def get_lines
74
+ @extracted ||= create_extracted
75
+ end
76
+
77
+ # returns the region/range that is represented by the region number
78
+ def get_region rnum
79
+ @regions ||= create_regions
80
+ @regions[rnum]
81
+ end
82
+
83
+ private
84
+ def create_extracted
85
+ # This is much easier. Just resplit the whole thing at end of line
86
+ # sequences.
87
+
88
+ eoline = "\n" # should be OS-dependent
89
+ srclines = @lines
90
+ reallines = @lines.join("").split ANY_END_OF_LINE
91
+
92
+ # "\n" after all but the last line
93
+ @extracted = (0 ... (reallines.length - 1)).collect { |lnum| reallines[lnum] + eoline }
94
+ @extracted << reallines[-1]
95
+
96
+ @extracted
97
+ end
98
+
99
+ def create_regions
100
+ @regions = [] # keys = region number; values = range of lines
101
+
102
+ lstart = 0
103
+ @lines.each do |line|
104
+ lend = lstart
105
+ line.scan(ANY_END_OF_LINE).each do |cr|
106
+ lend += 1
107
+ end
108
+
109
+ @regions << ::Range.new(lstart, lend - 1)
110
+
111
+ lstart = lend
112
+ end
113
+ @regions
114
+ end
115
+ end
116
+ end
117
+ end