google 1.0.8 → 1.0.9

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/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