prak 1.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -0,0 +1,27 @@
1
+
2
+ == 1.0 / 2009-09-27
3
+
4
+ * MinGW is a valid Windows platform type.
5
+ * Can use ~bang and ~ques in a regex and they will be turned into ! and ?
6
+ This is to get around bash.
7
+ * Added -k negative file match option (Contributed by Juozas Gaigalas')
8
+ * Added .cc and .hpp to the C++ file types
9
+ * Added Vala file types
10
+ * 20% faster on average
11
+ * Moved to Github
12
+
13
+ == 0.9 / 2008-02-03
14
+
15
+ * Added .rake to ruby files
16
+ * Colouring works on Win32 if win32console gem is installed.
17
+ * Checks that file is readable by the current user.
18
+ * Ignores socket files.
19
+ * Added .erb and .haml to Ruby filetypes.
20
+ * Added search at end-of/start-of line options
21
+ * Fixed searching up the directory tree when passed '.'
22
+
23
+ == 0.8.0 / 2007-10-30
24
+
25
+ * Initial release.
26
+
27
+
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/prak
6
+ lib/prak.rb
7
+ lib/prak/bootstrap.rb
8
+ lib/prak/command_line.rb
9
+ lib/prak/compile_match_file.rb
10
+ lib/prak/file.rb
11
+ lib/prak/search.rb
12
+ prak.gemspec
@@ -0,0 +1,70 @@
1
+ prak
2
+
3
+ Original by:
4
+ http://rubyforge.org/projects/rak
5
+ Daniel Lucraft (http://danlucraft.com/blog/)
6
+
7
+ Modifications by Sven Winkler
8
+
9
+ == DESCRIPTION:
10
+
11
+ Replacement for grep. Recursively scans directories to match a given
12
+ Ruby regular expression. Prints highlighted results.
13
+
14
+ Based on the Perl tool 'ack' by Andy Lester.
15
+
16
+ Examples with similar grep:
17
+
18
+ $ prak pattern
19
+ $ grep pattern $(find . | grep -v .svn)
20
+
21
+ $ prak --ruby pattern
22
+ $ grep pattern $(find . -name '*.rb' | grep -v .svn)
23
+
24
+ == FEATURES/PROBLEMS:
25
+
26
+ * Ruby regular expression syntax (uses oniguruma gem if installed).
27
+ * Highlighted output.
28
+ * Automatically recurses down the current directory or any given
29
+ directories.
30
+ * Skips version control directories, backups like '~' and '#' and your
31
+ * ruby project's pkg directory.
32
+ * Allows inclusion and exclusion of files based on types.
33
+ * Many options similar to grep.
34
+
35
+ == SYNOPSIS:
36
+
37
+ See 'prak --help' for usage information.
38
+
39
+ == REQUIREMENTS:
40
+
41
+ * Ruby
42
+
43
+ == INSTALL:
44
+
45
+ * gem install prak
46
+
47
+ == LICENSE:
48
+
49
+ (The MIT License)
50
+
51
+ Original copyright (c) 2007 Daniel Lucraft
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+
2
+ require 'rubygems'
3
+ require 'hoe'
4
+
5
+ $:.unshift 'lib'
6
+
7
+ require 'prak'
8
+
9
+ Hoe.spec('prak') do |p|
10
+ p.author = 'Sven Winkler'
11
+ p.email = 'sven@q-logix.de'
12
+ p.version = Prak::VERSION
13
+ p.summary = 'A grep replacement in Ruby, type "$prak pattern".'
14
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
15
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
16
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
17
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require "prak"
6
+
7
+ Prak.search
@@ -0,0 +1,9 @@
1
+ class Prak
2
+ VERSION = "1.1"
3
+ end
4
+
5
+ require "prak/bootstrap"
6
+ require "prak/command_line"
7
+ require "prak/compile_match_file"
8
+ require "prak/file"
9
+ require "prak/search"
@@ -0,0 +1,22 @@
1
+ require 'getoptlong'
2
+
3
+ begin
4
+ require 'oniguruma'
5
+ require 'inline'
6
+ $use_onig = true
7
+ rescue LoadError
8
+ $use_onig = false
9
+ end
10
+
11
+ class String
12
+ def expand_tabs(shift=0)
13
+ expanded = dup
14
+ 1 while expanded.sub!(/\t+/){ " "*($&.size*8 - ($`.size+shift)%8) }
15
+ expanded
16
+ end
17
+ end
18
+
19
+
20
+
21
+
22
+
@@ -0,0 +1,292 @@
1
+ class Prak
2
+
3
+ FILE_COLOUR = "\033[1;31m"
4
+ MATCH_COLOUR = "\033[1;37m\033[41m"
5
+ CLEAR_COLOURS = "\033[0m"
6
+
7
+ FILE_TYPES = {
8
+ :asm => %w( .s .S ),
9
+ :cc => %w( .c .h .xs ),
10
+ :coffee => %w( .coffee.js .coffee ),
11
+ :cpp => %w( .cpp .cc .m .h .hpp .C .H ),
12
+ :csharp => %w( .cs ),
13
+ :css => %w( .css .sass .scss .less ),
14
+ :elisp => %w( .el ),
15
+ :haskell => %w( .hs .lhs ),
16
+ :hh => %w( .h ),
17
+ :html => %w( .htm .html .shtml ),
18
+ :image => %w( .bmp .gif .jpg .jpeg .png .psd ),
19
+ :lisp => %w( .lisp ),
20
+ :java => %w( .java properties ),
21
+ :js => %w( .js ),
22
+ :jsp => %w( .jsp .jspx .jhtm .jhtml ),
23
+ :make => %w( Makefile ),
24
+ :mason => %w( .mas .mhtml .mpl .mtxt ),
25
+ :ocaml => %w( .ml .mli ),
26
+ :parrot => %w( .pir .pasm .pmc .ops .pod .pg .tg ),
27
+ :perl => %w( .pl .pm .pod .t ),
28
+ :php => %w( .php .phpt .php3 .php4 .php5 ),
29
+ :prolog => %w( .pl .ecl ),
30
+ :python => %w( .py ),
31
+ :ruby => %w( .rb .rhtml .rjs .rxml Rakefile .rake .erb .haml .slim),
32
+ :scheme => %w( .scm ),
33
+ :shell => %w( .sh .bash .csh .ksh .zsh ),
34
+ :sql => %w( .sql .ctl ),
35
+ :tcl => %w( .tcl ),
36
+ :tex => %w( .tex .cls .sty ),
37
+ :text => %w( .txt .text ),
38
+ :tt => %w( .tt .tt2 .ttml ),
39
+ :vala => %w( .vala .vapi ),
40
+ :vb => %w( .bas .cls .frm .ctl .vb .resx ),
41
+ :vim => %w( .vim ),
42
+ :yaml => %w( .yaml .yml ),
43
+ :xml => %w( .xml .dtd .xslt )
44
+ }
45
+
46
+ VC_DIRS = %w(blib CVS _darcs .git .pc RCS SCCS .svn pkg)
47
+
48
+ class << self
49
+ attr_reader :opt
50
+ end
51
+
52
+ def self.unknown_type(type)
53
+ puts "rak: Unknown --type \"#{type}\""
54
+ puts "rak: See rak --help types"
55
+ exit
56
+ end
57
+
58
+ def self.parse_command_line_options options = {}
59
+
60
+ @opt = options
61
+
62
+ # file types
63
+ opt[:includes] = []
64
+ opt[:excludes] = []
65
+
66
+ FILE_TYPES.each do |type, exts|
67
+ if ARGV.delete('--'+type.to_s)
68
+ exts.each do |ext|
69
+ opt[:includes] << ext
70
+ end
71
+ end
72
+ if ARGV.delete('--no'+type.to_s)
73
+ exts.each do |ext|
74
+ opt[:excludes] << ext
75
+ end
76
+ end
77
+ end
78
+
79
+ opts = GetoptLong.new(
80
+ [ '--help', GetoptLong::OPTIONAL_ARGUMENT ],
81
+ [ '--max-count', '-m', GetoptLong::REQUIRED_ARGUMENT ],
82
+ [ '--files', '-f', GetoptLong::NO_ARGUMENT ],
83
+ [ '--output', GetoptLong::REQUIRED_ARGUMENT ],
84
+ [ '--version', GetoptLong::NO_ARGUMENT ],
85
+ [ '-c', '--count', GetoptLong::NO_ARGUMENT ],
86
+ [ '-h', '--no-filename', GetoptLong::NO_ARGUMENT ],
87
+ [ '-i', '--ignore-case', GetoptLong::NO_ARGUMENT ],
88
+ [ '-v', '--invert-match', GetoptLong::NO_ARGUMENT ],
89
+ [ '-n', GetoptLong::NO_ARGUMENT ],
90
+ [ '-Q', '--literal', GetoptLong::NO_ARGUMENT ],
91
+ [ '-o', GetoptLong::NO_ARGUMENT ],
92
+ [ '-w', '--word-regexp', GetoptLong::NO_ARGUMENT ],
93
+ [ '--group', GetoptLong::NO_ARGUMENT ],
94
+ [ '--nogroup', GetoptLong::NO_ARGUMENT ],
95
+ [ '-l', '--files-with-matches', GetoptLong::NO_ARGUMENT ],
96
+ [ '-L', '--files-without-matches', GetoptLong::NO_ARGUMENT ],
97
+ [ '--passthru', GetoptLong::NO_ARGUMENT ],
98
+ [ '-H', '--with-filename', GetoptLong::NO_ARGUMENT ],
99
+ [ '--colour', GetoptLong::NO_ARGUMENT ],
100
+ [ '--nocolour', GetoptLong::NO_ARGUMENT ],
101
+ [ '--color', GetoptLong::NO_ARGUMENT ],
102
+ [ '--nocolor', GetoptLong::NO_ARGUMENT ],
103
+ [ '-a', '--all', GetoptLong::NO_ARGUMENT ],
104
+ [ '--type', GetoptLong::REQUIRED_ARGUMENT ],
105
+ [ '--sort-files', GetoptLong::NO_ARGUMENT ],
106
+ [ '--follow', GetoptLong::NO_ARGUMENT ],
107
+ [ '--nofollow', GetoptLong::NO_ARGUMENT ],
108
+ [ '--after-context', '-A', GetoptLong::REQUIRED_ARGUMENT ],
109
+ [ '--before-context', '-B', GetoptLong::REQUIRED_ARGUMENT ],
110
+ [ '--context', '-C', GetoptLong::OPTIONAL_ARGUMENT ],
111
+ [ '-g', GetoptLong::REQUIRED_ARGUMENT ],
112
+ [ '-k', GetoptLong::REQUIRED_ARGUMENT ],
113
+ [ '-x', '--line-regexp', GetoptLong::NO_ARGUMENT ],
114
+ [ '-s', '--line-start', GetoptLong::NO_ARGUMENT ],
115
+ [ '-e', '--line-end', GetoptLong::NO_ARGUMENT ],
116
+ [ '-E', '--encoding', GetoptLong::REQUIRED_ARGUMENT ],
117
+ )
118
+
119
+ self.standard_options
120
+
121
+ # if redirected (RAK_TEST allows us to redirect in testing and still
122
+ # get the non-redirected defaults).
123
+ unless STDOUT.isatty or ENV['RAK_TEST'] == "true"
124
+ opt[:colour] = false
125
+ opt[:print_file_each_line] = true
126
+ opt[:print_filename] = false
127
+ opt[:print_line_number] = false
128
+ end
129
+
130
+ begin
131
+ opts.each do |option, arg|
132
+ case option
133
+ when '--help'
134
+ if arg == ""
135
+ # TODO: USAGE_HELP
136
+ puts USAGE_HELP
137
+ elsif arg == "types" or arg == "type"
138
+ puts TYPES_HELP
139
+ end
140
+ exit
141
+ when '--max-count'
142
+ opt[:max_count] = arg.to_i
143
+ when '--files'
144
+ opt[:only_print_filelist] = true
145
+ when '--output'
146
+ opt[:print_filename] = false
147
+ opt[:print_line_number] = false
148
+ opt[:print_output] = arg
149
+ opt[:print_highlighted] = false
150
+ when '--version'
151
+ puts VERSION_INFO
152
+ exit
153
+ when '-c'
154
+ opt[:print_num_matches] = true
155
+ opt[:print_filename] = false
156
+ opt[:print_line_number] = false
157
+ opt[:print_highlighted] = false
158
+ when '-h'
159
+ opt[:print_filename] = false
160
+ opt[:print_line_number] = false
161
+ opt[:print_file_each_line] = false
162
+ when '-i'
163
+ opt[:ignore_case] = true
164
+ when '-v'
165
+ opt[:invert_match] = true
166
+ when '-n'
167
+ opt[:descend] = false
168
+ when '-Q'
169
+ opt[:literal] = true
170
+ when '-o'
171
+ opt[:print_match] = true
172
+ opt[:print_filename] = false
173
+ opt[:print_line_number] = false
174
+ opt[:print_highlighted] = false
175
+ when '-w'
176
+ opt[:match_whole_words] = true
177
+ when '--group'
178
+ opt[:print_filename] = true
179
+ opt[:print_file_each_line] = false
180
+ when '--nogroup'
181
+ opt[:print_file_each_line] = true
182
+ opt[:print_filename] = false
183
+ opt[:print_line_number] = false
184
+ when '-l'
185
+ opt[:print_filename] = false
186
+ opt[:print_line_number] = false
187
+ opt[:print_highlighted] = false
188
+ opt[:print_file_if_match] = true
189
+ when '-L'
190
+ opt[:print_filename] = false
191
+ opt[:print_line_number] = false
192
+ opt[:print_highlighted] = false
193
+ opt[:print_file_if_no_match] = true
194
+ when '--passthru'
195
+ opt[:print_entire_line_if_no_match] = true
196
+ when '-H'
197
+ opt[:print_filename] = true
198
+ opt[:print_line_number] = true
199
+ when '--nocolour', '--nocolor'
200
+ opt[:colour] = false
201
+ when '--colour', '--color'
202
+ opt[:colour] = true
203
+ when '-a'
204
+ opt[:all_files] = true
205
+ when '--type'
206
+ if arg[0..1] == "no"
207
+ type = arg[2..-1]
208
+ arr = opt[:excludes]
209
+ else
210
+ type = arg
211
+ arr = opt[:includes]
212
+ end
213
+ exts = FILE_TYPES[type.intern]
214
+ unknown_type(type) unless exts
215
+ exts.each do |ext|
216
+ arr << ext
217
+ end
218
+ when '--sort-files'
219
+ opt[:sort_files] = true
220
+ when '--follow'
221
+ opt[:follow_symlinks] = true
222
+ when '--nofollow'
223
+ opt[:follow_symlinks] = false
224
+ when '--after-context'
225
+ opt[:use_context] = true
226
+ opt[:after_context] = arg.to_i
227
+ when '--before-context'
228
+ opt[:use_context] = true
229
+ opt[:before_context] = arg.to_i
230
+ when '--context'
231
+ opt[:use_context] = true
232
+ if arg == ""
233
+ val = 2
234
+ else
235
+ val = arg.to_i
236
+ end
237
+ opt[:before_context] = val
238
+ opt[:after_context] = val
239
+ when '-g'
240
+ opt[:filename_regex] = compile_regexp(arg)
241
+ when '-k'
242
+ opt[:neg_filename_regex] = compile_regexp(arg)
243
+ when '-x'
244
+ opt[:match_whole_lines] = true
245
+ when '-s'
246
+ opt[:match_line_starts] = true
247
+ when '-e'
248
+ opt[:match_line_ends] = true
249
+ end
250
+ end
251
+ rescue GetoptLong::InvalidOption => ex
252
+ puts "rak: see rak --help for usage."
253
+ exit
254
+ rescue SystemExit
255
+ exit
256
+ end
257
+ end
258
+
259
+ def self.standard_options
260
+ opt[:max_count] = nil
261
+ opt[:only_print_filelist] = false
262
+ opt[:print_filename] = true
263
+ opt[:print_line_number] = true
264
+ opt[:print_output] = nil
265
+ opt[:print_highlighted] = true
266
+ opt[:print_num_matches] = false
267
+ opt[:ignore_case] = false
268
+ opt[:invert_match] = false
269
+ opt[:descend] = true
270
+ opt[:literal] = false
271
+ opt[:print_match] = false
272
+ opt[:match_whole_words] = false
273
+ opt[:match_whole_lines] = false
274
+ opt[:match_line_starts] = false
275
+ opt[:match_line_ends] = false
276
+ opt[:print_file_each_line] = false
277
+ opt[:print_file_if_match] = false
278
+ opt[:print_file_if_no_match] = false
279
+ opt[:print_entire_line_if_no_match] = false
280
+ opt[:colour] = true
281
+ opt[:all_files] = false
282
+ opt[:sort_files] = false
283
+ opt[:follow_symlinks] = false
284
+ opt[:after_context] = 0
285
+ opt[:before_context] = 0
286
+ opt[:collect_context] = false
287
+ opt[:filename_regex] = nil
288
+ opt[:neg_filename_regex] = nil
289
+ opt[:standard_encoding] = "UTF-8"
290
+ end
291
+
292
+ end
@@ -0,0 +1,145 @@
1
+ class Prak
2
+ def self.compile_match_file
3
+ c = []
4
+ c << %{def match_file(re, fn, file_separator) }
5
+ c << %{ displayed_filename = false }
6
+ c << %{ count = 0 }
7
+ c << %{ i = 0 }
8
+ c << %{ matches = [] }
9
+ c << %{ print_num = 0 }
10
+
11
+ if opt[:before_context] > 0
12
+ c << %{ before_context = [] }
13
+ c << %{ before_context_size = opt[:before_context] }
14
+ end
15
+ c << %{ if fn.is_a? String }
16
+ c << %{ f = File.open(fn, "r", :encoding => opt[:standard_encoding]) }
17
+ c << %{ elsif fn.is_a? IO }
18
+ c << %{ f = fn }
19
+ c << %{ end }
20
+
21
+ c << %{ f.each_line do |line| }
22
+ c << %{ line = line.force_encoding("BINARY") unless line.valid_encoding? }
23
+ c << %{ i += 1 }
24
+ if opt[:print_output]
25
+ c << %{ line.scan(re){ matches << eval(opt[:print_output]) } }
26
+ else
27
+ c << %{ line.scan(re){ matches << $~ } }
28
+ end
29
+ if opt[:print_match]
30
+ c << %{ matches.each{|md| puts md.to_s } }
31
+ end
32
+ c << %{ count += matches.size }
33
+ if opt[:invert_match]
34
+ if opt[:print_filename]
35
+ c << %{ unless displayed_filename }
36
+ c << %{ print file_separator }
37
+ c << %{ file_separator.replace("\\n") }
38
+ c << %{ puts FILE_COLOUR + fn + CLEAR_COLOURS }
39
+ c << %{ displayed_filename = true }
40
+ c << %{ end }
41
+ end
42
+ c << %{ if matches.empty? }
43
+ if opt[:print_highlighted]
44
+ if opt[:print_line_number]
45
+ c << %{ print "\#{i.to_s.rjust(4) }|" }
46
+ end
47
+ c << %{ puts "\#{line.expand_tabs }" }
48
+ end
49
+ c << %{ end }
50
+ c << %{ matches.clear }
51
+ else
52
+ c << %{ if matches.empty? }
53
+ if opt[:print_entire_line_if_no_match]
54
+ c << %{ puts line }
55
+ end
56
+ if opt[:use_context]
57
+ if opt[:before_context] > 0
58
+ c << %{ if print_num == 0 }
59
+ c << %{ before_context << [i, line] }
60
+ c << %{ if before_context.length > before_context_size }
61
+ c << %{ before_context.shift }
62
+ c << %{ end }
63
+ c << %{ end }
64
+ end
65
+ c << %{ if print_num > 0 }
66
+ c << %{ print_num -= 1 }
67
+ if opt[:print_highlighted]
68
+ if opt[:print_line_number]
69
+ c << %{ print "\#{i.to_s.rjust(4) }|" }
70
+ end
71
+ c << %{ puts "\#{line.expand_tabs }" }
72
+ c << %{ end }
73
+ end
74
+ end
75
+ c << %{ else }
76
+ c << %{ print_num = opt[:after_context] }
77
+ if opt[:print_filename]
78
+ c << %{ unless displayed_filename }
79
+ c << %{ print file_separator }
80
+ c << %{ file_separator.replace("\\n") }
81
+ c << %{ puts FILE_COLOUR + fn + CLEAR_COLOURS }
82
+ c << %{ displayed_filename = true }
83
+ c << %{ end }
84
+ end
85
+ if opt[:before_context] > 0
86
+ c << %{ before_context.each do |before_i, before_line| }
87
+ if opt[:print_line_number]
88
+ c << %{ print "\#{before_i.to_s.rjust(4) }|" }
89
+ end
90
+ c << %{ puts before_line.expand_tabs }
91
+ c << %{ end }
92
+ c << %{ before_context = [] }
93
+ end
94
+ if opt[:print_output]
95
+ c << %{ matches.each {|m| puts m } }
96
+ end
97
+ if opt[:print_highlighted]
98
+ if opt[:print_line_number]
99
+ c << %{ prefix = "\#{i.to_s.rjust(4) }|" }
100
+ else
101
+ if opt[:print_file_each_line]
102
+ c << %{ fn_str = (fn.is_a?(String) ? FILE_COLOUR + fn + CLEAR_COLOURS + ":" : "") }
103
+ c << %{ prefix = fn_str + "\#{i.to_s }:" }
104
+ else
105
+ c << %{ prefix = "" }
106
+ end
107
+ end
108
+ c << %{ print_highlighted(prefix, line, matches) }
109
+ end
110
+ c << %{ end }
111
+ if opt[:max_count]
112
+ c << %{ if count >= opt[:max_count] }
113
+ c << %{ break }
114
+ c << %{ end }
115
+ end
116
+ c << %{ matches.clear }
117
+ end
118
+ c << %{ end }
119
+ c << %{ f.close if f === File }
120
+ if opt[:print_num_matches]
121
+ if opt[:invert_match]
122
+ c << %{ puts "\#{fn }:\#{i-count }" }
123
+ else
124
+ c << %{ if count > 0 }
125
+ c << %{ puts "\#{fn }:\#{count }" }
126
+ c << %{ end }
127
+ end
128
+ end
129
+ if opt[:print_file_if_match]
130
+ c << %{ if count > 0 }
131
+ c << %{ puts fn }
132
+ c << %{ end }
133
+ end
134
+
135
+ if opt[:print_file_if_no_match]
136
+ c << %{ if count == 0 }
137
+ c << %{ puts fn }
138
+ c << %{ end }
139
+ end
140
+ c << %{end }
141
+
142
+ Prak.instance_eval c.join("\n")
143
+
144
+ end
145
+ end
@@ -0,0 +1,142 @@
1
+ class Prak
2
+
3
+ def self.file_relevant?(fn)
4
+ # These don't change at this point
5
+ @types_rx ||= extension_regexp(FILE_TYPES.values.flatten)
6
+ @includes_rx ||= extension_regexp(opt[:includes])
7
+ @excludes_rx ||= extension_regexp(opt[:excludes])
8
+
9
+ ext = File.basename(fn)
10
+ ext = shebang_matches(fn) unless ext =~ @types_rx
11
+
12
+ return false if !opt[:all_files] and !ext or fn =~ /[~#]\z/
13
+ return false if @includes_rx and (ext||"") !~ @includes_rx
14
+ return false if @excludes_rx and (ext||"") =~ @excludes_rx
15
+ return false if opt[:filename_regex] and fn !~ opt[:filename_regex]
16
+ return false if opt[:neg_filename_regex] and fn =~ opt[:neg_filename_regex]
17
+ return true
18
+ end
19
+
20
+ def self.find_all_files(path, &blk)
21
+ return if File.socket?(path)
22
+ return unless File.readable?(path)
23
+
24
+ if File.file?(path)
25
+ return unless file_relevant?(path)
26
+ yield(path.sub(/\A\.\/+/, "").gsub(/\/+/, "/"))
27
+ elsif File.directory?(path)
28
+ Dir["#{path}/*"].each do |fn|
29
+ next if VC_DIRS.any?{|vc| vc == File.basename(fn)}
30
+ next if File.directory?(fn) and not opt[:descend]
31
+ next if File.symlink?(fn) and not opt[:follow_symlinks]
32
+ find_all_files(fn, &blk)
33
+ end
34
+ end
35
+ end
36
+
37
+ # It's really asking for Pathname...
38
+ def self.each_file(todo, &blk)
39
+ if todo.empty?
40
+ if STDIN.isatty
41
+ todo = ["."]
42
+ else
43
+ opt[:print_filename] = false
44
+ yield(STDIN)
45
+ return
46
+ end
47
+ elsif todo.size == 1 and File.file?(todo[0])
48
+ opt[:print_filename] = false
49
+ end
50
+
51
+ if opt[:sort_files]
52
+ sortme = []
53
+ todo.each do |item|
54
+ find_all_files(item) do |fn|
55
+ sortme << fn
56
+ end
57
+ end
58
+ sortme.sort_by{|fn|fn.downcase}.each(&blk)
59
+ else
60
+ todo.each do |item|
61
+ find_all_files(item, &blk)
62
+ end
63
+ end
64
+ end
65
+
66
+ def self.print_highlighted(prefix, line, matches)
67
+ print prefix
68
+ matches = matches.map{|md| md.offset(0)}
69
+ cuts = [0, matches, line.size].flatten
70
+ column = 0
71
+ 0.upto(cuts.size-2) do |i|
72
+ part = line[cuts[i]...cuts[i+1]]
73
+ part = part.expand_tabs(column)
74
+ column += part.size
75
+ print MATCH_COLOUR if i%2 == 1
76
+ print part
77
+ print CLEAR_COLOURS if i%2 == 1
78
+ end
79
+ print "\n" unless line[-1,1] == "\n"
80
+ end
81
+
82
+ def self.compile_regexp(str)
83
+ if $use_onig
84
+ Oniguruma::ORegexp.new(str)
85
+ else
86
+ Regexp.new(str)
87
+ end
88
+ end
89
+
90
+ def self.extension_regexp(extensions)
91
+ return nil if extensions.empty?
92
+ Regexp.compile('(?:' + extensions.map{|x| Regexp.escape(x)}.join("|") + ')\z')
93
+ end
94
+
95
+ def self.shebang_matches(fn)
96
+ begin
97
+ line = File.open(fn, :encoding => opt[:standard_encoding]).readline
98
+ if line =~ /^#!/
99
+ if line =~ /\b(ruby|perl|php|python|make)[0-9.]*\b/i
100
+ FILE_TYPES[$1.downcase.intern].first
101
+ elsif line =~ /\b(sh|bash|csh|ksh|zsh)\b/
102
+ ".sh"
103
+ else
104
+ ".other"
105
+ end
106
+ elsif line =~ /^<\?xml\b/
107
+ ".xml"
108
+ else
109
+ false
110
+ end
111
+ rescue
112
+ nil
113
+ end
114
+ end
115
+
116
+ def self.compile_pattern(str)
117
+ if opt[:literal]
118
+ str = Regexp.quote(str)
119
+ end
120
+ if opt[:match_whole_words]
121
+ str = "\\b(?:" + str + ")\\b"
122
+ end
123
+ if opt[:match_whole_lines]
124
+ str = "^(?:" + str + ")$"
125
+ end
126
+ if opt[:match_line_starts]
127
+ str = "^(?:" + str + ")"
128
+ end
129
+ if opt[:match_line_ends]
130
+ str = "(?:" + str + ")$"
131
+ end
132
+ str = str.gsub("~bang", "!").gsub("~ques", "?")
133
+ if $use_onig
134
+ flags = opt[:ignore_case] ? Oniguruma::OPTION_IGNORECASE : nil
135
+ Oniguruma::ORegexp.new(str, :options => flags)
136
+ else
137
+ flags = opt[:ignore_case] ? Regexp::IGNORECASE : nil
138
+ Regexp.new(str, flags)
139
+ end
140
+ end
141
+
142
+ end
@@ -0,0 +1,36 @@
1
+ class Prak
2
+
3
+ def self.search
4
+
5
+ parse_command_line_options
6
+
7
+ unless opt[:colour]
8
+ FILE_COLOUR.replace ""
9
+ CLEAR_COLOURS.replace ""
10
+ MATCH_COLOUR.replace ""
11
+ end
12
+
13
+ if opt[:only_print_filelist]
14
+ each_file(ARGV) do |fn|
15
+ puts fn
16
+ end
17
+ elsif ARGV.empty?
18
+ # TODO USAGE_HELP
19
+ puts USAGE_HELP
20
+ exit
21
+ else
22
+ re = compile_pattern(ARGV.shift)
23
+ compiled = false
24
+ file_separator = ""
25
+ each_file(ARGV) do |fn|
26
+ # each_file might turn off printing file name, but only before first yield
27
+ unless compiled
28
+ compile_match_file
29
+ compiled = true
30
+ end
31
+ match_file(re, fn, file_separator)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+
2
+ Gem::Specification.spec do |s|
3
+ s.name = %q{prak}
4
+ s.version = "2.0"
5
+
6
+ s.authors = ["Daniel Lucraft"]
7
+ s.date = %q{2008-02-03}
8
+ s.default_executable = %q{prak}
9
+ s.description = %q{Based on the Perl tool 'ack' by Andy Lester. Examples with similar grep: $ prak pattern $ grep pattern $(find . | grep -v .svn) $ prak --ruby pattern $ grep pattern $(find . -name '*.rb' | grep -v .svn) == FEATURES/PROBLEMS: * Ruby regular expression syntax (uses oniguruma gem if installed). * Highlighted output. * Automatically recurses down the current directory or any given directories. * Skips version control directories, backups like '~' and '#' and your * ruby project's pkg directory. * Allows inclusion and exclusion of files based on types. * Many options similar to grep.}
10
+ s.email = %q{dan@fluentradical.com}
11
+ s.executables = ["prak"]
12
+ s.files = FileList["{lib,spec,bin,doc}/**/*"]
13
+ s.homepage = %q{http://github.com/sven-q/prak.git}
14
+ s.require_paths = ["lib"]
15
+ s.rubygems_version = %q{1.3.0}
16
+ s.summary = %q{A grep replacement in Ruby, type "prak pattern".}
17
+ s.required_ruby_version = '>= 1.9.2'
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: prak
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sven Winkler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hoe
16
+ requirement: &2153032040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.12'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2153032040
25
+ description: ! 'Modifications by Sven Winkler
26
+
27
+
28
+ == DESCRIPTION:
29
+
30
+
31
+ Replacement for grep. Recursively scans directories to match a given
32
+
33
+ Ruby regular expression. Prints highlighted results.
34
+
35
+
36
+ Based on the Perl tool ''ack'' by Andy Lester.'
37
+ email: sven@q-logix.de
38
+ executables:
39
+ - prak
40
+ extensions: []
41
+ extra_rdoc_files:
42
+ - History.txt
43
+ - Manifest.txt
44
+ - README.txt
45
+ files:
46
+ - History.txt
47
+ - Manifest.txt
48
+ - README.txt
49
+ - Rakefile
50
+ - bin/prak
51
+ - lib/prak.rb
52
+ - lib/prak/bootstrap.rb
53
+ - lib/prak/command_line.rb
54
+ - lib/prak/compile_match_file.rb
55
+ - lib/prak/file.rb
56
+ - lib/prak/search.rb
57
+ - prak.gemspec
58
+ - .gemtest
59
+ homepage:
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --main
64
+ - README.txt
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: prak
81
+ rubygems_version: 1.8.6
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A grep replacement in Ruby, type "$prak pattern".
85
+ test_files: []