ssoroka-grepmate 1.0.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 (6) hide show
  1. data/Manifest +4 -0
  2. data/README +47 -0
  3. data/Rakefile +14 -0
  4. data/bin/grepmate +292 -0
  5. data/grepmate.gemspec +34 -0
  6. metadata +71 -0
data/Manifest ADDED
@@ -0,0 +1,4 @@
1
+ bin/grepmate
2
+ Rakefile
3
+ README
4
+ Manifest
data/README ADDED
@@ -0,0 +1,47 @@
1
+ = grepmate
2
+
3
+ Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
4
+
5
+ == SYNOPSIS
6
+
7
+ grepmate [what_to_search_for*] [dir=dir] [exclude=exclude] [options]+
8
+
9
+ == PARAMETERS
10
+
11
+ what_to_search_for (-1 ~> what_to_search_for)
12
+ What to search for. Enclose in quotes to search for phrase.
13
+ dir=dir (-1 ~>
14
+ dir=app,config,db,lib,spec,public,vendor/plugins,test/selenium_fixtures,test/selenium)
15
+ Directories to search. Defaults to project.
16
+ exclude=exclude (-1 ~>
17
+ exclude=\.sql$,\.log$,\.tmp$,\.gz$,\.bz2$,\.tar$,\.db$,\.sqlite$,\.sqlite3$,\.csv$,\.DS_Store$,\.svn,\.git,\.CSV$,grepmate\.html$)
18
+ Exclude paths matching these patterns.
19
+ --case
20
+ Case sensitive search (exclude for case insensitive).
21
+ --no_html, -H
22
+ Turn off HTML output.
23
+ --only_rails, -R
24
+ Search Rails source, not the project. Takes precedence over dir=
25
+ --rails, -r
26
+ Search Rails source, in addition to whatever is named by dir= dir=
27
+ etc.
28
+ --gems, -g
29
+ Search all gems, in addition to whatever is named by dir= dir= etc.
30
+ --only_gems, -G
31
+ Search only gems, not the project. Takes precedence over dir=
32
+ --wait, -w
33
+ Wait between finds until TextMate is closed. Only works with
34
+ --no_html.
35
+ --count, -c
36
+ Display only the number of matches.
37
+ --help, -h
38
+
39
+ == Authors
40
+
41
+ - Steven Soroka
42
+ - Zach Holt
43
+
44
+ == To Do
45
+
46
+ - check ~/.grepmate for current rails repo to use instead of always using latest
47
+ - change output file to write to /tmp or something
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('grepmate', '1.0.0') do |p|
6
+ p.description = 'Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output'
7
+ p.url = 'http://github.com/ssoroka/grepmate'
8
+ p.author = 'Steven Soroka'
9
+ p.email = 'ssoroka78@gmail.com'
10
+ p.ignore_pattern = ["tmp/*"]
11
+ p.development_dependencies = ['main']
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each{|f| load f }
data/bin/grepmate ADDED
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env ruby
2
+ # script/grepmate brought to you by Steven Soroka and Zach Holt
3
+ # script/grepmate --help for help screen
4
+ require 'rubygems'
5
+ gem 'main', '>=2.8.0'
6
+ require 'main' # don't think this line is needed. gem should require it
7
+
8
+
9
+ def gem_path
10
+ `gem environment gemdir`.chomp
11
+ end
12
+
13
+ def gems_path
14
+ File.join(gem_path, 'gems')
15
+ end
16
+
17
+ def rails_version
18
+ `rails -v`.chomp.split(' ').last
19
+ end
20
+
21
+ def rails_path
22
+ vendor_rails = "vendor/rails"
23
+
24
+ if File.exist?(vendor_rails)
25
+ vendor_rails
26
+ else
27
+ Dir["#{gems_path}/acti*-#{rails_version}"]
28
+ end
29
+ end
30
+
31
+ Main {
32
+ option( 'case' ) {
33
+ cast :bool
34
+ description 'Case sensitive search (exclude for case insensitive).'
35
+ }
36
+
37
+ option( 'no_html', 'H' ) {
38
+ cast :bool
39
+ description 'Turn off HTML output.'
40
+ }
41
+
42
+ option( 'only_rails', 'R' ) {
43
+ cast :bool
44
+ description 'Search Rails source, not the project. Takes precedence over dir='
45
+ }
46
+
47
+ option( 'rails', 'r' ) {
48
+ cast :bool
49
+ description 'Search Rails source, in addition to whatever is named by dir= dir= etc.'
50
+ }
51
+
52
+ option('gems', 'g') {
53
+ cast :bool
54
+ description "Search all gems, in addition to whatever is named by dir= dir= etc."
55
+ }
56
+
57
+ option('only_gems', 'G') {
58
+ cast :bool
59
+ description "Search only gems, not the project. Takes precedence over dir="
60
+ }
61
+
62
+ option( 'wait', 'w' ) {
63
+ cast :bool
64
+ description 'Wait between finds until TextMate is closed. Only works with --no_html.'
65
+ }
66
+
67
+ option( 'count', 'c' ) {
68
+ cast :bool
69
+ description 'Display only the number of matches.'
70
+ }
71
+
72
+ keyword( 'dir', 'd' ) {
73
+ arity -1
74
+ default 'app', 'config', 'db', 'lib', 'spec', 'public', 'vendor/plugins', 'test/selenium_fixtures', 'test/selenium'
75
+ description 'Directories to search. Defaults to project.'
76
+ }
77
+
78
+ keyword( 'exclude' ) {
79
+ arity -1
80
+ cast { |v| Regexp.new( v ) }
81
+ default '\.sql$', '\.log$', '\.tmp$', '\.gz$', '\.bz2$', '\.tar$', '\.db$', '\.sqlite$', '\.sqlite3$', '\.csv$', '\.DS_Store$', '\.svn', '\.git', '\.CSV$', 'grepmate\.html$'
82
+ description 'Exclude paths matching these patterns.'
83
+ }
84
+
85
+ argument( 'what_to_search_for' ) {
86
+ arity -1
87
+ description "What to search for. Enclose in quotes to search for phrase."
88
+ }
89
+
90
+
91
+ def determine_directories_to_search
92
+ if @stdin.tty?
93
+ dirs = if params['only_rails'].value || params['only_gems'].value
94
+ []
95
+ else
96
+ params['dir'].values
97
+ end
98
+ dirs += Array(rails_path) if params['only_rails'].value || params['rails'].value
99
+ dirs << gems_path if params['only_gems'].value || params['gems'].value
100
+ else
101
+ dirs = []
102
+ input = @stdin.read
103
+
104
+ input.split( "\n" ).each do |ln|
105
+ if ln =~ /^([^:]*)/ # Assume everything to the first colon is a file name
106
+ filename = File.expand_path( $1 )
107
+ if File.exist?( filename ) # But actually check that it is
108
+ dirs << filename
109
+ end
110
+ end
111
+ end
112
+ end
113
+ dirs.map{ |dir| File.expand_path( dir ) }.uniq
114
+ end
115
+
116
+ def determine_what_to_search_for
117
+ # funny bunny => 'funny' 'bunny'
118
+ # 'funny bunny' => 'funny bunny'
119
+ params['what_to_search_for'].values.map {|v| "\"#{v.gsub( /"/, '\\"' )}\"" }.join( " " )
120
+ end
121
+
122
+ def determine_javascript_highlight_text
123
+ # funny bunny => 'funny' 'bunny'
124
+ # 'funny bunny' => 'funny bunny'
125
+ params['what_to_search_for'].values.map {|v| "highlightSearchTerms('#{v.gsub( /'/, "\\'" ).gsub( /:/, "\\:" )}', false)" }.join( ";" )
126
+ end
127
+
128
+ def find( what_to_find, opts={} )
129
+ directories = opts[:in]
130
+
131
+ paths = `find #{directories.join(' ')}`.split( "\n" )
132
+
133
+ paths.delete_if { |path| params['exclude'].values.any?{ |exclude| path =~ exclude } }
134
+
135
+ cmd = 'grep '
136
+ cmd << '-i ' unless params['case'].value
137
+ # 3 lines of context unless we're not displaying html, or we're counting, or we're piping into another process
138
+ cmd << '-C 3 ' if !params['no_html'].value && !params['count'].value && @stdout.tty?
139
+
140
+ # paths get too large for grep to handle, so limit the number it has to deal with at once.
141
+ results = []
142
+ paths.each_slice(100) {|paths|
143
+ results += `#{cmd} -n #{what_to_find} #{paths.join(" ")}`.split( "\n" )
144
+ }
145
+ results
146
+ end
147
+
148
+ def display( results )
149
+ if results.empty?
150
+ puts "Nothing found!"
151
+ exit
152
+ elsif params['count'].value
153
+ puts "Matches: #{results.size}"
154
+ exit
155
+ end
156
+
157
+ if @stdout.tty?
158
+ if params['no_html'].value
159
+ display_textmate results
160
+ else
161
+ display_html results
162
+ end
163
+ else
164
+ puts results
165
+ end
166
+ end
167
+
168
+ def display_textmate( results )
169
+ print "Found #{results.size} matches. "
170
+ if results.size > 20
171
+ puts "Display? [Y/n]..."
172
+ exit if $stdin.gets.chomp.downcase == 'n'
173
+ end
174
+
175
+ results.each { |f|
176
+ file, line = f.split( ':' )
177
+ system( "mate #{'-w ' if params['wait'].value}-l #{line} #{file}" )
178
+ }
179
+ end
180
+
181
+ def display_html( results )
182
+ syntax_installed = true
183
+ begin
184
+ require 'syntax/convertors/html'
185
+ rescue LoadError
186
+ syntax_installed = false
187
+ end
188
+
189
+ html = '<html><head>'
190
+ html << <<-CSS
191
+ <style type="text/css">body { background-color: #EEEEEE; } pre {
192
+ display: inline; } .ruby { font-family: Monaco; font-size: 10pt;
193
+ background-color: white } .ruby .normal {} .ruby .comment { color:
194
+ #005; font-style: italic; } .ruby .keyword { color: #A00; font-weight:
195
+ bold; } .ruby .method { color: #077; } .ruby .class { color: #074; }
196
+ .ruby .module { color: #050; } .ruby .punct { color: #447; font-weight:
197
+ bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944;
198
+ background: #FFE; } .ruby .char { color: #F07; } .ruby .ident { color:
199
+ #004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66;
200
+ background: #FEF; } .ruby .number { color: #F99; } .ruby .attribute {
201
+ color: #7BB; } .ruby .global { color: #7FB; } .ruby .expr { color:
202
+ #227; } .ruby .escape { color: #277; } .ruby .highlight {
203
+ background-color: yellow; font-weight: 900; } td.lineno { text-align:
204
+ right; font-family: Monaco; font-size: 9pt; padding-right: 10px; }
205
+ td.filename { padding-top: 35px; font-family: Monaco; font-size: 14pt;
206
+ }</style>
207
+
208
+ <script type="text/javascript">
209
+ // http://www.nsftools.com/misc/SearchAndHighlight.htm
210
+
211
+ function doHighlight(bodyText,searchTerm,highlightStartTag,highlightEndTag)
212
+ {if((!highlightStartTag)||(!highlightEndTag)){highlightStartTag="<font style='color:blue; background-color:yellow;'>";highlightEndTag="</font>";}
213
+ var newText="";var i=-1;var lcSearchTerm=searchTerm.toLowerCase();var lcBodyText=bodyText.toLowerCase();while(bodyText.length>0){i=lcBodyText.indexOf(lcSearchTerm,i+1);if(i<0){newText+=bodyText;bodyText="";}else{if(bodyText.lastIndexOf(">",i)>=bodyText.lastIndexOf("<",i)){if(lcBodyText.lastIndexOf("/script>",i)>=lcBodyText.lastIndexOf("<script",i)){newText+=bodyText.substring(0,i)+highlightStartTag+bodyText.substr(i,searchTerm.length)+highlightEndTag;bodyText=bodyText.substr(i+searchTerm.length);lcBodyText=bodyText.toLowerCase();i=-1;}}}}
214
+ return newText;}
215
+ function highlightSearchTerms(searchText,treatAsPhrase,warnOnFailure,highlightStartTag,highlightEndTag)
216
+ {if(treatAsPhrase){searchArray=[searchText];}else{searchArray=searchText.split(" ");}
217
+ if(!document.body||typeof(document.body.innerHTML)=="undefined"){if(warnOnFailure){alert("Sorry, for some reason the text of this page is unavailable. Searching will not work.");}
218
+ return false;}
219
+ var bodyText=document.body.innerHTML;for(var i=0;i<searchArray.length;i++){bodyText=doHighlight(bodyText,searchArray[i],highlightStartTag,highlightEndTag);}
220
+ document.body.innerHTML=bodyText;return true;}</script></script>
221
+ CSS
222
+
223
+ html << "</head><body onLoad=\"#{determine_javascript_highlight_text}\">"
224
+
225
+ syntax_converter = ( syntax_installed ? Syntax::Convertors::HTML.for_syntax( "ruby" ) : nil )
226
+ html << '<pre>sudo gem install syntax</pre> to get syntax highlighting<br><br>' unless syntax_installed
227
+
228
+ html << '<table cellspacing="0" cellpadding="2">'
229
+
230
+ last_file = ''
231
+ separator = false
232
+
233
+ html << results.map{ |line|
234
+ if line == '--'
235
+ separator = true
236
+ ''
237
+ elsif line =~ /^(.+?)-(\d+)-(.*)$/ || line =~ /^(.+?):(\d+):(.*)$/
238
+ file = $1
239
+ line = $2
240
+ context = $3
241
+
242
+ file_group = ''
243
+
244
+ if file == last_file
245
+ file_group << "<tr><td class=\"lineno\">...</td><td></td></tr>" if separator
246
+ else
247
+ parts = file.split( /\// )
248
+ path = ''
249
+ file_group << "<tr><td colspan=\"2\" class=\"filename\">"
250
+ parts.each do |part|
251
+ path << "/#{part}"
252
+ file_group << "/" unless part.equal?( parts.first )
253
+ if part.equal?( parts.last )
254
+ file_group << "<a href=\"txmt://open?url=file://#{file}\">#{part}</a>"
255
+ else
256
+ file_group << "<a href=\"file:/#{path}\">#{part}</a>"
257
+ end
258
+ end
259
+ file_group << "</td></tr>\n"
260
+ end
261
+
262
+ separator = false
263
+ last_file = file
264
+
265
+ file_group << "<tr><td class=\"lineno\"><a href=\"txmt://open?url=file://#{file}&line=#{line}\">#{line}</a></td>"
266
+
267
+ converted = begin
268
+ syntax_converter ? syntax_converter.convert( context =~ /^(.+?)\s*$/ ? $1 : context ) : context
269
+ rescue Exception => e
270
+ "TOKENIZING ERROR: #{context} <!-- \n#{e.message}\n#{e.backtrace.join("\n")}\n -->"
271
+ end
272
+ file_group << "<td class=\"ruby\">#{ converted }</td></tr>\n"
273
+
274
+ file_group
275
+ end
276
+ }.join
277
+
278
+ html << '</table></body></html>'
279
+
280
+ File.open('grepmate.html', 'w') { |f| f.write(html) }
281
+ system("open grepmate.html")
282
+ end
283
+
284
+ def run
285
+ haystack = determine_directories_to_search
286
+ needle = determine_what_to_search_for
287
+
288
+ results = find needle, :in => haystack
289
+
290
+ display results
291
+ end
292
+ }
data/grepmate.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{grepmate}
3
+ s.version = "1.0.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Steven Soroka"]
7
+ s.date = %q{2008-12-05}
8
+ s.default_executable = %q{grepmate}
9
+ s.description = %q{Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output}
10
+ s.email = %q{ssoroka78@gmail.com}
11
+ s.executables = ["grepmate"]
12
+ s.extra_rdoc_files = ["bin/grepmate", "README"]
13
+ s.files = ["bin/grepmate", "Rakefile", "README", "Manifest", "grepmate.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/ssoroka/grepmate}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Grepmate", "--main", "README"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{grepmate}
19
+ s.rubygems_version = %q{1.2.0}
20
+ s.summary = %q{Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if current_version >= 3 then
27
+ s.add_development_dependency(%q<main>, [">= 0"])
28
+ else
29
+ s.add_dependency(%q<main>, [">= 0"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<main>, [">= 0"])
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ssoroka-grepmate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Steven Soroka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-05 00:00:00 -08:00
13
+ default_executable: grepmate
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: main
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
25
+ email: ssoroka78@gmail.com
26
+ executables:
27
+ - grepmate
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - bin/grepmate
32
+ - README
33
+ files:
34
+ - bin/grepmate
35
+ - Rakefile
36
+ - README
37
+ - Manifest
38
+ - grepmate.gemspec
39
+ has_rdoc: true
40
+ homepage: http://github.com/ssoroka/grepmate
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --line-numbers
44
+ - --inline-source
45
+ - --title
46
+ - Grepmate
47
+ - --main
48
+ - README
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "1.2"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project: grepmate
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
70
+ test_files: []
71
+