interactive_grep 0.0.2 → 0.0.4
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/README.txt +32 -29
- data/bin/igrep +29 -28
- data/interactive_grep.gemspec +1 -0
- data/lib/interactive_grep/grepper.rb +27 -67
- data/lib/interactive_grep/version.rb +1 -1
- data/spec/lib/interactive_grep/grepper_spec.rb +4 -4
- metadata +14 -3
data/README.txt
CHANGED
@@ -1,14 +1,11 @@
|
|
1
1
|
Interactively Grep for patterns.
|
2
2
|
|
3
|
-
This works particularly well for
|
4
|
-
weblogs) and it handles zipped files.
|
3
|
+
This works particularly well for exploring multi-line pattern even in gzip'd files (i.e. weblogs)
|
5
4
|
|
6
|
-
|
7
|
-
the code was a total hack)!
|
5
|
+
Why? This is based on my very first Ruby program (the code was a total hack)!
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
of the power of refactoring ;)
|
7
|
+
I kept it because it's actually useful.
|
8
|
+
Hopefully by the time you get this the code (v1.0), it will serve as an example of the power of refactoring ;)
|
12
9
|
|
13
10
|
Basic use-case(s):
|
14
11
|
gem install interactive_grep
|
@@ -17,41 +14,47 @@ Basic use-case(s):
|
|
17
14
|
|
18
15
|
# OR in your code:
|
19
16
|
irb
|
20
|
-
# normal ('grep') mode
|
21
|
-
ig = InteractiveGrep::Grepper.new(
|
22
|
-
|
17
|
+
# normal ('grep') mode
|
18
|
+
ig = InteractiveGrep::Grepper.new(
|
19
|
+
"files" => "/path/to/weblog.gz",
|
20
|
+
"pattern" => search_string
|
23
21
|
)
|
24
22
|
puts ig.run
|
25
|
-
# => [matching_line1,
|
23
|
+
# => [matching_line1, ..., matching_lineN]
|
26
24
|
|
27
|
-
# count ('grep -c') mode
|
28
|
-
ig = InteractiveGrep::Grepper.new(
|
29
|
-
|
30
|
-
|
25
|
+
# count ('grep -c') mode
|
26
|
+
ig = InteractiveGrep::Grepper.new(
|
27
|
+
"files" => "/path/to/weblog.gz",
|
28
|
+
"pattern" => search_string,
|
29
|
+
"mode" => "count"
|
31
30
|
)
|
32
31
|
ig.run
|
33
32
|
# => 20
|
34
33
|
|
35
34
|
# interactive mode - oh yeah!!!
|
36
|
-
ig = InteractiveGrep::Grepper.new(
|
37
|
-
|
35
|
+
ig = InteractiveGrep::Grepper.new(
|
36
|
+
files => "/path/to/weblog.gz",
|
37
|
+
"pattern" => search_string
|
38
|
+
"mode" => "interactive"
|
38
39
|
)
|
39
|
-
ig.interactive = true
|
40
40
|
ig.run
|
41
|
-
# every
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
41
|
+
# every line matching the current pattern is displayed
|
42
|
+
# and you're prompted to:
|
43
|
+
# repeat the current search (press enter)
|
44
|
+
#
|
45
|
+
# turn off interactive-mode (enter '-'*)
|
46
|
+
# -- grep remainder of file(s) for current pattern
|
47
|
+
#
|
48
|
+
# modify the current pattern (whatever you enter)
|
49
|
+
# e.g. to explore one-line at a time enter "." (dot)
|
50
|
+
# *note: to search for a dash, escape it (i.e. "\-")
|
50
51
|
|
51
52
|
(See specs for more detailed use-cases ...and short-comings)
|
52
53
|
rake rspec
|
53
54
|
|
54
55
|
# TODO:
|
55
|
-
#
|
56
|
+
# specs the behavior I've already described
|
56
57
|
# test-drive an API I can be proud of ;-)
|
57
|
-
#
|
58
|
+
# refactor (DRY-up and modularize)
|
59
|
+
# add ability to record & replay grep-sessions
|
60
|
+
# add support for zip, bzip, etc..
|
data/bin/igrep
CHANGED
@@ -1,46 +1,47 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
# the "i" is for interactive
|
3
|
+
|
4
4
|
begin
|
5
5
|
require 'rubygems'
|
6
6
|
gem 'interactive_grep'
|
7
|
+
require 'interactive_grep'
|
7
8
|
rescue LoadError
|
9
|
+
require File.expand_path( '../../lib/interactive_grep/grepper.rb', __FILE__ )
|
8
10
|
end
|
9
|
-
|
10
|
-
file_or_gem = 'interactive_grep' unless File.exists?( file_or_gem )
|
11
|
-
require file_or_gem
|
11
|
+
require 'optparse'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
puts InteractiveGrep::Grepper.usage
|
16
|
-
end
|
13
|
+
options = {}
|
14
|
+
options["verbose"] = true
|
17
15
|
|
18
|
-
|
16
|
+
opt_parser = OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: #{$0} [OPTIONS] A_FILEGLOB or FILE(S)"
|
19
18
|
|
20
|
-
|
19
|
+
options["pattern"] = nil
|
20
|
+
opts.on( "--pattern [PATTERN]", "Regex to grep with") do |p|
|
21
|
+
options["pattern"] = p
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
options["mode"] = 'interactive'
|
25
|
+
opts.on( "--mode [MODE]", ['interactive', 'count', 'normal'], "'interactive', 'count' or 'normal'") do |m|
|
26
|
+
options["mode"] = m
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
"interactive"
|
31
|
-
when /^c/i
|
32
|
-
interactive = false
|
33
|
-
"count"
|
34
|
-
else
|
35
|
-
interactive = false
|
36
|
-
"normal"
|
37
|
-
end
|
29
|
+
opts.on_tail( '-h', '--help', 'This help screen' ) do
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
38
33
|
end
|
39
34
|
|
40
|
-
|
41
|
-
|
35
|
+
opt_parser.parse!
|
36
|
+
|
37
|
+
options["files"] = ARGV
|
38
|
+
if options["files"].empty?
|
39
|
+
puts opt_parser
|
40
|
+
exit
|
41
|
+
end
|
42
42
|
|
43
|
-
|
43
|
+
igrep = InteractiveGrep::Grepper.new( options )
|
44
|
+
puts "Welcome..." if :interactive == options["mode"]
|
44
45
|
igrep.run()
|
45
46
|
|
46
47
|
exit
|
data/interactive_grep.gemspec
CHANGED
@@ -3,56 +3,34 @@ require 'zlib'
|
|
3
3
|
module InteractiveGrep
|
4
4
|
class Grepper
|
5
5
|
DEFAULT_PATTERN = %r{.}.freeze
|
6
|
-
|
6
|
+
DEFAULT_PROGRESS_INDICATOR_COUNT = 100.freeze # in verbose mode, show signs of life after processing every N lines
|
7
7
|
DEBUG = false.freeze
|
8
8
|
|
9
|
-
|
9
|
+
attr_reader :file_names, :current_pattern, :file_index
|
10
|
+
attr_accessor :progress_indicator_count, :initial_pattern
|
10
11
|
|
11
12
|
def initialize( options = nil )
|
12
13
|
options ||= {}
|
13
|
-
@enough_lines_to_indicate = options[:line_indicator_count] || DEFAULT_NUMBER_OF_LINES_TO_INDICATE
|
14
|
-
@verbose = DEBUG || !!options[ "verbose" ]
|
15
|
-
reset_file_index
|
16
|
-
@file_names = options[ "files" ]
|
17
|
-
if ( !@file_names.is_a?( Array ) ) && @file_names[/\*/]
|
18
|
-
@file_names = Dir.glob( @file_names ).map{|fname| fname}
|
19
|
-
end
|
20
|
-
@file_names = [ @file_names ] unless @file_names.is_a? Array
|
21
|
-
unless current_file && File.exists?( current_file )
|
22
|
-
raise "must specify at least one valid file (and/or file_glob)"
|
23
|
-
end
|
24
|
-
|
25
|
-
@initial_pattern = !!options[ "pattern" ] ? %r{#{options[ "pattern" ]}} : DEFAULT_PATTERN
|
26
|
-
@current_pattern = @initial_pattern
|
27
14
|
|
15
|
+
@progress_indicator_count = options[:progress_indicator_count] || DEFAULT_PROGRESS_INDICATOR_COUNT
|
16
|
+
@verbose = DEBUG || !!options[ "verbose" ]
|
28
17
|
@mode = options[ "mode" ] || "normal"
|
29
|
-
|
30
18
|
@gz = options[ "gz" ]
|
19
|
+
@initial_pattern = !!options[ "pattern" ] ? %r{#{options[ "pattern" ]}} : DEFAULT_PATTERN
|
20
|
+
@current_pattern = @initial_pattern
|
21
|
+
reset_file_index
|
22
|
+
@file_names = self.class.globs_to_files( options[ "files" ] )
|
31
23
|
|
32
|
-
if
|
33
|
-
|
24
|
+
if !current_file || !File.exists?( current_file )
|
25
|
+
raise "must specify at least one valid file (and/or file_glob)"
|
34
26
|
end
|
35
|
-
end
|
36
27
|
|
37
|
-
|
38
|
-
input_options.any?{|o| o[/^\s*\-+#{option_string}/] }
|
28
|
+
puts "using:\n\tfiles: #{file_names}\n\tending in: #{ending}\n\tinitial_pattern: #{current_pattern_string}\n" if verbose?
|
39
29
|
end
|
40
30
|
|
41
|
-
def self.
|
42
|
-
|
43
|
-
|
44
|
-
puts ""
|
45
|
-
|
46
|
-
puts "usage $0 <input_file> [<pattern>] [<mode>]"
|
47
|
-
puts ""
|
48
|
-
puts "modes: 'interactive' (default), 'count', or 'normal'"
|
49
|
-
puts "e.g."
|
50
|
-
puts "./igrep.rb big_test.txt.gz"
|
51
|
-
puts './igrep.rb "/reporting/access*.gz" cvsfa=63 interactive'
|
52
|
-
puts './igrep.rb "/reporting/access*.gz" cvsfa=63 count'
|
53
|
-
puts './igrep.rb "/reporting/access*.gz" cvsfa=63 # normal-grep mode'
|
54
|
-
puts ""
|
55
|
-
exit
|
31
|
+
def self.globs_to_files( files_or_globs )
|
32
|
+
files_or_globs = files_or_globs.is_a?( Array ) ? files_or_globs : [ files_or_globs ]
|
33
|
+
files_or_globs.map {|file_or_glob| Dir.glob( file_or_glob ) }.flatten
|
56
34
|
end
|
57
35
|
|
58
36
|
def default_pattern?
|
@@ -96,17 +74,12 @@ module InteractiveGrep
|
|
96
74
|
end
|
97
75
|
@current_pattern = prompt( line )
|
98
76
|
end
|
99
|
-
if verbose?
|
100
|
-
puts "." if 0 == (counter % enough_lines_to_indicate)
|
101
|
-
end
|
77
|
+
puts "." if verbose? && 0 == (counter % progress_indicator_count)
|
102
78
|
end
|
103
79
|
reset_file_index
|
104
80
|
puts "no more files.\n" if verbose?
|
105
81
|
if just_count?
|
106
|
-
if verbose?
|
107
|
-
puts "matched #{counter} line(s)"
|
108
|
-
puts "done.\n"
|
109
|
-
end
|
82
|
+
puts "matched #{counter} line(s)\ndone.\n" if verbose?
|
110
83
|
counter
|
111
84
|
else
|
112
85
|
puts "done.\n" if verbose?
|
@@ -116,6 +89,8 @@ module InteractiveGrep
|
|
116
89
|
|
117
90
|
private
|
118
91
|
|
92
|
+
attr_reader :current_pattern, :file_index
|
93
|
+
|
119
94
|
def verbose?
|
120
95
|
!!@verbose
|
121
96
|
end
|
@@ -129,39 +104,24 @@ module InteractiveGrep
|
|
129
104
|
end
|
130
105
|
|
131
106
|
def prompt( msg )
|
132
|
-
if verbose? && msg && !just_count?
|
133
|
-
puts "\n>>\n#{msg}\n<<"
|
134
|
-
end
|
107
|
+
puts "\n>>\n#{msg}\n<<" if verbose? && msg && !just_count?
|
135
108
|
|
136
109
|
if interactive?
|
137
|
-
puts "
|
138
|
-
user_input = STDIN.gets.
|
110
|
+
puts ". | O | <pattern: [#{current_pattern_string}]> ? "
|
111
|
+
user_input = STDIN.gets.chomp
|
139
112
|
puts ""
|
140
|
-
if DEBUG
|
141
|
-
puts "user_input: >>#{user_input.inspect}<<"
|
142
|
-
end
|
113
|
+
puts "user_input: >>#{user_input.inspect}<<" if DEBUG
|
143
114
|
|
144
115
|
case
|
145
116
|
when /^\s*$/.match( user_input ) #corresponds w/ <enter> (or <return>)
|
146
|
-
if verbose?
|
147
|
-
puts " => continuing w/ the previous pattern"
|
148
|
-
end
|
117
|
+
puts " => continuing w/ the previous pattern" if verbose?
|
149
118
|
@current_pattern
|
150
|
-
when
|
119
|
+
when "-" == user_input #interactive mode Off
|
151
120
|
@mode = "normal"
|
152
|
-
if verbose?
|
153
|
-
puts " => interactive switched mode off"
|
154
|
-
end
|
121
|
+
puts " => interactive switched mode off" if verbose?
|
155
122
|
@current_pattern
|
156
|
-
when [ "S", "s" ].include?( user_input ) #Show every line
|
157
|
-
if verbose?
|
158
|
-
puts " => showing the next line"
|
159
|
-
end
|
160
|
-
/./
|
161
123
|
else #use whatever was entered
|
162
|
-
if verbose?
|
163
|
-
puts " => using your input as the new search pattern"
|
164
|
-
end
|
124
|
+
puts " => using your input as the new search pattern" if verbose?
|
165
125
|
%r{#{user_input}}
|
166
126
|
end
|
167
127
|
else
|
@@ -26,7 +26,7 @@ describe InteractiveGrep::Grepper do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should have gz set to false" do
|
29
|
-
grepper.
|
29
|
+
grepper.should_not be_gz
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -38,7 +38,7 @@ describe InteractiveGrep::Grepper do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should have gz set to true" do
|
41
|
-
grepper.
|
41
|
+
grepper.should be_gz
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -50,7 +50,7 @@ describe InteractiveGrep::Grepper do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "should have gz set to true" do
|
53
|
-
grepper.
|
53
|
+
grepper.should be_gz
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -62,7 +62,7 @@ describe InteractiveGrep::Grepper do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should have gz set to false" do
|
65
|
-
grepper.
|
65
|
+
grepper.should_not be_gz
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interactive_grep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-07-21 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70136989126620 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,18 @@ dependencies:
|
|
21
21
|
version: 2.11.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70136989126620
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ruby-debug19
|
27
|
+
requirement: &70136989126200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70136989126200
|
25
36
|
description: grep for stuff in (optionally gzipped) files ...even before you fully
|
26
37
|
know what that 'stuff' looks like
|
27
38
|
email:
|