grepper 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ === 0.9.0 / 2008-12-21
2
+
3
+ * 1 major enhancement
4
+
5
+ * First release
6
+
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/grepper.rb
6
+ test/input.1
7
+ test/input.2
8
+ test/input.3
9
+ test/input.4
10
+ test/input.6
11
+ test/test_grepper.rb
@@ -0,0 +1,97 @@
1
+ Grepper -- simple way to grep through files and save results
2
+
3
+ == Version
4
+
5
+ 0.9.0, December 21, 2008
6
+
7
+ == Author
8
+
9
+ David A. Black (dblack@rubypal.com)
10
+
11
+ == Copyright and license
12
+
13
+ Copyright (c) 2008, Ruby Power and Light, LLC
14
+
15
+ Released under the Ruby license. No warranty of any kind. Use
16
+ entirely at your own risk.
17
+
18
+ == Description
19
+
20
+ The Grepper class greps through files, and returns a result
21
+ set of Grepper::Result objects. Each Result object represents the matches
22
+ found in a single file. The Result contains a set of
23
+ Grepper::Match objects. Each Match object represents a line (the
24
+ line that matched) and before- and after-context arrays. If no before
25
+ or after lines were requested, those context values will be nil.
26
+
27
+ To use, you prepare a Grepper object; call <tt>run</tt> on it; and
28
+ walk through the result set.
29
+
30
+ == Preparing a Grepper object
31
+
32
+ You instantiate Grepper, and provide it with:
33
+
34
+ * a pattern, in the form of a regular expression
35
+ * zero or more options, as an array
36
+ * an array of filenames
37
+
38
+ === Setting the grepper's pattern
39
+
40
+ To specify a pattern for the Grepper object:
41
+
42
+ grepper.pattern = /abc/
43
+
44
+ === Setting the grepper's file list
45
+
46
+ grepper.files = ["file1.txt", "file2.txt"]
47
+ grepper.files = Dir["grep_me/*.txt"]
48
+
49
+ === Options
50
+
51
+ To set options, you provide an array of strings. For example, for a
52
+ reverse grep with two lines of after-context you would do:
53
+
54
+ grepper.options = %w{ v A2 }
55
+
56
+ Available options are:
57
+
58
+ * <tt>v</tt> -- negate the sense of the match
59
+ * <tt>An</tt> -- provide n lines of after-context
60
+ * <tt>Bn</tt> -- provide b lines of before-context
61
+
62
+ == Generating the result set
63
+
64
+ To generate the result set, you call <tt>run</tt>.
65
+
66
+ grepper.run
67
+
68
+ Now you can access grepper.results, and walk through all the
69
+ matches.
70
+
71
+ == Walking through the result set and match set
72
+
73
+ Given a <tt>Grepper</tt> object <tt>grepper</tt>, the result set
74
+ will be at <tt>grepper.results</tt>.
75
+ It will iterate per entry, yielding
76
+ the filename and the corresponding set of matches.
77
+
78
+ grepper.results.each do |filename, matches|
79
+ ...
80
+ end
81
+
82
+ For each match set, you can iterate like this:
83
+
84
+ matches.each do |lineno, before, line, after|
85
+ ...
86
+ end
87
+
88
+ If you want to walk through either set and just get the
89
+ objects, not broken out into their properties, you can do:
90
+
91
+ grepper.results.each_result do |result|
92
+
93
+ and
94
+
95
+ matches.each_match do |match|
96
+
97
+
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/grepper.rb'
6
+
7
+ Hoe.new('grepper', Grepper::VERSION) do |p|
8
+ # p.rubyforge_name = 'grepperx' # if different than lowercase project name
9
+ p.developer('David A. Black', 'dblack@rubypal.com')
10
+ end
11
+
12
+ # vim: syntax=Ruby
@@ -0,0 +1,229 @@
1
+ # Grepper -- simple way to grep through files and save results
2
+ #
3
+ # == Version
4
+ #
5
+ # 0.9.0, December 21, 2008
6
+ #
7
+ # == Author
8
+ #
9
+ # David A. Black (dblack@rubypal.com)
10
+ #
11
+ # == Copyright and license
12
+ #
13
+ # Copyright (c) 2008, Ruby Power and Light, LLC
14
+ #
15
+ # Released under the Ruby license. No warranty of any kind. Use
16
+ # entirely at your own risk.
17
+ #
18
+ # == Description
19
+ #
20
+ # The Grepper class greps through files, and returns a result
21
+ # set of Grepper::Result objects. Each Result object represents the matches
22
+ # found in a single file. The Result contains a set of
23
+ # Grepper::Match objects. Each Match object represents a line (the
24
+ # line that matched) and before- and after-context arrays. If no before
25
+ # or after lines were requested, those context values will be nil.
26
+ #
27
+ # To use, you prepare a Grepper object; call <tt>run</tt> on it; and
28
+ # walk through the result set.
29
+ #
30
+ # == Preparing a Grepper object
31
+ #
32
+ # You instantiate Grepper, and provide it with:
33
+ #
34
+ # * a pattern, in the form of a regular expression
35
+ # * zero or more options, as an array
36
+ # * an array of filenames
37
+ #
38
+ # === Setting the grepper's pattern
39
+ #
40
+ # To specify a pattern for the Grepper object:
41
+ #
42
+ # grepper.pattern = /abc/
43
+ #
44
+ # === Setting the grepper's file list
45
+ #
46
+ # grepper.files = ["file1.txt", "file2.txt"]
47
+ # grepper.files = Dir["grep_me/*.txt"]
48
+ #
49
+ # === Options
50
+ #
51
+ # To set options, you provide an array of strings. For example, for a
52
+ # reverse grep with two lines of after-context you would do:
53
+ #
54
+ # grepper.options = %w{ v A2 }
55
+ #
56
+ # Available options are:
57
+ #
58
+ # * <tt>v</tt> -- negate the sense of the match
59
+ # * <tt>An</tt> -- provide n lines of after-context
60
+ # * <tt>Bn</tt> -- provide b lines of before-context
61
+ #
62
+ # == Generating the result set
63
+ #
64
+ # To generate the result set, you call <tt>run</tt>.
65
+ #
66
+ # grepper.run
67
+ #
68
+ # Now you can access grepper.results, and walk through all the
69
+ # matches.
70
+ #
71
+ # == Walking through the result set and match set
72
+ #
73
+ # Given a <tt>Grepper</tt> object <tt>grepper</tt>, the result set
74
+ # will be at <tt>grepper.results</tt>.
75
+ # It will iterate per entry, yielding
76
+ # the filename and the corresponding set of matches.
77
+ #
78
+ # grepper.results.each do |filename, matches|
79
+ # ...
80
+ # end
81
+ #
82
+ # For each match set, you can iterate like this:
83
+ #
84
+ # matches.each do |lineno, before, line, after|
85
+ # ...
86
+ # end
87
+ #
88
+ # If you want to walk through either set and just get the
89
+ # objects, not broken out into their properties, you can do:
90
+ #
91
+ # grepper.results.each_result do |result|
92
+ #
93
+ # and
94
+ #
95
+ # matches.each_match do |match|
96
+ #
97
+
98
+ class Grepper
99
+ VERSION = '0.9.0'
100
+
101
+ attr_accessor :files, :pattern, :options
102
+ attr_reader :results
103
+
104
+ def initialize
105
+ @files = []
106
+ @options = []
107
+ @results = [].extend(ResultsExtension)
108
+ @negate = false
109
+ end
110
+
111
+ private
112
+
113
+ def get_after_context(fh, after_count)
114
+ res = []
115
+ after_count.times do |i|
116
+ line = fh.gets
117
+ break unless line
118
+ if match?(line)
119
+ fh.pos -= line.size
120
+ break
121
+ else
122
+ res << line
123
+ end
124
+ end
125
+ res.empty? ? nil : res
126
+ end
127
+
128
+ def match?(line)
129
+ m = line =~ @pattern
130
+ @negate ? !m : m
131
+ end
132
+
133
+ public
134
+
135
+ # Generate the result set.
136
+ def run
137
+ @negate = true if options.include?('v')
138
+
139
+ after_count = $1.to_i if options.find {|o| /A(\d)/.match(o) }
140
+ before_count = $1.to_i if options.find {|o| /B(\d)/.match(o) }
141
+
142
+ files.each do |file|
143
+ result = Result.new(file)
144
+ results << result
145
+ buffer = []
146
+ File.open(file) do |fh|
147
+ fh.each_with_index do |line,i|
148
+ if match?(line)
149
+ match = Match.new(line)
150
+ match.lineno = i + 1
151
+ if after_count
152
+ match.after = get_after_context(fh, after_count)
153
+ end
154
+
155
+ if before_count
156
+ match.before = buffer.empty? ? nil : buffer
157
+ buffer = []
158
+ end
159
+
160
+ result.matches << match
161
+
162
+ else
163
+ if before_count
164
+ buffer << line
165
+ buffer.shift if buffer.size > before_count
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ # Grepper::Match represents a match on a single line, possibly
174
+ # with before- and/or after-context.
175
+ #
176
+ # Match instances are created automatically by the Grepper
177
+ # object when you run it.
178
+ class Match
179
+ attr_accessor :before, :line, :after, :lineno
180
+ def initialize(line)
181
+ @before = @after = nil
182
+ @line = line
183
+ end
184
+ end
185
+
186
+ # Grepper::Result represents the matches from a single file. It
187
+ # connects the filename (the <tt>file</tt> attribute) with a
188
+ # set of Match objects (the <tt>matches</tt> attribute).
189
+ #
190
+ # Result objects are created automatically by the Grepper object
191
+ # when you run it.
192
+ class Result
193
+ attr_reader :file, :matches
194
+ def initialize(file)
195
+ @file = file
196
+ @matches = [].extend(MatchesExtension)
197
+ end
198
+ end
199
+
200
+ # Provides the iteration intelligence for result sets.
201
+ module ResultsExtension
202
+ def each(&block)
203
+ (0...size).each do |i|
204
+ yield(self[i].file, self[i].matches)
205
+ end
206
+ end
207
+ def each_result(&block)
208
+ (0...size).each do |i|
209
+ yield self[i]
210
+ end
211
+ end
212
+ end
213
+
214
+ # Provides the iteration intelligence for match sets.
215
+ module MatchesExtension
216
+ def each
217
+ (0...size).each do |i|
218
+ m = self[i]
219
+ yield(m.lineno,m.before,m.line,m.after)
220
+ end
221
+ end
222
+
223
+ def each_match
224
+ (0...size).each do |i|
225
+ yield(self[i])
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,3 @@
1
+ This is a file
2
+ This matches abc.
3
+ This doesn't.
@@ -0,0 +1,4 @@
1
+ This doesn't match.
2
+ However, this:
3
+ So does this abc.
4
+ does.
@@ -0,0 +1,3 @@
1
+ This file
2
+ has no
3
+ matching lines.
@@ -0,0 +1,8 @@
1
+ this abc
2
+ blah one
3
+ blah two
4
+ blah three
5
+ that abc
6
+ one
7
+ two
8
+ three
@@ -0,0 +1,9 @@
1
+ one
2
+ two
3
+ abc
4
+ three
5
+ four
6
+ abc
7
+ five
8
+ six
9
+ abc
@@ -0,0 +1,139 @@
1
+ require 'test/unit'
2
+ require 'English'
3
+ require "lib/grepper.rb"
4
+
5
+ class GrepTest < Test::Unit::TestCase
6
+ def setup
7
+ @g = Grepper.new
8
+ @g.files = %w{ test/input.1 test/input.2 test/input.3 test/input.4 }
9
+ @g.pattern = /abc/
10
+ end
11
+
12
+ def test_basic_lines_from_one_file
13
+ @g.files = ["test/input.1"]
14
+ exp = ["This matches abc.\n"]
15
+ @g.run
16
+ @g.results.each do |file,matches|
17
+ assert_equal("test/input.1", file)
18
+ matches.each do |no,before,line,after|
19
+ assert_equal(nil, before)
20
+ assert_equal(nil, after)
21
+ assert_equal(exp.shift, line)
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_basic_negation_from_one_file
27
+ @g.files =["test/input.4"]
28
+ @g.pattern = /a/
29
+ @g.options = ['v']
30
+ @g.run
31
+ assert_equal(["one\n","two\n","three\n"],
32
+ @g.results[0].matches.map {|m| m.line })
33
+ end
34
+
35
+ def test_case_insensitive_pattern
36
+ @g.files = ["test/input.1"]
37
+ @g.pattern = /ABC/i
38
+ exp = "This matches abc.\n"
39
+ @g.options = ['i']
40
+ @g.run
41
+ assert_equal(exp, @g.results[0].matches[0].line)
42
+ end
43
+
44
+ def test_basic_lines_from_multiple_files
45
+ @g.run
46
+ files = @g.files.dup
47
+ exp = <<EOM.scan(/.*\n/)
48
+ This matches abc.
49
+ So does this abc.
50
+ this abc
51
+ that abc
52
+ EOM
53
+ @g.results.each do |file,matches|
54
+ assert_equal(files.shift, file)
55
+ matches.each_match do |match|
56
+ assert_equal(nil, match.before)
57
+ assert_equal(nil, match.after)
58
+ assert_equal(exp.shift, match.line)
59
+ end
60
+ end
61
+ end
62
+
63
+ def test_after_context_from_one_file
64
+ @g.options = %w{ A2 }
65
+ @g.files = ["test/input.4"]
66
+ exp = <<EOM.scan(/.*\n/)
67
+ this abc
68
+ blah one
69
+ blah two
70
+ that abc
71
+ one
72
+ two
73
+ EOM
74
+ @g.run
75
+ @g.results.each do |file,matches|
76
+ assert_equal("test/input.4", file)
77
+ matches.each do |no,before,line,after|
78
+ assert_equal(nil, before)
79
+ assert_equal(exp.shift, line)
80
+ assert_equal([exp.shift, exp.shift], after)
81
+ end
82
+ end
83
+ end
84
+
85
+ def test_overlapping_context_from_one_file
86
+ @g.options = "A4"
87
+ @g.files = ["test/input.4"]
88
+ @g.run
89
+ assert_equal(1, @g.results.size)
90
+ assert_equal(3, @g.results[0].matches[0].after.size)
91
+ assert_equal(2, @g.results[0].matches.size)
92
+ end
93
+
94
+ def test_lines_from_multiple_files
95
+ @g.files.pop # just 3 files
96
+ @g.run
97
+ assert_equal(3, @g.results.size)
98
+ assert_equal(@g.files, @g.results.map {|r| r.file})
99
+ assert_equal("This matches abc.\n", @g.results[0].matches[0].line)
100
+ assert_equal("So does this abc.\n", @g.results[1].matches[0].line)
101
+ assert(@g.results[2].matches.empty?)
102
+ end
103
+
104
+ def test_before_buffer
105
+ @g.files = ["test/input.4"]
106
+ @g.options = "B2"
107
+ @g.run
108
+ r = @g.results[0]
109
+ assert_equal(1, @g.results.size)
110
+ assert_equal(2, r.matches.size)
111
+ assert_equal("this abc\n", r.matches[0].line)
112
+ assert_equal(["blah two\n", "blah three\n"], r.matches[1].before)
113
+ assert_equal("that abc\n", r.matches[1].line)
114
+ end
115
+
116
+ def test_before_and_after
117
+ @g.files = ["test/input.6"]
118
+ @g.options = %w{A2 B2}
119
+ @g.run
120
+
121
+ r = @g.results[0]
122
+ assert_equal(1, @g.results.size)
123
+ assert_equal(3, r.matches.size)
124
+ assert_equal(["one\n", "two\n"], r.matches[0].before)
125
+ assert(r.matches.all? {|no,b,l,a| l == "abc\n"})
126
+ assert_equal(["three\n", "four\n"], r.matches[0].after)
127
+ assert_equal(["five\n", "six\n"], r.matches[1].after)
128
+ end
129
+
130
+ def test_line_numbering
131
+ test_basic_lines_from_one_file
132
+ assert_equal(2, @g.results[0].matches[0].lineno)
133
+ end
134
+
135
+ def test_line_numbering_in_multiple_files
136
+ test_basic_lines_from_multiple_files
137
+ assert_equal(3, @g.results[1].matches[0].lineno)
138
+ end
139
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grepper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - David A. Black
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-22 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.2
24
+ version:
25
+ description: The Grepper class greps through files, and returns a result set of Grepper::Result objects. Each Result object represents the matches found in a single file. The Result contains a set of Grepper::Match objects. Each Match object represents a line (the line that matched) and before- and after-context arrays. If no before or after lines were requested, those context values will be nil. To use, you prepare a Grepper object; call <tt>run</tt> on it; and walk through the result set.
26
+ email:
27
+ - dblack@rubypal.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - lib/grepper.rb
42
+ - test/input.1
43
+ - test/input.2
44
+ - test/input.3
45
+ - test/input.4
46
+ - test/input.6
47
+ - test/test_grepper.rb
48
+ has_rdoc: true
49
+ homepage: 0.9.0, December 21, 2008
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --main
53
+ - README.txt
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project: grepper
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: The Grepper class greps through files, and returns a result set of Grepper::Result objects
75
+ test_files:
76
+ - test/test_grepper.rb