grepper 0.9.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 +6 -0
- data/Manifest.txt +11 -0
- data/README.txt +97 -0
- data/Rakefile +12 -0
- data/lib/grepper.rb +229 -0
- data/test/input.1 +3 -0
- data/test/input.2 +4 -0
- data/test/input.3 +3 -0
- data/test/input.4 +8 -0
- data/test/input.6 +9 -0
- data/test/test_grepper.rb +139 -0
- metadata +76 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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
|
data/lib/grepper.rb
ADDED
@@ -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
|
data/test/input.1
ADDED
data/test/input.2
ADDED
data/test/input.3
ADDED
data/test/input.4
ADDED
data/test/input.6
ADDED
@@ -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
|