google 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/bin/google CHANGED
@@ -2,4 +2,35 @@
2
2
 
3
3
  require_relative '../lib/google'
4
4
 
5
- # Trollop::die "This is a fancy trollop die message."
5
+ opts = Trollop::options do
6
+ version "google v1.0.9 (c) 2012 Kerrick Long http://kerrick.github.com/google"
7
+ banner <<-EOM
8
+ The google gem is a simple tool to search Gooogle with via a CLI.
9
+ Usage:
10
+ google [options] "my search query string here"
11
+ where [options] are:
12
+ EOM
13
+
14
+ opt :page, "Start by showing the <i>th result page.", :type => :int, :default => 1
15
+ opt :size, "Show <i> results on each SERP. Must be between 1 and 8.", :type => :int, :default => 4
16
+ opt :result, "Skip the SERP and show the <i>th result.", :type => :int
17
+ opt :lucky, "I'm feeling lucky! Skip the SERP and show the first result. (Alias to --result 1)"
18
+ opt :readability, "Filter the results through readability to get rid of extra content.", :default => true
19
+ opt :markdown, "Change the results from raw HTML to markdown.", :default => true
20
+ opt :version, "Print the version and exit."
21
+ opt :help, "Show this information and exit."
22
+ end
23
+
24
+ query = ARGV.join(' ')
25
+ raise Trollop::die "no search query specified" if query.empty?
26
+
27
+ opts[:result] = 1 if opts[:lucky]
28
+ raise Trollop::die "Must use --no-markdown if you use --no-readability" if !opts[:readability] && opts[:markdown]
29
+
30
+ begin
31
+ g = Google.new query, opts
32
+ g.search
33
+ rescue Interrupt
34
+ puts "\nInterrupt received. Exiting application."
35
+ exit
36
+ end
@@ -1,19 +1,19 @@
1
1
  Gem::Specification.new do |s|
2
- s.name = "google"
3
- s.version = "1.0.8"
2
+ s.name = "google"
3
+ s.version = "1.0.9"
4
4
  s.executables << 'google'
5
+ s.add_runtime_dependency "trollop", ["~> 1"]
5
6
  s.add_runtime_dependency "json", ["~> 1"]
6
7
  s.add_runtime_dependency "htmlentities", ["~> 4"]
7
8
  s.add_runtime_dependency "formatador", ["~> 0.2"]
8
9
  s.add_runtime_dependency "ruby-readability", ["~> 0.5"]
9
- s.date = "2012-05-23"
10
- s.summary = "Google Search on the command line"
10
+ s.date = "2012-05-25"
11
+ s.summary = "Google Search on the command line"
11
12
  s.description = "A ruby gem to give you the power of Google Search in your command line."
12
- s.authors = ["Kerrick Long"]
13
- s.email = "me@kerricklong.com"
14
- s.files = ["lib/google.rb"]
15
- s.files += %w(LICENSE.md README.md google.gemspec)
16
- s.files += Dir.glob("lib/**/*.rb")
17
- s.files += Dir.glob("bin/**/*")
18
- s.homepage = "http://kerrick.github.com/google/"
13
+ s.authors = ["Kerrick Long"]
14
+ s.email = "me@kerricklong.com"
15
+ s.files = ["bin/google"]
16
+ s.files += ["lib/google.rb", "lib/google/utils.rb", "lib/google/reverse-markdown/reverse_markdown.rb"]
17
+ s.files += ["LICENSE.md", "README.md", "google.gemspec"]
18
+ s.homepage = "http://kerrick.github.com/google/"
19
19
  end
@@ -1,66 +1,141 @@
1
- require_relative 'trollop/lib/trollop'
2
- require_relative 'google/utils'
3
- require_relative 'google/search'
4
- require_relative 'google/request'
5
- require_relative 'google/display_serp'
6
- require_relative 'google/input'
7
- require_relative 'google/grab'
8
- require_relative 'google/pipe-view'
9
-
10
- opts = Trollop::options do
11
- version "google v1.0.8 (c) 2012 Kerrick Long http://kerrick.github.com/google"
12
- banner <<-EOM
13
- The google gem is a simple tool to search Gooogle with via a CLI.
14
- Usage:
15
- google [options] "my search query string here"
16
- where [options] are:
17
- EOM
18
-
19
- opt :page,
20
- "Start by showing the <i>th result page.",
21
- :type => :int,
22
- :default => 1
23
-
24
- opt :size,
25
- "Show <i> results on each SERP. Must be between 1 and 8.",
26
- :type => :int,
27
- :default => 4
28
-
29
- opt :result,
30
- "Skip the SERP and show the <i>th result.",
31
- :type => :int
32
-
33
- opt :lucky,
34
- "I'm feeling lucky! Skip the SERP and show the first result. " +
35
- "(Alias to --result 1)"
36
-
37
- opt :readability,
38
- "Filter the results through readability to get rid of extra content.",
39
- :default => true
40
-
41
- opt :markdown,
42
- "Change the results from raw HTML to markdown.",
43
- :default => true
44
-
45
- opt :version,
46
- "Print the version and exit."
47
-
48
- opt :help,
49
- "Show this information and exit."
50
- end
1
+ require 'google/utils'
2
+ require 'google/reverse-markdown/reverse_markdown'
3
+ require 'trollop'
4
+ require 'uri'
5
+ require 'open-uri'
6
+ require 'json'
7
+ require 'formatador'
8
+ require 'htmlentities'
9
+ require 'ruby-readability'
51
10
 
52
- query = ARGV.join(' ')
53
- raise Trollop::die "no search query specified" if query.empty?
11
+ class Google
12
+ def initialize(query, opts)
13
+ @query = URI.escape(query)
14
+ @opts = opts
15
+ @opts[:size] = 8 if opts[:size] > 7
16
+ @opts[:size] = 1 if opts[:size] <= 1
17
+ end
54
18
 
55
- opts[:result] = 1 if opts[:lucky]
56
- if !opts[:readability] && opts[:markdown]
57
- raise Trollop::die "Must use --no-markdown if you use --no-readability"
58
- end
19
+ def search
20
+ if @opts[:result]
21
+ results = request :q => @query, :rsz => 1, :start => (@opts[:result] - 1)
22
+ view results[:results]['responseData']['results'][0]['url']
23
+ else
24
+ results = request :q => @query, :rsz => @opts[:size], :start => ((@opts[:page] - 1) * @opts[:size])
25
+ display_serp results
26
+ end
27
+ end
28
+
29
+ def request(query_strings)
30
+ @api_url = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0"\
31
+ "&rsz=#{query_strings[:rsz]}&start=#{query_strings[:start]}&q=#{query_strings[:q]}"
32
+ results = JSON.parse(open(@api_url).read)
33
+ if results['responseStatus'].to_i != 200
34
+ Trollop::die Utils::wrap("Google Search API Status #{results['responseStatus']}. Details:\n"\
35
+ "#{results['responseDetails']}\nTry again in a moment")
36
+ end
37
+
38
+ {:results => results, :query_strings => query_strings}
39
+ end
40
+
41
+ def display_serp(info)
42
+ results = info[:results]
43
+ query_strings = info[:query_strings]
44
+ coder = HTMLEntities.new
45
+ current_page = results['responseData']['cursor']['currentPageIndex']+1
46
+ max_result = query_strings[:start] + query_strings[:rsz]
47
+ estimated_results = results['responseData']['cursor']['resultCount']
48
+ result_array = results['responseData']['results']
49
+
50
+ Formatador.display_line "\n#{' ' * (max_result.to_s.length + 2)}[yellow]Powered by Google[/]"
51
+
52
+ result_array.each_with_index do |result, i|
53
+ this_num = (i + query_strings[:start] + 1).to_s
54
+
55
+ serp_title = "\n#{' ' * (max_result.to_s.length - this_num.length)}[bold][blue]#{this_num}. "\
56
+ "[normal]#{result["titleNoFormatting"]}[/]\n"
57
+ serp_url = "#{' ' * max_result.to_s.length}[green]#{result["url"]}[/]\n"
58
+ serp_desc = ' ' * max_result.to_s.length + result["content"].gsub(/<b>/, "[bold]").gsub(/<\/b>/, "[/]").squeeze(" ")
59
+
60
+ Formatador.display_line coder.decode(Utils::wrap(serp_title, :prefix => max_result.to_s.length + 2))
61
+ Formatador.display_line coder.decode(Utils::wrap(serp_url, :prefix => max_result.to_s.length + 2))
62
+ Formatador.display_line coder.decode(Utils::wrap(serp_desc, :prefix => max_result.to_s.length + 2))
63
+ end
64
+
65
+ Formatador.display_line "\n#{' ' * (max_result.to_s.length + 2)}[yellow]Displaying results #{query_strings[:start] + 1}"\
66
+ " through #{max_result} of #{estimated_results} (Page #{current_page})"
67
+
68
+ input info, result_array
69
+ end
70
+
71
+ def input(info, result_array)
72
+ Formatador.display Utils::wrap("\n[yellow]Enter N or P for pagination, E or Q to quit, or a number to see that result.")
73
+ Formatador.display "\n[bold]>[/] "
74
+ choice = STDIN.gets
75
+ if choice.nil? # Likely because the user submitted EOT via ^D
76
+ choice = ' '
77
+ else
78
+ choice.chomp + ' '
79
+ end
80
+
81
+ case
82
+ # Quit
83
+ when choice[0].downcase == 'e' || choice[0].downcase == 'q'
84
+ exit
85
+ # Next Page
86
+ when choice[0].downcase == 'n'
87
+ display_serp request(:q => @query, :rsz => @opts[:size], :start => info[:query_strings][:start] + @opts[:size])
88
+ # Previous Page
89
+ when choice[0].downcase == 'p'
90
+ if info[:query_strings][:start] < 1
91
+ Formatador.display Utils::wrap("[yellow]! Already at page one.")
92
+ input info, result_array
93
+ else
94
+ display_serp request(:q => @query, :rsz => @opts[:size], :start => info[:query_strings][:start] - @opts[:size])
95
+ end
96
+ # Numerical Choice
97
+ when choice[0].match(/\d/)
98
+ /(\d+)(\s*\|(.*))*/.match(choice) do |str|
99
+ num = str[1].to_i - 1 # Remember, we are 1-indexing things for the user
100
+ # Is the result on the current page?
101
+ if info[:query_strings][:start] <= num && info[:query_strings][:start] + @opts[:size] > num
102
+ # Is the user piping the result to something?
103
+ if str[3].nil?
104
+ view result_array[num - info[:query_strings][:start]]['url']
105
+ else
106
+ pipe str[3].strip, result_array[num - info[:query_strings][:start]]['url']
107
+ end
108
+ else
109
+ Formatador.display Utils::wrap("[yellow]! Result not on this page.")
110
+ input info, result_array
111
+ end
112
+ end
113
+ # Catch-all to grab input again
114
+ else
115
+ input info, result_array
116
+ end
117
+ end
118
+
119
+ def grab(url)
120
+ source = open(url).read
121
+ content = @opts[:readability] ? Readability::Document.new(source,
122
+ :tags => %w[div p a pre code h1 h2 h3 h4 h5 h6 blockquote ul ol li],
123
+ :attributes => %w[href],
124
+ :remote_empty_nodes => true).content : source
125
+ output = @opts[:markdown] ? ReverseMarkdown.new.parse_string(content) : content
126
+ output
127
+ end
128
+
129
+ def pipe(command, url)
130
+ text = grab(url)
131
+ IO.popen(command, 'w+') do |process|
132
+ process.write(text)
133
+ process.close_write
134
+ puts process.read
135
+ end
136
+ end
59
137
 
60
- begin
61
- g = Google.new query, opts
62
- g.search
63
- rescue Interrupt
64
- puts "\nInterrupt received. Exiting application."
65
- exit
138
+ def view(url)
139
+ Formatador.display Utils::wrap(grab(url))
140
+ end
66
141
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.8
4
+ version: 1.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-23 00:00:00.000000000 Z
12
+ date: 2012-05-25 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: trollop
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: json
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -82,21 +98,13 @@ executables:
82
98
  extensions: []
83
99
  extra_rdoc_files: []
84
100
  files:
85
- - lib/google.rb
86
101
  - bin/google
102
+ - lib/google.rb
103
+ - lib/google/utils.rb
104
+ - lib/google/reverse-markdown/reverse_markdown.rb
87
105
  - LICENSE.md
88
106
  - README.md
89
107
  - google.gemspec
90
- - lib/google/display_serp.rb
91
- - lib/google/request.rb
92
- - lib/google/pipe-view.rb
93
- - lib/google/search.rb
94
- - lib/google/utils.rb
95
- - lib/google/input.rb
96
- - lib/google/grab.rb
97
- - lib/reverse-markdown/reverse_markdown.rb
98
- - lib/trollop/test/test_trollop.rb
99
- - lib/trollop/lib/trollop.rb
100
108
  homepage: http://kerrick.github.com/google/
101
109
  licenses: []
102
110
  post_install_message:
@@ -1,53 +0,0 @@
1
- require 'formatador'
2
- require 'htmlentities'
3
-
4
- class Google
5
- def display_serp info
6
- results = info[:results]
7
- query_strings = info[:query_strings]
8
- coder = HTMLEntities.new
9
- current_page = results['responseData']['cursor']['currentPageIndex']+1
10
- max_result = query_strings[:start] + query_strings[:rsz]
11
- estimated_results = results['responseData']['cursor']['resultCount']
12
- result_array = results['responseData']['results']
13
-
14
- attribution = "\n"
15
- attribution << ' ' * (max_result.to_s.length + 2)
16
- attribution << "[yellow]Powered by Google[/]"
17
- Formatador.display_line attribution
18
-
19
- result_array.each_with_index do | result, i |
20
- this_num = (i + query_strings[:start] + 1).to_s
21
-
22
- serp_title = "\n#{' ' * (max_result.to_s.length - this_num.length)}"
23
- serp_title << "[bold][blue]#{this_num}. "
24
- serp_title << "[normal]#{result["titleNoFormatting"]}[/]\n"
25
- serp_url = ' ' * max_result.to_s.length
26
- serp_url << "[green]#{result["url"]}[/]\n"
27
- serp_desc = ' ' * max_result.to_s.length
28
- serp_desc << result["content"].gsub(/<b>/, "[bold]")
29
- .gsub(/<\/b>/, "[/]").squeeze(" ")
30
-
31
- Formatador.display_line coder.decode(
32
- Utils::wrap(serp_title, :prefix => max_result.to_s.length + 2)
33
- )
34
- Formatador.display_line coder.decode(
35
- Utils::wrap(serp_url, :prefix => max_result.to_s.length + 2)
36
- )
37
- Formatador.display_line coder.decode(
38
- Utils::wrap(serp_desc, :prefix => max_result.to_s.length + 2)
39
- )
40
- end
41
-
42
- metadata = ''
43
- metadata << "\n#{' ' * (max_result.to_s.length + 2)}"
44
- metadata << "[yellow]Displaying results "
45
- metadata << "#{query_strings[:start] + 1} through "
46
- metadata << "#{max_result} of "
47
- metadata << "#{estimated_results} "
48
- metadata << "(Page #{current_page})"
49
- Formatador.display_line metadata
50
-
51
- input info, result_array
52
- end
53
- end
@@ -1,26 +0,0 @@
1
- require 'open-uri'
2
- require 'ruby-readability'
3
- require_relative '../reverse-markdown/reverse_markdown'
4
-
5
- class Google
6
- def grab url
7
- source = open(url).read
8
-
9
- if @opts[:readability]
10
- content = Readability::Document.new(source,
11
- :tags => %w[div p a pre code h1 h2 h3 h4 h5 h6 blockquote ul ol li],
12
- :attributes => %w[href],
13
- :remote_empty_nodes => true).content
14
- else
15
- content = source
16
- end
17
-
18
- if @opts[:markdown]
19
- output = ReverseMarkdown.new.parse_string(content)
20
- else
21
- output = content
22
- end
23
-
24
- output
25
- end
26
- end
@@ -1,57 +0,0 @@
1
- require 'formatador'
2
-
3
- class Google
4
- def input info, result_array
5
- prompt = "\n[yellow]"
6
- prompt << "Enter N or P for Next or Previous page, E or Q to quit, "
7
- prompt << "or a number to see that result."
8
-
9
- Formatador.display Utils::wrap(prompt)
10
-
11
- Formatador.display "\n[bold]>[/] "
12
- choice = STDIN.gets
13
- if choice.nil?
14
- choice = ' '
15
- else
16
- choice.chomp + ' '
17
- end
18
-
19
- case
20
- when choice[0].downcase == 'e' || choice[0].downcase == 'q'
21
- exit
22
- when choice[0].downcase == 'n'
23
- results = request :q => @query,
24
- :rsz => @opts[:size],
25
- :start => info[:query_strings][:start] + @opts[:size]
26
- display_serp results
27
- when choice[0].downcase == 'p'
28
- if info[:query_strings][:start] < 1
29
- Formatador.display Utils::wrap("[yellow]! Already at page one.")
30
- input info
31
- else
32
- results = request :q => @query,
33
- :rsz => @opts[:size],
34
- :start => info[:query_strings][:start] - @opts[:size]
35
- display_serp results
36
- end
37
- when choice[0].match(/\d/)
38
- /(\d+)(\s*\|(.*))*/.match(choice) do | str |
39
- num = str[1].to_i - 1
40
- if info[:query_strings][:start] <= num &&
41
- info[:query_strings][:start] + @opts[:size] > num
42
- if str[3].nil?
43
- view result_array[num - info[:query_strings][:start]]['url']
44
- else
45
- pipe str[3].strip,
46
- result_array[num - info[:query_strings][:start]]['url']
47
- end
48
- else
49
- Formatador.display Utils::wrap("[yellow]! Result not on this page.")
50
- input info, result_array
51
- end
52
- end
53
- else
54
- input info, result_array
55
- end
56
- end
57
- end