├── History.rdoc
├── Manifest
├── README.rdoc
├── Rakefile
├── examples
├── image.rb
├── images.html
└── web.rb
├── google-search.gemspec
├── lib
├── google-search.rb
└── google-search
│ ├── item.rb
│ ├── item
│ ├── base.rb
│ ├── blog.rb
│ ├── book.rb
│ ├── image.rb
│ ├── local.rb
│ ├── news.rb
│ ├── patent.rb
│ ├── video.rb
│ └── web.rb
│ ├── response.rb
│ ├── search.rb
│ ├── search
│ ├── base.rb
│ ├── blog.rb
│ ├── book.rb
│ ├── image.rb
│ ├── local.rb
│ ├── mixins.rb
│ ├── mixins
│ │ ├── filter.rb
│ │ ├── order_by.rb
│ │ └── safety_level.rb
│ ├── news.rb
│ ├── patent.rb
│ ├── video.rb
│ └── web.rb
│ └── version.rb
├── spec
├── fixtures
│ ├── 400-response.json
│ ├── blog-response.json
│ ├── book-response.json
│ ├── image-response.json
│ ├── invalid-response.json
│ ├── local-response.json
│ ├── news-response.json
│ ├── patent-response.json
│ ├── video-response.json
│ ├── web-2-response.json
│ └── web-response.json
├── item_blog_spec.rb
├── item_book_spec.rb
├── item_image_spec.rb
├── item_local_spec.rb
├── item_news_spec.rb
├── item_patent_spec.rb
├── item_spec.rb
├── item_video_spec.rb
├── item_web_spec.rb
├── response_spec.rb
├── search_blog_spec.rb
├── search_book_spec.rb
├── search_image_spec.rb
├── search_local_spec.rb
├── search_news_spec.rb
├── search_patent_spec.rb
├── search_spec.rb
├── search_video_spec.rb
├── search_web_spec.rb
├── spec.opts
└── spec_helper.rb
└── tasks
├── docs.rake
├── gemspec.rake
└── spec.rake
/History.rdoc:
--------------------------------------------------------------------------------
1 |
2 | === 1.0.3 / 2012-08-29
3 |
4 | * Support multibyte keyword
5 |
6 | === 1.0.2 / 2009-07-27
7 |
8 | * Defaulting Item#uri to unescapedUrl
9 |
10 | === 1.0.0 / 2009-07-24
11 |
12 | * Initial release
--------------------------------------------------------------------------------
/Manifest:
--------------------------------------------------------------------------------
1 | examples/image.rb
2 | examples/images.html
3 | examples/web.rb
4 | google-search.gemspec
5 | History.rdoc
6 | lib/google-search/item/base.rb
7 | lib/google-search/item/blog.rb
8 | lib/google-search/item/book.rb
9 | lib/google-search/item/image.rb
10 | lib/google-search/item/local.rb
11 | lib/google-search/item/news.rb
12 | lib/google-search/item/patent.rb
13 | lib/google-search/item/video.rb
14 | lib/google-search/item/web.rb
15 | lib/google-search/item.rb
16 | lib/google-search/response.rb
17 | lib/google-search/search/base.rb
18 | lib/google-search/search/blog.rb
19 | lib/google-search/search/book.rb
20 | lib/google-search/search/image.rb
21 | lib/google-search/search/local.rb
22 | lib/google-search/search/mixins/filter.rb
23 | lib/google-search/search/mixins/order_by.rb
24 | lib/google-search/search/mixins/safety_level.rb
25 | lib/google-search/search/mixins.rb
26 | lib/google-search/search/news.rb
27 | lib/google-search/search/patent.rb
28 | lib/google-search/search/video.rb
29 | lib/google-search/search/web.rb
30 | lib/google-search/search.rb
31 | lib/google-search/version.rb
32 | lib/google-search.rb
33 | Manifest
34 | Rakefile
35 | README.rdoc
36 | spec/fixtures/400-response.json
37 | spec/fixtures/blog-response.json
38 | spec/fixtures/book-response.json
39 | spec/fixtures/image-response.json
40 | spec/fixtures/invalid-response.json
41 | spec/fixtures/local-response.json
42 | spec/fixtures/news-response.json
43 | spec/fixtures/patent-response.json
44 | spec/fixtures/video-response.json
45 | spec/fixtures/web-2-response.json
46 | spec/fixtures/web-response.json
47 | spec/item_blog_spec.rb
48 | spec/item_book_spec.rb
49 | spec/item_image_spec.rb
50 | spec/item_local_spec.rb
51 | spec/item_news_spec.rb
52 | spec/item_patent_spec.rb
53 | spec/item_spec.rb
54 | spec/item_video_spec.rb
55 | spec/item_web_spec.rb
56 | spec/response_spec.rb
57 | spec/search_blog_spec.rb
58 | spec/search_book_spec.rb
59 | spec/search_image_spec.rb
60 | spec/search_local_spec.rb
61 | spec/search_news_spec.rb
62 | spec/search_patent_spec.rb
63 | spec/search_spec.rb
64 | spec/search_video_spec.rb
65 | spec/search_web_spec.rb
66 | spec/spec.opts
67 | spec/spec_helper.rb
68 | tasks/docs.rake
69 | tasks/gemspec.rake
70 | tasks/spec.rake
71 |
--------------------------------------------------------------------------------
/README.rdoc:
--------------------------------------------------------------------------------
1 |
2 | = Google deprecated their API, this package no longer works
3 |
4 | = Google Search
5 |
6 | Fast, feature rich Google Search client. Search web results, images,
7 | books, local, patents, blogs and news using an elegant Ruby API with
8 | only a single dependency.
9 |
10 |
11 | == Dependencies
12 |
13 | * json gem
14 |
15 | == Features
16 |
17 | * Fast
18 | * Lazy Enumeration (requests more results from google, not all at once)
19 | * Populates Google::Search::Item's blog, book, image, local, news, patent, video, and web
20 | * Clean, well documented source code
21 | * Full test coverage
22 |
23 | == Classes
24 |
25 | - Google::Search | superclass of all other search classes. Is Enumerable
26 | - Google::Search::Web | web search.
27 | - Google::Search::Blog | blog search.
28 | - Google::Search::Book | book search.
29 | - Google::Search::Image | image search.
30 | - Google::Search::Local | local search.
31 | - Google::Search::News | news search.
32 | - Google::Search::Patent | patent search.
33 | - Google::Search::Video | video search.
34 | - Google::Search::Response | single request response, containing items. Is Enumerable
35 | - Google::Search::Item | single item, superclass of all other items.
36 | - Google::Search::Item::Web | single item containing web specific data.
37 | - Google::Search::Item::Blog | single item containing blog specific data.
38 | - Google::Search::Item::Book | single item containing book specific data.
39 | - Google::Search::Item::Image | single item containing image specific data.
40 | - Google::Search::Item::Local | single item containing local specific data.
41 | - Google::Search::Item::News | single item containing news specific data.
42 | - Google::Search::Item::Patent | single item containing patent specific data.
43 | - Google::Search::Item::Video | single item containing video specific data.
44 |
45 | == Arbitrary Query String Support
46 |
47 | Arbitrary key / value pairs may be passed to Google::Search.new, all options
48 | passed that are not assigned (deleted) will pass on to be part of the query string.
49 |
50 | For argument reference visit: http://code.google.com/apis/ajaxsearch/documentation/reference.html#_fonje_web
51 |
52 | == Items
53 |
54 | Each item type (web, image, etc) is a subclass of Google::Search::Item,
55 | whose constant is Google::Search::Item::{Web, Image, Blog, etc}. Every aspect
56 | of google-search is well documented, so poke around to learn more or view
57 | spec/item_spec.rb for item attributes.
58 |
59 | == Image example
60 |
61 | Below we simply create a new :image search, and pass a :query string.
62 | Query strings are urlencoded when Search#get_uri is called, so there
63 | is no reason to do so manually.
64 |
65 | File.open('path/to/images.html', 'w+') do |file|
66 | Google::Search::Image.new(:query => 'Cookies').each do |image|
67 | file.write %(
)
68 | end
69 | end
70 |
71 | == More Information
72 |
73 | * View the source :)
74 |
75 | == License:
76 |
77 | (The MIT License)
78 |
79 | Copyright (c) 2009 TJ Holowaychuk
80 |
81 | Permission is hereby granted, free of charge, to any person obtaining
82 | a copy of this software and associated documentation files (the
83 | 'Software'), to deal in the Software without restriction, including
84 | without limitation the rights to use, copy, modify, merge, publish,
85 | distribute, sublicense, an d/or sell copies of the Software, and to
86 | permit persons to whom the Software is furnished to do so, subject to
87 | the following conditions:
88 |
89 | The above copyright notice and this permission notice shall be
90 | included in all copies or substantial portions of the Software.
91 |
92 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
93 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
94 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
98 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
99 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 |
2 | $:.unshift 'lib'
3 | require 'google-search'
4 | require 'rubygems'
5 | require 'rake'
6 | require 'echoe'
7 |
8 | Echoe.new "google-search", Google::Search::VERSION do |p|
9 | p.author = "TJ Holowaychuk"
10 | p.email = "tj@vision-media.ca"
11 | p.summary = "Google Search API"
12 | p.url = "http://github.com/visionmedia/google-search"
13 | p.runtime_dependencies << 'json'
14 | end
15 |
16 | Dir['tasks/**/*.rake'].sort.each { |f| load f }
--------------------------------------------------------------------------------
/examples/image.rb:
--------------------------------------------------------------------------------
1 |
2 | $:.unshift File.dirname(__FILE__) + '/../lib'
3 | require 'rubygems'
4 | require 'google-search'
5 | require 'rext/all'
6 |
7 | HTML = File.dirname(__FILE__) + '/images.html'
8 |
9 | File.open(HTML, 'w+') do |file|
10 | Google::Search::Image.new(:query => 'Cookies', :image_size => :icon).each do |image|
11 | file.write %(
)
12 | end
13 | end
14 |
15 | begin
16 | `open -a Safari #{HTML}`
17 | rescue
18 | puts "Not on OSX? wtf? open #{HTML} in your browser to view the images"
19 | end
20 |
21 |
22 |
--------------------------------------------------------------------------------
/examples/images.html:
--------------------------------------------------------------------------------
1 | 






























































--------------------------------------------------------------------------------
/examples/web.rb:
--------------------------------------------------------------------------------
1 |
2 | $:.unshift File.dirname(__FILE__) + '/../lib'
3 | require 'rubygems'
4 | require 'google-search'
5 |
6 | def find_item uri, query
7 | search = Google::Search::Web.new do |search|
8 | search.query = query
9 | search.size = :large
10 | search.each_response { print '.'; $stdout.flush }
11 | end
12 | search.find { |item| item.uri =~ uri }
13 | end
14 |
15 | def rank_for query
16 | print "%35s " % query
17 | if item = find_item(/vision\-media\.ca/, query)
18 | puts " #%d" % (item.index + 1)
19 | else
20 | puts " Not found"
21 | end
22 | end
23 |
24 | rank_for 'Victoria Web Training'
25 | rank_for 'Victoria Web School'
26 | rank_for 'Victoria Web Design'
27 | rank_for 'Victoria Drupal'
28 | rank_for 'Victoria Drupal Development'
--------------------------------------------------------------------------------
/google-search.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 |
3 | Gem::Specification.new do |s|
4 | s.name = %q{google-search}
5 | s.version = "1.0.3"
6 |
7 | s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8 | s.authors = ["TJ Holowaychuk"]
9 | s.date = %q{2012-08-29}
10 | s.description = %q{Google Search API}
11 | s.email = %q{tj@vision-media.ca}
12 | s.extra_rdoc_files = ["lib/google-search/item/base.rb", "lib/google-search/item/blog.rb", "lib/google-search/item/book.rb", "lib/google-search/item/image.rb", "lib/google-search/item/local.rb", "lib/google-search/item/news.rb", "lib/google-search/item/patent.rb", "lib/google-search/item/video.rb", "lib/google-search/item/web.rb", "lib/google-search/item.rb", "lib/google-search/response.rb", "lib/google-search/search/base.rb", "lib/google-search/search/blog.rb", "lib/google-search/search/book.rb", "lib/google-search/search/image.rb", "lib/google-search/search/local.rb", "lib/google-search/search/mixins/filter.rb", "lib/google-search/search/mixins/order_by.rb", "lib/google-search/search/mixins/safety_level.rb", "lib/google-search/search/mixins.rb", "lib/google-search/search/news.rb", "lib/google-search/search/patent.rb", "lib/google-search/search/video.rb", "lib/google-search/search/web.rb", "lib/google-search/search.rb", "lib/google-search/version.rb", "lib/google-search.rb", "README.rdoc", "tasks/docs.rake", "tasks/gemspec.rake", "tasks/spec.rake"]
13 | s.files = ["examples/image.rb", "examples/images.html", "examples/web.rb", "google-search.gemspec", "History.rdoc", "lib/google-search/item/base.rb", "lib/google-search/item/blog.rb", "lib/google-search/item/book.rb", "lib/google-search/item/image.rb", "lib/google-search/item/local.rb", "lib/google-search/item/news.rb", "lib/google-search/item/patent.rb", "lib/google-search/item/video.rb", "lib/google-search/item/web.rb", "lib/google-search/item.rb", "lib/google-search/response.rb", "lib/google-search/search/base.rb", "lib/google-search/search/blog.rb", "lib/google-search/search/book.rb", "lib/google-search/search/image.rb", "lib/google-search/search/local.rb", "lib/google-search/search/mixins/filter.rb", "lib/google-search/search/mixins/order_by.rb", "lib/google-search/search/mixins/safety_level.rb", "lib/google-search/search/mixins.rb", "lib/google-search/search/news.rb", "lib/google-search/search/patent.rb", "lib/google-search/search/video.rb", "lib/google-search/search/web.rb", "lib/google-search/search.rb", "lib/google-search/version.rb", "lib/google-search.rb", "Manifest", "Rakefile", "README.rdoc", "spec/fixtures/400-response.json", "spec/fixtures/blog-response.json", "spec/fixtures/book-response.json", "spec/fixtures/image-response.json", "spec/fixtures/invalid-response.json", "spec/fixtures/local-response.json", "spec/fixtures/news-response.json", "spec/fixtures/patent-response.json", "spec/fixtures/video-response.json", "spec/fixtures/web-2-response.json", "spec/fixtures/web-response.json", "spec/item_blog_spec.rb", "spec/item_book_spec.rb", "spec/item_image_spec.rb", "spec/item_local_spec.rb", "spec/item_news_spec.rb", "spec/item_patent_spec.rb", "spec/item_spec.rb", "spec/item_video_spec.rb", "spec/item_web_spec.rb", "spec/response_spec.rb", "spec/search_blog_spec.rb", "spec/search_book_spec.rb", "spec/search_image_spec.rb", "spec/search_local_spec.rb", "spec/search_news_spec.rb", "spec/search_patent_spec.rb", "spec/search_spec.rb", "spec/search_video_spec.rb", "spec/search_web_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/docs.rake", "tasks/gemspec.rake", "tasks/spec.rake"]
14 | s.homepage = %q{http://github.com/visionmedia/google-search}
15 | s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Google-search", "--main", "README.rdoc"]
16 | s.require_paths = ["lib"]
17 | s.rubyforge_project = %q{google-search}
18 | s.rubygems_version = %q{1.3.5}
19 | s.summary = %q{Google Search API}
20 |
21 | if s.respond_to? :specification_version then
22 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23 | s.specification_version = 3
24 |
25 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26 | s.add_runtime_dependency(%q, [">= 0"])
27 | else
28 | s.add_dependency(%q, [">= 0"])
29 | end
30 | else
31 | s.add_dependency(%q, [">= 0"])
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/lib/google-search.rb:
--------------------------------------------------------------------------------
1 | #--
2 | # Copyright (c) 2009 2009 TJ Holowaychuk
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining
5 | # a copy of this software and associated documentation files (the
6 | # "Software"), to deal in the Software without restriction, including
7 | # without limitation the rights to use, copy, modify, merge, publish,
8 | # distribute, sublicense, and/or sell copies of the Software, and to
9 | # permit persons to whom the Software is furnished to do so, subject to
10 | # the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be
13 | # included in all copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | #++
23 |
24 | require 'json'
25 | require 'open-uri'
26 | require 'google-search/version'
27 | require 'google-search/item'
28 | require 'google-search/response'
29 | require 'google-search/search'
--------------------------------------------------------------------------------
/lib/google-search/item.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'google-search/item/base'
3 | require 'google-search/item/web'
4 | require 'google-search/item/blog'
5 | require 'google-search/item/book'
6 | require 'google-search/item/image'
7 | require 'google-search/item/local'
8 | require 'google-search/item/news'
9 | require 'google-search/item/video'
10 | require 'google-search/item/patent'
11 |
--------------------------------------------------------------------------------
/lib/google-search/item/base.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 |
6 | ##
7 | # Index.
8 |
9 | attr_reader :index
10 |
11 | ##
12 | # Unformatted page title.
13 |
14 | attr_reader :title
15 |
16 | ##
17 | # Absolute uri.
18 |
19 | attr_reader :uri
20 |
21 | ##
22 | # Visible uri.
23 |
24 | attr_reader :visible_uri
25 |
26 | ##
27 | # Thumbnail uri.
28 |
29 | attr_reader :thumbnail_uri
30 |
31 | ##
32 | # Thumbnail width in pixels.
33 |
34 | attr_reader :thumbnail_width
35 |
36 | ##
37 | # Thumbnail height in pixels.
38 |
39 | attr_reader :thumbnail_height
40 |
41 | ##
42 | # Contents.
43 |
44 | attr_reader :content
45 |
46 | ##
47 | # Initialize with _hash_.
48 |
49 | def initialize hash
50 | @index = hash['index']
51 | @title = hash['titleNoFormatting'] || hash['title']
52 | @uri = hash['unescapedUrl'] || hash['url'] || hash['postUrl']
53 | @content = hash['contentNoFormatting'] || hash['content']
54 | @thumbnail_uri = hash['tbUrl']
55 | @thumbnail_width = hash['tbWidth'].to_i
56 | @thumbnail_height = hash['tbHeight'].to_i
57 | @visible_uri = hash['visibleUrl']
58 | end
59 |
60 | ##
61 | # Return class for _google_class_ string formatted
62 | # as 'GwebSearch', 'GbookSearch', etc.
63 |
64 | def self.class_for google_class
65 | case google_class
66 | when 'GwebSearch' ; Web
67 | when 'GlocalSearch' ; Local
68 | when 'GbookSearch' ; Book
69 | when 'GimageSearch' ; Image
70 | when 'GvideoSearch' ; Video
71 | when 'GpatentSearch' ; Patent
72 | when 'GnewsSearch' ; News
73 | when 'GblogSearch' ; Blog
74 | end
75 | end
76 | end
77 | end
78 | end
79 |
--------------------------------------------------------------------------------
/lib/google-search/item/blog.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Blog < self
6 |
7 | ##
8 | # Blog base uri.
9 |
10 | attr_reader :blog_uri
11 |
12 | ##
13 | # Author name.
14 |
15 | attr_reader :author
16 |
17 | ##
18 | # Published DateTime.
19 |
20 | attr_reader :published
21 |
22 | ##
23 | # Initialize with _hash_.
24 |
25 | def initialize hash
26 | super
27 | @author = hash['author']
28 | @blog_uri = hash['blogUrl']
29 | @published = DateTime.parse hash['publishedDate']
30 | end
31 | end
32 | end
33 | end
34 | end
--------------------------------------------------------------------------------
/lib/google-search/item/book.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Book < self
6 |
7 | ##
8 | # Book id.
9 |
10 | attr_reader :id
11 |
12 | ##
13 | # Author name(s).
14 |
15 | attr_reader :author
16 |
17 | ##
18 | # Published year.
19 |
20 | attr_reader :published_year
21 |
22 | ##
23 | # Page count.
24 |
25 | attr_reader :pages
26 |
27 | ##
28 | # Initialize with _hash_.
29 |
30 | def initialize hash
31 | super
32 | @author = hash['authors']
33 | @published_year = hash['publishedYear'].to_i
34 | @id = hash['bookId']
35 | @pages = hash['pageCount'].to_i
36 | end
37 | end
38 | end
39 | end
40 | end
--------------------------------------------------------------------------------
/lib/google-search/item/image.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Image < self
6 |
7 | ##
8 | # Image id.
9 |
10 | attr_reader :id
11 |
12 | ##
13 | # Context uri.
14 |
15 | attr_reader :context_uri
16 |
17 | ##
18 | # Image width in pixels.
19 |
20 | attr_reader :width
21 |
22 | ##
23 | # Image height in pixels.
24 |
25 | attr_reader :height
26 |
27 | ##
28 | # Initialize with _hash_.
29 |
30 | def initialize hash
31 | super
32 | @id = hash['imageId']
33 | @context_uri = hash['originalContextUrl']
34 | @width = hash['width'].to_i
35 | @height = hash['height'].to_i
36 | end
37 | end
38 | end
39 | end
40 | end
--------------------------------------------------------------------------------
/lib/google-search/item/local.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Local < self
6 |
7 | ##
8 | # Country.
9 |
10 | attr_reader :country
11 |
12 | ##
13 | # Region.
14 |
15 | attr_reader :region
16 |
17 | ##
18 | # City.
19 |
20 | attr_reader :city
21 |
22 | ##
23 | # Type.
24 |
25 | attr_reader :type
26 |
27 | ##
28 | # Accuracy.
29 |
30 | attr_reader :accuracy
31 |
32 | ##
33 | # Max age in seconds.
34 |
35 | attr_reader :max_age
36 |
37 | ##
38 | # Google maps directions uri.
39 |
40 | attr_reader :directions_uri
41 |
42 | ##
43 | # Google maps directions to here uri.
44 |
45 | attr_reader :directions_to_here_uri
46 |
47 | ##
48 | # Google maps directions from here uri.
49 |
50 | attr_reader :directions_from_here_uri
51 |
52 | ##
53 | # Longitude float.
54 |
55 | attr_reader :long
56 |
57 | ##
58 | # Latitude float.
59 |
60 | attr_reader :lat
61 |
62 | ##
63 | # Viewport mode.
64 |
65 | attr_reader :viewport_mode
66 |
67 | ##
68 | # Phone numbers array.
69 |
70 | attr_reader :phone_numbers
71 |
72 | ##
73 | # Street address.
74 |
75 | attr_reader :street_address
76 |
77 | ##
78 | # Address lines array.
79 |
80 | attr_reader :address_lines
81 |
82 | ##
83 | # Initialize with _hash_.
84 |
85 | def initialize hash
86 | super
87 | @country = hash['country']
88 | @region = hash['region']
89 | @city = hash['city']
90 | @type = hash['listingType']
91 | @accuracy = hash['accuracy'].to_i
92 | @max_age = hash['maxAge']
93 | @directions_uri = hash['ddUrl']
94 | @directions_to_here_uri = hash['ddUrlToHere']
95 | @directions_from_here_uri = hash['ddUrlFromHere']
96 | @thumbnail_uri = hash['staticMapUrl']
97 | @long = hash['lng'].to_f
98 | @lat = hash['lat'].to_f
99 | @viewport_mode = hash['viewportmode']
100 | @phone_numbers = hash['phoneNumbers'].map { |phone| phone['number'] }
101 | @street_address = hash['streetAddress']
102 | @address_lines = hash['addressLines']
103 | end
104 | end
105 | end
106 | end
107 | end
--------------------------------------------------------------------------------
/lib/google-search/item/news.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class News < self
6 |
7 | ##
8 | # Published DateTime.
9 |
10 | attr_reader :published
11 |
12 | ##
13 | # Publisher.
14 |
15 | attr_reader :publisher
16 |
17 | ##
18 | # Location.
19 |
20 | attr_reader :location
21 |
22 | ##
23 | # Language.
24 |
25 | attr_reader :language
26 |
27 | ##
28 | # Redirect uri.
29 |
30 | attr_reader :redirect_uri
31 |
32 | ##
33 | # Initialize with _hash_.
34 |
35 | def initialize hash
36 | super
37 | @location = hash['location']
38 | @published = DateTime.parse hash['publishedDate']
39 | @language = hash['language']
40 | @publisher = hash['publisher']
41 | @redirect_uri = hash['signedRedirectUrl']
42 | end
43 | end
44 | end
45 | end
46 | end
--------------------------------------------------------------------------------
/lib/google-search/item/patent.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Patent < self
6 |
7 | ##
8 | # Patent id.
9 |
10 | attr_reader :id
11 |
12 | ##
13 | # Patent status.
14 |
15 | attr_reader :status
16 |
17 | ##
18 | # Assignee.
19 |
20 | attr_reader :assignee
21 |
22 | ##
23 | # Application DateTime.
24 |
25 | attr_reader :application_date
26 |
27 | ##
28 | # Initialize with _hash_.
29 |
30 | def initialize hash
31 | super
32 | @id = hash['patentNumber'].to_i
33 | @application_date = DateTime.parse hash['applicationDate']
34 | @assignee = hash['assignee']
35 | @status = hash['patentStatus']
36 | end
37 | end
38 | end
39 | end
40 | end
--------------------------------------------------------------------------------
/lib/google-search/item/video.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Video < self
6 |
7 | ##
8 | # Rating float.
9 |
10 | attr_reader :rating
11 |
12 | ##
13 | # Video type.
14 |
15 | attr_reader :type
16 |
17 | ##
18 | # Publisher.
19 |
20 | attr_reader :publisher
21 |
22 | ##
23 | # Published DateTime.
24 |
25 | attr_reader :published
26 |
27 | ##
28 | # Duration in seconds.
29 |
30 | attr_reader :duration
31 |
32 | ##
33 | # Initialize with _hash_.
34 |
35 | def initialize hash
36 | super
37 | @rating = hash['rating'].to_f
38 | @type = hash['videoType']
39 | @publisher = hash['publisher']
40 | @published = DateTime.parse hash['published']
41 | @duration = hash['duration'].to_i
42 | end
43 | end
44 | end
45 | end
46 | end
--------------------------------------------------------------------------------
/lib/google-search/item/web.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Item
5 | class Web < self
6 |
7 | ##
8 | # Cached uri.
9 |
10 | attr_reader :cache_uri
11 |
12 | ##
13 | # Initialize with _hash_.
14 |
15 | def initialize hash
16 | super
17 | @cache_uri = hash['cacheUrl']
18 | end
19 | end
20 | end
21 | end
22 | end
--------------------------------------------------------------------------------
/lib/google-search/response.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Response
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include Enumerable
11 |
12 | ##
13 | # Response status code.
14 |
15 | attr_reader :status
16 |
17 | ##
18 | # Response details.
19 |
20 | attr_reader :details
21 |
22 | ##
23 | # Raw JSON string.
24 |
25 | attr_accessor :raw
26 |
27 | ##
28 | # Hash parsed from raw JSON string.
29 |
30 | attr_reader :hash
31 |
32 | ##
33 | # Items populated by the JSON hash.
34 |
35 | attr_reader :items
36 |
37 | ##
38 | # Estimated number of results.
39 |
40 | attr_reader :estimated_count
41 |
42 | ##
43 | # Current page index.
44 |
45 | attr_reader :page
46 |
47 | ##
48 | # Size of response.
49 |
50 | attr_reader :size
51 |
52 | ##
53 | # Initialize with _hash_.
54 |
55 | def initialize hash
56 | @page = 0
57 | @hash = hash
58 | @size = (hash['responseSize'] || :large).to_sym
59 | @items = []
60 | @status = hash['responseStatus']
61 | @details = hash['responseDetails']
62 | if valid?
63 | if hash['responseData'].include? 'cursor'
64 | @estimated_count = hash['responseData']['cursor']['estimatedResultCount'].to_i
65 | @page = hash['responseData']['cursor']['currentPageIndex'].to_i
66 | end
67 | @hash['responseData']['results'].each_with_index do |result, i|
68 | item_class = Google::Search::Item.class_for result['GsearchResultClass']
69 | result['index'] = i + Google::Search.size_for(size) * page
70 | items << item_class.new(result)
71 | end
72 | end
73 | end
74 |
75 | ##
76 | # Iterate each item with _block_.
77 |
78 | def each_item &block
79 | items.each { |item| yield item }
80 | end
81 | alias :each :each_item
82 |
83 | ##
84 | # Check if the response is valid.
85 |
86 | def valid?
87 | hash['responseStatus'] == 200
88 | end
89 |
90 | end
91 | end
92 | end
--------------------------------------------------------------------------------
/lib/google-search/search.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'google-search/search/mixins'
3 | require 'google-search/search/base'
4 | require 'google-search/search/web'
5 | require 'google-search/search/blog'
6 | require 'google-search/search/image'
7 | require 'google-search/search/local'
8 | require 'google-search/search/news'
9 | require 'google-search/search/video'
10 | require 'google-search/search/book'
11 | require 'google-search/search/patent'
12 |
--------------------------------------------------------------------------------
/lib/google-search/search/base.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 |
5 | #--
6 | # Mixins
7 | #++
8 |
9 | include Enumerable
10 |
11 | #--
12 | # Constants
13 | #++
14 |
15 | URI = 'https://www.google.com/uds'
16 |
17 | #--
18 | # Exceptions
19 | #++
20 |
21 | class Error < StandardError; end
22 |
23 | ##
24 | # Version. Defaults to 1.0
25 |
26 | attr_accessor :version
27 |
28 | ##
29 | # Search type symbol.
30 |
31 | attr_accessor :type
32 |
33 | ##
34 | # Offset. Defaults to 0
35 |
36 | attr_accessor :offset
37 |
38 | ##
39 | # Language. Defaults to :en
40 |
41 | attr_accessor :language
42 |
43 | ##
44 | # Weither or not a search request has been sent.
45 |
46 | attr_accessor :sent
47 |
48 | ##
49 | # Query. Defaults to nil
50 |
51 | attr_accessor :query
52 |
53 | ##
54 | # API Key. Defaults to :notsupplied
55 |
56 | attr_accessor :api_key
57 |
58 | ##
59 | # Size. Defaults to :large
60 | #
61 | # - :small = 4
62 | # - :large = 8
63 | #
64 |
65 | attr_accessor :size
66 |
67 | ##
68 | # Additional options. All those listed above
69 | # are deleted. The remaining represent query
70 | # string key / value pairs.
71 |
72 | attr_reader :options
73 |
74 | ##
75 | # Initialize search _type_ with _options_. Optionally
76 | # a block may be passed, and the Search instance will
77 | # be yielded to it.
78 |
79 | def initialize options = {}, &block
80 | @type = self.class.to_s.split('::').last.downcase.to_sym
81 | @version = options.delete(:version) || 1.0
82 | @offset = options.delete(:offset) || 0
83 | @size = options.delete(:size) || :large
84 | @language = options.delete(:language) || :en
85 | @query = options.delete(:query)
86 | @api_key = options.delete(:api_key) || :notsupplied
87 | @options = options
88 | raise Error, 'Do not initialize Google::Search; Use a subclass such as Google::Search::Web' if @type == :search
89 | yield self if block
90 | end
91 |
92 | ##
93 | # Set a response _block_ which is called every time
94 | # #get_response is called. Useful for reporting etc.
95 |
96 | def each_response &block
97 | @each_response = block
98 | end
99 |
100 | ##
101 | # Iterate each item with _block_.
102 |
103 | def each_item &block
104 | response = self.next.response
105 | if response.valid?
106 | response.each { |item| yield item }
107 | each_item &block
108 | end
109 | end
110 | alias :each :each_item
111 |
112 | ##
113 | # Return all items.
114 |
115 | def all_items
116 | select { true }
117 | end
118 | alias :all :all_items
119 |
120 | ##
121 | # Return uri.
122 |
123 | def get_uri
124 | URI + "/G#{@type}Search?" +
125 | (get_uri_params + options.to_a).
126 | map { |key, value| "#{key}=#{Search.url_encode(value)}" unless value.nil? }.compact.join('&')
127 | end
128 |
129 | #:nodoc:
130 |
131 | def get_uri_params
132 | validate(:query) { |query| query.respond_to?(:to_str) && !query.to_str.empty? }
133 | validate(:version) { |version| Numeric === version }
134 | [[:start, offset],
135 | [:rsz, size],
136 | [:hl, language],
137 | [:key, api_key],
138 | [:v, version],
139 | [:q, query]]
140 | end
141 |
142 | ##
143 | # Prepare for next request.
144 |
145 | def next
146 | @offset += Search.size_for(size) if sent
147 | self
148 | end
149 |
150 | ##
151 | # Return raw JSON response string.
152 |
153 | def get_raw
154 | @sent = true
155 | open(get_uri).read
156 | end
157 |
158 | ##
159 | # Return hash parsed from the raw JSON response.
160 |
161 | def get_hash
162 | Search.json_decode get_raw
163 | end
164 |
165 | ##
166 | # Return Response object wrapping the JSON
167 | # response hash.
168 |
169 | def get_response
170 | raw = get_raw
171 | hash = Search.json_decode raw
172 | hash['responseSize'] = size
173 | response = Response.new hash
174 | response.raw = raw
175 | @each_response.call response if @each_response
176 | response
177 | end
178 | alias :response :get_response
179 |
180 | ##
181 | # Return int for size _sym_.
182 |
183 | def self.size_for sym
184 | { :small => 4,
185 | :large => 8 }[sym]
186 | end
187 |
188 | #:nodoc:
189 |
190 | def validate meth, &block
191 | value = send meth
192 | raise Error, "invalid #{type} #{meth} #{value.inspect}", caller unless yield value
193 | end
194 |
195 | ##
196 | # Decode JSON _string_.
197 |
198 | def self.json_decode string
199 | JSON.parse string
200 | end
201 |
202 | ##
203 | # Url encode _string_.
204 |
205 | def self.url_encode string
206 | string.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/) {
207 | '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
208 | }.tr(' ', '+')
209 | end
210 |
211 | end
212 | end
213 |
--------------------------------------------------------------------------------
/lib/google-search/search/blog.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Blog < self
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include OrderBy
11 |
12 | end
13 | end
14 | end
--------------------------------------------------------------------------------
/lib/google-search/search/book.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Book < self
5 | # Nothing book specific
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/lib/google-search/search/image.rb:
--------------------------------------------------------------------------------
1 | module Google
2 | class Search
3 | class Image < self
4 |
5 | #--
6 | # Mixins
7 | #++
8 |
9 | include SafetyLevel
10 |
11 | #--
12 | # Constants
13 | #++
14 |
15 | SIZES = :icon, :small, :medium, :large, :xlarge, :xxlarge, :huge
16 | TYPES = :face, :photo, :clipart, :lineart
17 | EXTENSIONS = :jpg, :png, :gif, :bmp
18 |
19 | ##
20 | # Image size:
21 | #
22 | # - :icon
23 | # - :small
24 | # - :medium
25 | # - :large
26 | # - :xlarge
27 | # - :xxlarge
28 | # - :huge
29 | #
30 |
31 | attr_accessor :image_size
32 |
33 | ##
34 | # Image type:
35 | #
36 | # - :face
37 | # - :photo
38 | # - :clipart
39 | # - :lineart
40 | #
41 |
42 | attr_accessor :image_type
43 |
44 | ##
45 | # File type:
46 | #
47 | # - :jpg
48 | # - :gif
49 | # - :png
50 | # - :bmp
51 | #
52 |
53 | attr_accessor :file_type
54 |
55 | ##
56 | # Image color.
57 |
58 | attr_accessor :color
59 |
60 | ##
61 | # Specific uri to fetch images from.
62 |
63 | attr_accessor :uri
64 |
65 | #:nodoc:
66 |
67 | def initialize options = {}, &block
68 | @color = options.delete :color
69 | @image_size = options.delete :image_size
70 | @image_type = options.delete :image_type
71 | @file_type = options.delete :file_type
72 | @uri = options.delete :uri
73 | super
74 | end
75 |
76 | #:nodoc:
77 |
78 | def get_uri_params
79 | validate(:image_size) { |size| size.nil? || size.is_a?(Array) || SIZES.include?(size) }
80 | validate(:image_type) { |type| type.nil? || TYPES.include?(type) }
81 | validate(:file_type) { |ext| ext.nil? || EXTENSIONS.include?(ext) }
82 | super + [
83 | [:safe, safety_level],
84 | [:imgsz, image_size.is_a?(Array) ? image_size.join('|') : image_size],
85 | [:imgcolor, color],
86 | [:imgtype, image_type],
87 | [:as_filetype, file_type],
88 | [:as_sitesearch, uri]
89 | ]
90 | end
91 | end
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/lib/google-search/search/local.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Local < self
5 | # Nothing local specific
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/lib/google-search/search/mixins.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'google-search/search/mixins/order_by'
3 | require 'google-search/search/mixins/safety_level'
4 | require 'google-search/search/mixins/filter'
5 |
--------------------------------------------------------------------------------
/lib/google-search/search/mixins/filter.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | module Filter
5 |
6 | ##
7 | # Weither or not to filter duplicate results.
8 | # Defaults to true.
9 |
10 | attr_accessor :filter
11 |
12 | #:nodoc:
13 |
14 | def initialize options = {}, &block
15 | @filter = options.delete(:filter) || 1
16 | super
17 | end
18 |
19 | #:nodoc:
20 |
21 | def get_uri_params
22 | super + [[:filter, filter ? 1 : 0]]
23 | end
24 | end
25 | end
26 | end
--------------------------------------------------------------------------------
/lib/google-search/search/mixins/order_by.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | module OrderBy
5 |
6 | #--
7 | # Constants
8 | #++
9 |
10 | ORDER_BY = :relevance, :date
11 |
12 | ##
13 | # Order by. Defaults to :relevance
14 | #
15 | # - :relevance
16 | # - :date
17 | #
18 |
19 | attr_accessor :order_by
20 |
21 | #:nodoc:
22 |
23 | def initialize options = {}, &block
24 | @order_by = options.delete :order_by
25 | super
26 | end
27 |
28 | #:nodoc:
29 |
30 | def get_uri_params
31 | validate(:order_by) { |order| order.nil? || ORDER_BY.include?(order) }
32 | super + [[:scoring, order_by ? 'd' : nil]]
33 | end
34 | end
35 | end
36 | end
--------------------------------------------------------------------------------
/lib/google-search/search/mixins/safety_level.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | module SafetyLevel
5 |
6 | #--
7 | # Constants
8 | #++
9 |
10 | SAFETY_LEVELS = :active, :moderate, :off
11 |
12 | ##
13 | # Safety level:
14 | #
15 | # - :active | :high
16 | # - :moderate | :medium
17 | # - :off
18 | #
19 |
20 | attr_accessor :safety_level
21 |
22 | #:nodoc:
23 |
24 | def initialize options = {}, &block
25 | @safety_level = options.delete :safety_level
26 | super
27 | end
28 |
29 | #:nodoc:
30 |
31 | def get_uri_params
32 | @safety_level = :off if @safety_level == :none
33 | @safety_level = :moderate if @safety_level == :medium
34 | @safety_level = :active if @safety_level == :high
35 | validate(:safety_level) { |level| level.nil? || SAFETY_LEVELS.include?(level) }
36 | super + [[:safe, safety_level]]
37 | end
38 | end
39 | end
40 | end
--------------------------------------------------------------------------------
/lib/google-search/search/news.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class News < self
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include OrderBy
11 |
12 | #--
13 | # Constants
14 | #++
15 |
16 | TOPICS = :headlines, :world, :business, :nation, :science,
17 | :elections, :politics, :entertainment, :sports, :health
18 |
19 | ##
20 | # Relative to city, state, province, zipcode, etc.
21 |
22 | attr_accessor :relative_to
23 |
24 | ##
25 | # Topic:
26 | #
27 | # - :headlines
28 | # - :world
29 | # - :business
30 | # - :nation
31 | # - :science
32 | # - :elections
33 | # - :politics
34 | # - :entertainment
35 | # - :sports
36 | # - :health
37 | #
38 |
39 | attr_accessor :topic
40 |
41 | ##
42 | # Edition, such as :us, :uk, :fr_ca, etc.
43 |
44 | attr_accessor :edition
45 |
46 | #:nodoc:
47 |
48 | def initialize options = {}, &block
49 | @relative_to = options.delete :relative_to
50 | @edition = options.delete :edition
51 | super
52 | end
53 |
54 | #:nodoc:
55 |
56 | def get_uri_params
57 | validate(:topic) { |topic| topic.nil? || TOPICS.include?(topic) }
58 | super + [
59 | [:geo, relative_to],
60 | [:topic, topic],
61 | [:ned, edition]
62 | ]
63 | end
64 | end
65 | end
66 | end
--------------------------------------------------------------------------------
/lib/google-search/search/patent.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Patent < self
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include OrderBy
11 |
12 | ##
13 | # When nil all parents are returned.
14 | # When true only issued will be returned,
15 | # otherwise when false only filed but NOT
16 | # issued patents will be returned.
17 |
18 | attr_accessor :issued_only
19 |
20 | #:nodoc:
21 |
22 | def initialize options = {}, &block
23 | @issued_only = options.delete :issued_only
24 | super
25 | end
26 |
27 | #:nodoc:
28 |
29 | def get_uri_params
30 | super + [
31 | [:as_psrg, issued_only ? 1 : nil],
32 | [:as_psra, issued_only === false ? 1 : nil]
33 | ]
34 | end
35 | end
36 | end
37 | end
--------------------------------------------------------------------------------
/lib/google-search/search/video.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Video < self
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include OrderBy
11 | include Filter
12 |
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/lib/google-search/search/web.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | class Web < self
5 |
6 | #--
7 | # Mixins
8 | #++
9 |
10 | include Filter
11 | include SafetyLevel
12 |
13 | end
14 | end
15 | end
--------------------------------------------------------------------------------
/lib/google-search/version.rb:
--------------------------------------------------------------------------------
1 |
2 | module Google
3 | class Search
4 | VERSION = '1.0.2'
5 | end
6 | end
--------------------------------------------------------------------------------
/spec/fixtures/400-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[],"cursor":{"moreResultsUrl":"http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q"}}, "responseDetails": "invalid start range", "responseStatus": 400}
--------------------------------------------------------------------------------
/spec/fixtures/blog-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GblogSearch","title":"\u003cb\u003eFoo\u003c/b\u003e (51), Amsterdam (4-12) shine for Guyana on opening day \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"Foo (51), Amsterdam (4-12) shine for Guyana on opening day ...","postUrl":"http://www.kaieteurnewsonline.com/2009/07/22/foo-51-amsterdam-4-12-shine-for-guyana-on-opening-day/","content":"Jonathon \u003cb\u003eFoo\u003c/b\u003e hit a confident 51 and Alex Amsterdam took 4 last session wickets to keep Guyana in the hunt for first innings points against defending champions Barbados at the Jamalco ground yesterday in their 4 ...","author":"KNews","blogUrl":"http://www.kaieteurnewsonline.com/","publishedDate":"Wed, 22 Jul 2009 02:16:11 -0700"},{"GsearchResultClass":"GblogSearch","title":"Web News Site » Blog Archive » AS220 Annual \u003cb\u003eFoo\u003c/b\u003e Fest","titleNoFormatting":"Web News Site » Blog Archive » AS220 Annual Foo Fest","postUrl":"http://webnewssite.com/2009/07/22/as220-annual-foo-fest/","content":"AS220 is holding their annual \u003cb\u003eFoo\u003c/b\u003e Fest in Providence, Rhode Island. It looks like a really interesting event, especially for kids. Check out the link for the complete schedule of artists, musicians, and other activities. ...","author":"Marc de Vinck","blogUrl":"http://webnewssite.com/","publishedDate":"Wed, 22 Jul 2009 03:00:00 -0700"},{"GsearchResultClass":"GblogSearch","title":"Dnx Rockabilly Zone: \u003cb\u003eFoo\u003c/b\u003e Fighters","titleNoFormatting":"Dnx Rockabilly Zone: Foo Fighters","postUrl":"http://danangfadian.blogspot.com/2009/07/foo-fighters.html","content":"Those tapes would become the foundation of the \u003cb\u003eFoo\u003c/b\u003e Fighters, the band he formed in 1995, after the death of Kurt Cobain. Like Nirvana, the \u003cb\u003eFoo\u003c/b\u003e Fighters melded loud, heavy guitars with pretty melodies and mixed punk sensibilities with a ...","author":"Danang Fadian","blogUrl":"http://danangfadian.blogspot.com/","publishedDate":"Tue, 21 Jul 2009 19:22:00 -0700"},{"GsearchResultClass":"GblogSearch","title":"Fruit Rojak \u0026amp; Tau \u003cb\u003eFoo\u003c/b\u003e Fah @ Damansara Jaya | MICHAEL YIP | 叶志坚","titleNoFormatting":"Fruit Rojak \u0026amp; Tau Foo Fah @ Damansara Jaya | MICHAEL YIP | 叶志坚","postUrl":"http://mikeyip.com/fruit-rojak-tau-foo-fah-damansara-jaya/","content":"Located on a vacant parking space just in front of the Atria main entrance (the entrance in front of KFC is actually the side entrance), it's flanked by the Tau \u003cb\u003eFoo\u003c/b\u003e Fah seller that sells piping hot tau \u003cb\u003efoo\u003c/b\u003e fah to anyone who visits the ...","author":"Michael Yip","blogUrl":"http://mikeyip.com/","publishedDate":"Tue, 21 Jul 2009 21:14:27 -0700"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"2231827","currentPageIndex":0,"moreResultsUrl":"http://blogsearch.google.com/blogsearch?oe\u003dutf8\u0026ie\u003dutf8\u0026safe\u003dactive\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/book-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GbookSearch","unescapedUrl":"http://books.google.com/books?id\u003dvUoCAgAACAAJ\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://books.google.com/books%3Fid%3DvUoCAgAACAAJ%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters","titleNoFormatting":"Foo Fighters","authors":"\u003cb\u003eFoo\u003c/b\u003e Fighters (CRT), Hal Leonard Publishing Corporation","bookId":"ISBN1423404580","publishedYear":"2006","tbUrl":"http://bks6.books.google.com/books?id\u003dvUoCAgAACAAJ\u0026printsec\u003dfrontcover\u0026img\u003d1\u0026zoom\u003d5\u0026sig\u003dACfU3U1NHHhXuERH30Xfn0GC3A0BW5nMPg","tbHeight":"80","tbWidth":"60","pageCount":"69"},{"GsearchResultClass":"GbookSearch","unescapedUrl":"http://books.google.com/books?id\u003dYY_JyNscCYAC\u0026printsec\u003dfrontcover\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://books.google.com/books%3Fid%3DYY_JyNscCYAC%26printsec%3Dfrontcover%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"Advanced topics in artificial intelligence: 12th Australian Joint Conference on Artificial Intelligence, AI'99, Sydney, Australia, December 6-10, 1999 : proceedings","titleNoFormatting":"Advanced topics in artificial intelligence: 12th Australian Joint Conference on Artificial Intelligence, AI'99, Sydney, Australia, December 6-10, 1999 : proceedings","authors":"Norman Y. \u003cb\u003eFoo\u003c/b\u003e","bookId":"ISBN3540668225","publishedYear":"1999","tbUrl":"http://bks7.books.google.com/books?id\u003dYY_JyNscCYAC\u0026printsec\u003dfrontcover\u0026img\u003d1\u0026zoom\u003d5\u0026sig\u003dACfU3U3iaZtJ35pPqFz4RUmmDBg2JSwwGA","tbHeight":"80","tbWidth":"60","pageCount":"500"},{"GsearchResultClass":"GbookSearch","unescapedUrl":"http://books.google.com/books?id\u003dj2QrFVEd2GUC\u0026printsec\u003dfrontcover\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://books.google.com/books%3Fid%3Dj2QrFVEd2GUC%26printsec%3Dfrontcover%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"PRICAI '96: topics in artificial intelligence : 4th Pacific Rim International Conference on Artificial Intelligence, Cairns, Australia, August 26-30, 1996 : proceedings","titleNoFormatting":"PRICAI '96: topics in artificial intelligence : 4th Pacific Rim International Conference on Artificial Intelligence, Cairns, Australia, August 26-30, 1996 : proceedings","authors":"Norman Y. \u003cb\u003eFoo\u003c/b\u003e, Randy Goebel","bookId":"ISBN3540615326","publishedYear":"1996","tbUrl":"http://bks8.books.google.com/books?id\u003dj2QrFVEd2GUC\u0026printsec\u003dfrontcover\u0026img\u003d1\u0026zoom\u003d5\u0026sig\u003dACfU3U1-btY8opiKptNpoXupyChBvPeFDA","tbHeight":"80","tbWidth":"60","pageCount":"658"},{"GsearchResultClass":"GbookSearch","unescapedUrl":"http://books.google.com/books?id\u003db6wnl81RguwC\u0026printsec\u003dfrontcover\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://books.google.com/books%3Fid%3Db6wnl81RguwC%26printsec%3Dfrontcover%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"Advanced topics in artificial intelligence: 12th Australian Joint Conference on Artificial Intelligence, AI'99, Sydney, Australia, December 6-10, 1999 : proceedings","titleNoFormatting":"Advanced topics in artificial intelligence: 12th Australian Joint Conference on Artificial Intelligence, AI'99, Sydney, Australia, December 6-10, 1999 : proceedings","authors":"Norman Y. \u003cb\u003eFoo\u003c/b\u003e","bookId":"ISBN3540668225","publishedYear":"1999","tbUrl":"http://bks9.books.google.com/books?id\u003db6wnl81RguwC\u0026printsec\u003dfrontcover\u0026img\u003d1\u0026zoom\u003d5\u0026sig\u003dACfU3U2h-nHauxIQbFENKR-njj5hRpe9lg","tbHeight":"80","tbWidth":"60","pageCount":"500"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"11242","currentPageIndex":0,"moreResultsUrl":"http://books.google.com/books?source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/image-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GimageSearch","width":"883","height":"891","imageId":"IYlLzX-w4vX2AM","tbWidth":"145","tbHeight":"146","unescapedUrl":"http://tomdiaz.files.wordpress.com/2009/06/foo_fighters.jpg","url":"http://tomdiaz.files.wordpress.com/2009/06/foo_fighters.jpg","visibleUrl":"tomdiaz.wordpress.com","title":"\u003cb\u003efoo\u003c/b\u003e_fighters.jpg","titleNoFormatting":"foo_fighters.jpg","originalContextUrl":"http://tomdiaz.wordpress.com/2009/06/","content":"Not FBI Agents--\u003cb\u003eFoo\u003c/b\u003e Fighters","contentNoFormatting":"Not FBI Agents--Foo Fighters","tbUrl":"http://images.google.com/images?q\u003dtbn:IYlLzX-w4vX2AM:tomdiaz.files.wordpress.com/2009/06/foo_fighters.jpg"},{"GsearchResultClass":"GimageSearch","width":"720","height":"580","imageId":"iHzf4CaizHK8TM","tbWidth":"140","tbHeight":"113","unescapedUrl":"http://community.post-gazette.com/cfs-file.ashx/__key/CommunityServer.Components.UserFiles/00.00.00.48.45/FooFighters1A.jpg","url":"http://community.post-gazette.com/cfs-file.ashx/__key/CommunityServer.Components.UserFiles/00.00.00.48.45/FooFighters1A.jpg","visibleUrl":"community.post-gazette.com","title":"\u003cb\u003eFoo\u003c/b\u003eFighters1A.jpg","titleNoFormatting":"FooFighters1A.jpg","originalContextUrl":"http://community.post-gazette.com/blogs/popnoise/archive/2008/10/08/foo-fighters-to-mccain-don-t-use-my-hero.aspx","content":"\u003cb\u003e...\u003c/b\u003e \u003cb\u003eFoo\u003c/b\u003e Fighters publicist contacted \u003cb\u003e...\u003c/b\u003e","contentNoFormatting":"... Foo Fighters publicist contacted ...","tbUrl":"http://images.google.com/images?q\u003dtbn:iHzf4CaizHK8TM:community.post-gazette.com/cfs-file.ashx/__key/CommunityServer.Components.UserFiles/00.00.00.48.45/FooFighters1A.jpg"},{"GsearchResultClass":"GimageSearch","width":"360","height":"302","imageId":"-eufEAEMWQ8_-M","tbWidth":"121","tbHeight":"102","unescapedUrl":"http://www.gotdogsonline.com/chinese-foo-dog-pictures-breeders-puppies-rescue/pictures/chinese-foo-dog-0003.jpg","url":"http://www.gotdogsonline.com/chinese-foo-dog-pictures-breeders-puppies-rescue/pictures/chinese-foo-dog-0003.jpg","visibleUrl":"www.gotdogsonline.com","title":"chinese-\u003cb\u003efoo\u003c/b\u003e-dog-0003.jpg","titleNoFormatting":"chinese-foo-dog-0003.jpg","originalContextUrl":"http://www.gotdogsonline.com/pictures/gallery/chinese-foo-dogs/chinese-foo-dog-0003/","content":"Chinese \u003cb\u003eFoo\u003c/b\u003e Dogs","contentNoFormatting":"Chinese Foo Dogs","tbUrl":"http://images.google.com/images?q\u003dtbn:-eufEAEMWQ8_-M:www.gotdogsonline.com/chinese-foo-dog-pictures-breeders-puppies-rescue/pictures/chinese-foo-dog-0003.jpg"},{"GsearchResultClass":"GimageSearch","width":"300","height":"299","imageId":"ZFPGVM71yQ-k_M","tbWidth":"116","tbHeight":"116","unescapedUrl":"http://www.aeg-tv.com/assets/events/Foo%20Fighter%20Logo%20Small.jpg","url":"http://www.aeg-tv.com/assets/events/Foo%2520Fighter%2520Logo%2520Small.jpg","visibleUrl":"djocean.wordpress.com","title":"\u003cb\u003eFoo\u003c/b\u003e Fighter Logo Small.jpg","titleNoFormatting":"Foo Fighter Logo Small.jpg","originalContextUrl":"http://djocean.wordpress.com/2008/07/28/foo-fighters-to-release-dvd-featuring-led-zeppelin-jam/","content":"\u003cb\u003eFoo\u003c/b\u003e Fighters to Release DVD \u003cb\u003e...\u003c/b\u003e","contentNoFormatting":"Foo Fighters to Release DVD ...","tbUrl":"http://images.google.com/images?q\u003dtbn:ZFPGVM71yQ-k_M:www.aeg-tv.com/assets/events/Foo%2520Fighter%2520Logo%2520Small.jpg"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"5120000","currentPageIndex":0,"moreResultsUrl":"http://www.google.com/images?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/invalid-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[],"cursor":{"moreResultsUrl":"http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/local-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GlocalSearch","viewportmode":"computed","listingType":"local","lat":"37.795279","lng":"-122.407451","accuracy":"8","title":"\u003cb\u003eFoo\u003c/b\u003e Wah Cheung","titleNoFormatting":"Foo Wah Cheung","ddUrl":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451\u0026saddr","ddUrlToHere":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451\u0026iwstate1\u003ddir%3Ato","ddUrlFromHere":"http://www.google.com/maps?source\u003duds\u0026saddr\u003d852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451\u0026iwstate1\u003ddir%3Afrom","streetAddress":"852 Washington St","city":"San Francisco","region":"CA","country":"United States","staticMapUrl":"http://mt.google.com/mapdata?cc\u003dus\u0026tstyp\u003d5\u0026Point\u003db\u0026Point.latitude_e6\u003d37795279\u0026Point.longitude_e6\u003d-122407451\u0026Point.iconid\u003d15\u0026Point\u003de\u0026w\u003d150\u0026h\u003d100\u0026zl\u003d4","url":"http://www.google.com/local?source\u003duds\u0026q\u003dfoo\u0026sll\u003d37.795279%2C-122.407451\u0026latlng\u003d37795279%2C-122407451%2C1909516875098392575\u0026near\u003d37.795279%2C-122.407451","content":"","maxAge":604800,"phoneNumbers":[{"type":"","number":"(415) 391-4067"}],"addressLines":["852 Washington St","San Francisco, CA"]},{"GsearchResultClass":"GlocalSearch","viewportmode":"computed","listingType":"local","lat":"37.794836","lng":"-122.403527","accuracy":"8","title":"Timothy \u003cb\u003eFoo\u003c/b\u003e \u0026amp; Co","titleNoFormatting":"Timothy Foo \u0026 Co","ddUrl":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d601+Montgomery+St%2C+San+Francisco%2C+CA+%28Timothy+Foo+%26+Co%29+%4037.794836%2C-122.403527\u0026saddr","ddUrlToHere":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d601+Montgomery+St%2C+San+Francisco%2C+CA+%28Timothy+Foo+%26+Co%29+%4037.794836%2C-122.403527\u0026iwstate1\u003ddir%3Ato","ddUrlFromHere":"http://www.google.com/maps?source\u003duds\u0026saddr\u003d601+Montgomery+St%2C+San+Francisco%2C+CA+%28Timothy+Foo+%26+Co%29+%4037.794836%2C-122.403527\u0026iwstate1\u003ddir%3Afrom","streetAddress":"601 Montgomery St","city":"San Francisco","region":"CA","country":"United States","staticMapUrl":"http://mt.google.com/mapdata?cc\u003dus\u0026tstyp\u003d5\u0026Point\u003db\u0026Point.latitude_e6\u003d37794836\u0026Point.longitude_e6\u003d-122403527\u0026Point.iconid\u003d15\u0026Point\u003de\u0026w\u003d150\u0026h\u003d100\u0026zl\u003d4","url":"http://www.google.com/local?source\u003duds\u0026q\u003dfoo\u0026sll\u003d37.794836%2C-122.403527\u0026latlng\u003d37794836%2C-122403527%2C6926352342283831233\u0026near\u003d37.794836%2C-122.403527","content":"","maxAge":604800,"phoneNumbers":[{"type":"","number":"(415) 986-5215"}],"addressLines":["601 Montgomery St","San Francisco, CA"]},{"GsearchResultClass":"GlocalSearch","viewportmode":"computed","listingType":"local","lat":"37.90716","lng":"-122.305244","accuracy":"8","title":"Yuet \u003cb\u003eFoo\u003c/b\u003e Seafood Restaurant","titleNoFormatting":"Yuet Foo Seafood Restaurant","ddUrl":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d10350+San+Pablo+Ave%2C+El+Cerrito%2C+CA+%28Yuet+Foo+Seafood+Restaurant%29+%4037.90716%2C-122.305244\u0026saddr","ddUrlToHere":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d10350+San+Pablo+Ave%2C+El+Cerrito%2C+CA+%28Yuet+Foo+Seafood+Restaurant%29+%4037.90716%2C-122.305244\u0026iwstate1\u003ddir%3Ato","ddUrlFromHere":"http://www.google.com/maps?source\u003duds\u0026saddr\u003d10350+San+Pablo+Ave%2C+El+Cerrito%2C+CA+%28Yuet+Foo+Seafood+Restaurant%29+%4037.90716%2C-122.305244\u0026iwstate1\u003ddir%3Afrom","streetAddress":"10350 San Pablo Ave","city":"El Cerrito","region":"CA","country":"United States","staticMapUrl":"http://mt.google.com/mapdata?cc\u003dus\u0026tstyp\u003d5\u0026Point\u003db\u0026Point.latitude_e6\u003d37907160\u0026Point.longitude_e6\u003d-122305244\u0026Point.iconid\u003d15\u0026Point\u003de\u0026w\u003d150\u0026h\u003d100\u0026zl\u003d4","url":"http://www.google.com/local?source\u003duds\u0026q\u003dfoo\u0026sll\u003d37.90716%2C-122.305244\u0026latlng\u003d37907160%2C-122305244%2C4537340541452700142\u0026near\u003d37.90716%2C-122.305244","content":"","maxAge":604800,"phoneNumbers":[{"type":"","number":"(510) 528-6847"}],"addressLines":["10350 San Pablo Ave","El Cerrito, CA"]},{"GsearchResultClass":"GlocalSearch","viewportmode":"computed","listingType":"local","lat":"37.901572","lng":"-122.527484","accuracy":"8","title":"\u003cb\u003eFoo\u003c/b\u003e-\u003cb\u003eFoo\u003c/b\u003e Design","titleNoFormatting":"Foo-Foo Design","ddUrl":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d250+Camino+Alto+%23+250%2C+Mill+Valley%2C+CA+%28Foo-Foo+Design%29+%4037.901572%2C-122.527484\u0026saddr","ddUrlToHere":"http://www.google.com/maps?source\u003duds\u0026daddr\u003d250+Camino+Alto+%23+250%2C+Mill+Valley%2C+CA+%28Foo-Foo+Design%29+%4037.901572%2C-122.527484\u0026iwstate1\u003ddir%3Ato","ddUrlFromHere":"http://www.google.com/maps?source\u003duds\u0026saddr\u003d250+Camino+Alto+%23+250%2C+Mill+Valley%2C+CA+%28Foo-Foo+Design%29+%4037.901572%2C-122.527484\u0026iwstate1\u003ddir%3Afrom","streetAddress":"250 Camino Alto # 250","city":"Mill Valley","region":"CA","country":"United States","staticMapUrl":"http://mt.google.com/mapdata?cc\u003dus\u0026tstyp\u003d5\u0026Point\u003db\u0026Point.latitude_e6\u003d37901572\u0026Point.longitude_e6\u003d-122527484\u0026Point.iconid\u003d15\u0026Point\u003de\u0026w\u003d150\u0026h\u003d100\u0026zl\u003d4","url":"http://www.google.com/local?source\u003duds\u0026q\u003dfoo\u0026sll\u003d37.901572%2C-122.527484\u0026latlng\u003d37901572%2C-122527484%2C5970323968344476572\u0026near\u003d37.901572%2C-122.527484","content":"","maxAge":604800,"phoneNumbers":[{"type":"","number":"(415) 888-8337"}],"addressLines":["250 Camino Alto # 250","Mill Valley, CA"]}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4}],"estimatedResultCount":"574","currentPageIndex":0,"moreResultsUrl":"http://www.google.com/local?oe\u003dutf8\u0026ie\u003dutf8\u0026num\u003d4\u0026mrt\u003dyp%2Cloc\u0026sll\u003d37.779160%2C-122.420090\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"},"viewport":{"center":{"lat":"37.78722","lng":"-122.41377"},"span":{"lat":"0.019343","lng":"0.015167"},"sw":{"lat":"37.77755","lng":"-122.42136"},"ne":{"lat":"37.79689","lng":"-122.40619"}}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/news-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GnewsSearch","clusterUrl":"","content":"After all, it was Susanna \u003cb\u003eFoo\u003c/b\u003e Chinese Cuisine, a major player in Philadelphia\u0026#39;s restaurant renaissance, an innovative dining palace where Chinese-French \u003cb\u003e...\u003c/b\u003e","unescapedUrl":"http://www.montgomerynews.com/articles/2009/07/22/entertainment/doc4a672746b0941650009917.txt","url":"http%3A%2F%2Fwww.montgomerynews.com%2Farticles%2F2009%2F07%2F22%2Fentertainment%2Fdoc4a672746b0941650009917.txt","title":"TICKET TO DINING: Susanna \u003cb\u003eFoo\u003c/b\u003e Gourmet Kitchen — elegant suburban \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"TICKET TO DINING: Susanna Foo Gourmet Kitchen — elegant suburban ...","location":"Fort Washington,PA,USA","publisher":"Montgomery Newspapers","publishedDate":"Wed, 22 Jul 2009 09:02:05 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-0-0\u0026fd\u003dS\u0026url\u003dhttp://www.montgomerynews.com/articles/2009/07/22/entertainment/doc4a672746b0941650009917.txt\u0026cid\u003d0\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNGsuTniL5DY24lNJ8qy204ZWjQoKA","language":"en"},{"GsearchResultClass":"GnewsSearch","clusterUrl":"http://news.google.com/news/story?ncl\u003ddwbAwUnuy6hZgRMiTb6kcoks-EKYM\u0026hl\u003den\u0026ned\u003dus","content":"After holing up in their native Denmark this spring to lay down new material, members Sune Rose Wagner and Sharin \u003cb\u003eFoo\u003c/b\u003e are now reflecting on the final \u003cb\u003e...\u003c/b\u003e","unescapedUrl":"http://www.billboard.com/bbcom/news/the-raveonettes-unveil-album-release-and-1003995751.story","url":"http%3A%2F%2Fwww.billboard.com%2Fbbcom%2Fnews%2Fthe-raveonettes-unveil-album-release-and-1003995751.story","title":"The Raveonettes Unveil Album Release And Tour Dates","titleNoFormatting":"The Raveonettes Unveil Album Release And Tour Dates","location":"New York,NY,USA","publisher":"Billboard","publishedDate":"Tue, 21 Jul 2009 09:29:52 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-0\u0026fd\u003dS\u0026url\u003dhttp://www.billboard.com/bbcom/news/the-raveonettes-unveil-album-release-and-1003995751.story\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNGP0OBMkBW5SOT9Q_ndo2Jfk2iOYQ","language":"en","image":{"url":"http://www.chartattack.com/files/imagecache/180x150_SC/chart_global/news/20050606-raveonettes.jpg","tbUrl":"http://nt0.ggpht.com/news/tbn/hOEaRUeyqeQJ","originalContextUrl":"http://www.chartattack.com/news/72405/the-raveonettes-are-out-of-control","publisher":"ChartAttack","tbWidth":80,"tbHeight":67},"relatedStories":[{"unescapedUrl":"http://consequenceofsound.net/2009/07/22/the-raveonettes-are-in-and-out-of-control-hit-the-road-to-figure-it-out/","url":"http%3A%2F%2Fconsequenceofsound.net%2F2009%2F07%2F22%2Fthe-raveonettes-are-in-and-out-of-control-hit-the-road-to-figure-it-out%2F","title":"The Raveonettes are In and Out of Control, hit the road to figure \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"The Raveonettes are In and Out of Control, hit the road to figure ...","location":"Manassas,VA,USA","publisher":"Consequence of Sound","publishedDate":"Wed, 22 Jul 2009 11:37:22 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-1\u0026fd\u003dS\u0026url\u003dhttp://consequenceofsound.net/2009/07/22/the-raveonettes-are-in-and-out-of-control-hit-the-road-to-figure-it-out/\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNGKYS-UQiltq5-JH8qOBl_ZQ6Cvaw","language":"en"},{"unescapedUrl":"http://www.clashmusic.com/news/raveonettes-album-details","url":"http%3A%2F%2Fwww.clashmusic.com%2Fnews%2Fraveonettes-album-details","title":"Raveonettes Album Details","titleNoFormatting":"Raveonettes Album Details","location":"London,London,UK","publisher":"ClashMusic.com","publishedDate":"Wed, 22 Jul 2009 08:01:50 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-2\u0026fd\u003dS\u0026url\u003dhttp://www.clashmusic.com/news/raveonettes-album-details\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNE0yNOkyeqoWNAw58Z4PwRjO56FhQ","language":"en"},{"unescapedUrl":"http://www.exclaim.ca/articles/generalarticlesynopsfullart.aspx?csid1\u003d134\u0026csid2\u003d844\u0026fid1\u003d40047","url":"http%3A%2F%2Fwww.exclaim.ca%2Farticles%2Fgeneralarticlesynopsfullart.aspx%3Fcsid1%3D134%26csid2%3D844%26fid1%3D40047","title":"Raveonettes Ready “the Ultimate Light Album,” Play Toronto \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"Raveonettes Ready “the Ultimate Light Album,” Play Toronto ...","location":"Toronto,Ontario,Canada","publisher":"Exclaim!","publishedDate":"Wed, 22 Jul 2009 14:01:54 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-3\u0026fd\u003dS\u0026url\u003dhttp://www.exclaim.ca/articles/generalarticlesynopsfullart.aspx%3Fcsid1%3D134%26csid2%3D844%26fid1%3D40047\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNH-tOgy53FR5RD-zmnbqJuPRgDIqQ","language":"en"},{"unescapedUrl":"http://www.spinner.com/2009/07/20/the-raveonettes-will-lighten-up-on-new-album-sort-of/","url":"http%3A%2F%2Fwww.spinner.com%2F2009%2F07%2F20%2Fthe-raveonettes-will-lighten-up-on-new-album-sort-of%2F","title":"The Raveonettes Will Lighten Up on New Album ... Sort Of","titleNoFormatting":"The Raveonettes Will Lighten Up on New Album ... Sort Of","location":"New York,NY,USA","publisher":"Spinner","publishedDate":"Mon, 20 Jul 2009 13:15:48 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-4\u0026fd\u003dS\u0026url\u003dhttp://www.spinner.com/2009/07/20/the-raveonettes-will-lighten-up-on-new-album-sort-of/\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNE8hqFExKou1mwaMJIoQjXFNXQVpw","language":"en"},{"unescapedUrl":"http://music.rightcelebrity.com/?p\u003d2781","url":"http%3A%2F%2Fmusic.rightcelebrity.com%2F%3Fp%3D2781","title":"Raveonettes Tour Dates: Raveonettes Announce New Album","titleNoFormatting":"Raveonettes Tour Dates: Raveonettes Announce New Album","location":"USA","publisher":"Right On Music","publishedDate":"Wed, 22 Jul 2009 10:24:29 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-5\u0026fd\u003dS\u0026url\u003dhttp://music.rightcelebrity.com/%3Fp%3D2781\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNEZCc_Q_Os4fkrfEPjO4_q2EAQRcA","language":"en"},{"unescapedUrl":"http://www.prefixmag.com/news/raveonettes-announce-tour-and-title-and-release-da/31033/","url":"http%3A%2F%2Fwww.prefixmag.com%2Fnews%2Fraveonettes-announce-tour-and-title-and-release-da%2F31033%2F","title":"Raveonettes Announce In \u0026amp; Out of Control, Tour Dates","titleNoFormatting":"Raveonettes Announce In \u0026amp; Out of Control, Tour Dates","location":"Brooklyn,NY,USA","publisher":"Prefixmag","publishedDate":"Tue, 21 Jul 2009 13:37:27 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-1-6\u0026fd\u003dS\u0026url\u003dhttp://www.prefixmag.com/news/raveonettes-announce-tour-and-title-and-release-da/31033/\u0026cid\u003d1281523655\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNFhxoOl0O5tTTyxNOKxoP9iGzXkrQ","language":"en"}]},{"GsearchResultClass":"GnewsSearch","clusterUrl":"http://news.google.com/news/story?ncl\u003dd2XBGfzTDmHIzvMtwfSQCiP0uifIM\u0026hl\u003den\u0026ned\u003dus","content":"\u003cb\u003eFoo\u003c/b\u003e Fighters have been on hiatus since their last tour wrapped, but they\u0026#39;ll play one show this weekend out of civic duty. Rolling Stone reports that the \u003cb\u003e...\u003c/b\u003e","unescapedUrl":"http://newsroom.mtv.com/2009/07/02/foo-fighters-white-house/","url":"http%3A%2F%2Fnewsroom.mtv.com%2F2009%2F07%2F02%2Ffoo-fighters-white-house%2F","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters Should Avoid Playing These Songs At The White House","titleNoFormatting":"Foo Fighters Should Avoid Playing These Songs At The White House","location":"USA","publisher":"MTV.com","publishedDate":"Thu, 02 Jul 2009 12:55:45 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-0\u0026fd\u003dS\u0026url\u003dhttp://newsroom.mtv.com/2009/07/02/foo-fighters-white-house/\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNGN9FGKFakqx9jyfqgWrf3-K5JMYw","language":"en","image":{"url":"http://akamai-static.nme.com/images/article/0925_172010_foofighterspaphotosL50209.jpg","tbUrl":"http://nt3.ggpht.com/news/tbn/92Q2RWIx1j4J","originalContextUrl":"http://www.nme.com/news/foo-fighters/45873","publisher":"NME.com","tbWidth":80,"tbHeight":49},"relatedStories":[{"unescapedUrl":"http://www.rollingstone.com/rockdaily/index.php/2009/07/02/foo-fighters-head-to-dc-to-rock-white-house-fourth-of-july-bash/","url":"http%3A%2F%2Fwww.rollingstone.com%2Frockdaily%2Findex.php%2F2009%2F07%2F02%2Ffoo-fighters-head-to-dc-to-rock-white-house-fourth-of-july-bash%2F","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters Head to DC to Rock White House Fourth of July Bash","titleNoFormatting":"Foo Fighters Head to DC to Rock White House Fourth of July Bash","location":"USA","publisher":"Rolling Stone","publishedDate":"Thu, 02 Jul 2009 05:15:17 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-1\u0026fd\u003dS\u0026url\u003dhttp://www.rollingstone.com/rockdaily/index.php/2009/07/02/foo-fighters-head-to-dc-to-rock-white-house-fourth-of-july-bash/\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNEXWRX1jpi8R9LFOkAfZ_rjdfApjw","language":"en"},{"unescapedUrl":"http://www.nme.com/news/foo-fighters/45873","url":"http%3A%2F%2Fwww.nme.com%2Fnews%2Ffoo-fighters%2F45873","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters debut new song \u0026#39;Wheels\u0026#39; for Barack Obama - video","titleNoFormatting":"Foo Fighters debut new song \u0026#39;Wheels\u0026#39; for Barack Obama - video","location":"UK","publisher":"NME.com","publishedDate":"Mon, 06 Jul 2009 10:40:05 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-2\u0026fd\u003dS\u0026url\u003dhttp://www.nme.com/news/foo-fighters/45873\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNHdxKm3ogufQMZmAnBDVp1QOEyKcg","language":"en"},{"unescapedUrl":"http://www.examiner.com/x-14721-Boston-Music-Examiner~y2009m7d4-Foo-Fighters-to-rock-the-White-House-4th-of-July-Celebration","url":"http%3A%2F%2Fwww.examiner.com%2Fx-14721-Boston-Music-Examiner%7Ey2009m7d4-Foo-Fighters-to-rock-the-White-House-4th-of-July-Celebration","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters to rock the White House 4th of July Celebration","titleNoFormatting":"Foo Fighters to rock the White House 4th of July Celebration","location":"USA","publisher":"Examiner.com","publishedDate":"Sat, 04 Jul 2009 07:03:43 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-3\u0026fd\u003dS\u0026url\u003dhttp://www.examiner.com/x-14721-Boston-Music-Examiner~y2009m7d4-Foo-Fighters-to-rock-the-White-House-4th-of-July-Celebration\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNHWyu9L0ofwoifhR0h6ZntpX3b3hg","language":"en"},{"unescapedUrl":"http://consequenceofsound.net/2009/07/06/watch-foo-fighters-wheels-new-song/","url":"http%3A%2F%2Fconsequenceofsound.net%2F2009%2F07%2F06%2Fwatch-foo-fighters-wheels-new-song%2F","title":"Watch: \u003cb\u003eFoo\u003c/b\u003e Fighters - “Wheels” (New Song)","titleNoFormatting":"Watch: Foo Fighters - “Wheels” (New Song)","location":"Manassas,VA,USA","publisher":"Consequence of Sound","publishedDate":"Mon, 06 Jul 2009 10:04:34 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-4\u0026fd\u003dS\u0026url\u003dhttp://consequenceofsound.net/2009/07/06/watch-foo-fighters-wheels-new-song/\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNEoW_3LrrZh-UgRwWU5tS6HYyGq9A","language":"en"},{"unescapedUrl":"http://www.filter-mag.com/index.php?id\u003d19307\u0026c\u003d1","url":"http%3A%2F%2Fwww.filter-mag.com%2Findex.php%3Fid%3D19307%26c%3D1","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters Debut New Material At The White House","titleNoFormatting":"Foo Fighters Debut New Material At The White House","location":"Los Angeles,CA,USA","publisher":"Filter Magazine","publishedDate":"Mon, 06 Jul 2009 11:10:13 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-5\u0026fd\u003dS\u0026url\u003dhttp://www.filter-mag.com/index.php%3Fid%3D19307%26c%3D1\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNGIb4EFWS7jPneMOMP7aS9yePcxaA","language":"en"},{"unescapedUrl":"http://newsroom.mtv.com/2009/07/06/foo-fighters-white-house-2/","url":"http%3A%2F%2Fnewsroom.mtv.com%2F2009%2F07%2F06%2Ffoo-fighters-white-house-2%2F","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters Debut New Song On White House Lawn","titleNoFormatting":"Foo Fighters Debut New Song On White House Lawn","location":"USA","publisher":"MTV.com","publishedDate":"Mon, 06 Jul 2009 07:42:56 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-2-6\u0026fd\u003dS\u0026url\u003dhttp://newsroom.mtv.com/2009/07/06/foo-fighters-white-house-2/\u0026cid\u003d1271271606\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNFkB54hu4JmcWmjRmo4BcTDCTfAAA","language":"en"}]},{"GsearchResultClass":"GnewsSearch","clusterUrl":"","content":"\u003cb\u003eFoo\u003c/b\u003e Fighters- On a hiatus but just played the White House on the 4th of July \u0026amp; Sunny Day tour with Nate doesn\u0026#39;t start til Sept. \u003cb\u003eFoo\u003c/b\u003e have a Greatest Hits \u003cb\u003e...\u003c/b\u003e","unescapedUrl":"http://www.signonsandiego.com/entertainment/street/2009/07/street_scene_nogo_beastie_boys.html","url":"http%3A%2F%2Fwww.signonsandiego.com%2Fentertainment%2Fstreet%2F2009%2F07%2Fstreet_scene_nogo_beastie_boys.html","title":"NO TOUR : Beastie Boys cancel gigs, including Street Scene","titleNoFormatting":"NO TOUR : Beastie Boys cancel gigs, including Street Scene","location":"San Diego,CA,USA","publisher":"San Diego Union Tribune","publishedDate":"Mon, 20 Jul 2009 10:45:46 -0700","signedRedirectUrl":"http://news.google.com/news/url?sa\u003dT\u0026ct\u003dus/0-3-0\u0026fd\u003dS\u0026url\u003dhttp://www.signonsandiego.com/entertainment/street/2009/07/street_scene_nogo_beastie_boys.html\u0026cid\u003d1281239545\u0026ei\u003d4aFnSpnxK474rQPutNHRAQ\u0026usg\u003dAFQjCNFyvSZc8q6a7VZlFBqDckNtVlVpdQ","language":"en"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"2071","currentPageIndex":0,"moreResultsUrl":"http://news.google.com/nwshp?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026q\u003dfoo\u0026hl\u003den\u0026start\u003d0"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/patent-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GpatentSearch","unescapedUrl":"http://www.google.com/patents/about?id\u003dGDMdAAAAEBAJ\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://www.google.com/patents/about%3Fid%3DGDMdAAAAEBAJ%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"SZE-\u003cb\u003eFOO\u003c/b\u003e CHIEN","titleNoFormatting":"SZE-FOO CHIEN","applicationDate":"Tue, 26 Mar 1968 00:00:00 -0800","patentNumber":"3468158","patentStatus":"issued","content":"\u003cb\u003e...\u003c/b\u003e 3468158 METHOD OF AND APPARATUS FOR DETERMINING RHEOLOGICAL PROPERTIES OF NON-NEWTONIAN FLUIDS SUCH AS DRILLING FLUIDS OR THE LIKE Filed March 26, r .£. \u003cb\u003e...\u003c/b\u003e","assignee":"","tbUrl":"http://bks9.books.google.com/patents?id\u003dGDMdAAAAEBAJ\u0026printsec\u003ddrawing\u0026img\u003d1\u0026zoom\u003d1\u0026sig\u003dACfU3U10b3w-4hMfKTEykPmtqnoObaLhaA"},{"GsearchResultClass":"GpatentSearch","unescapedUrl":"http://www.google.com/patents/about?id\u003d9YMBAAAAEBAJ\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://www.google.com/patents/about%3Fid%3D9YMBAAAAEBAJ%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"Method for dynamically linking definable program elements of an interactive data processing system","titleNoFormatting":"Method for dynamically linking definable program elements of an interactive data processing system","applicationDate":"Thu, 28 May 1992 00:00:00 -0700","patentNumber":"5381547","patentStatus":"issued","content":"\u003cb\u003eFOO\u003c/b\u003e is provided in this exemplary embodiment, to which a link header l.FAULT is chained. \u003cb\u003e...\u003c/b\u003e 35 The input symbol \u0026quot;\u003cb\u003eFOO\u003c/b\u003e\u0026quot; is not yet defined at this tune. \u003cb\u003e...\u003c/b\u003e","assignee":"Siemens Aktiengesellschaft","tbUrl":"http://bks0.books.google.com/patents?id\u003d9YMBAAAAEBAJ\u0026printsec\u003ddrawing\u0026img\u003d1\u0026zoom\u003d1\u0026sig\u003dACfU3U1L7MxCO4Y8TeU4eV3PgABUfcPMLA"},{"GsearchResultClass":"GpatentSearch","unescapedUrl":"http://www.google.com/patents/about?id\u003dchwfAAAAEBAJ\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://www.google.com/patents/about%3Fid%3DchwfAAAAEBAJ%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"Method for analyzing calls of application program by inserting monitoring routines into the executable version and redirecting calls to the monitoring routines","titleNoFormatting":"Method for analyzing calls of application program by inserting monitoring routines into the executable version and redirecting calls to the monitoring routines","applicationDate":"Tue, 18 Sep 1990 00:00:00 -0700","patentNumber":"5313616","patentStatus":"issued","content":"The -u option 40 routines can be tested by running \u003cb\u003efoo\u003c/b\u003e under another test causes the names of unexecuted user and system proce- harness as follows: \u003cb\u003e...\u003c/b\u003e","assignee":"88Open Consortium, Ltd.","tbUrl":"http://bks1.books.google.com/patents?id\u003dchwfAAAAEBAJ\u0026printsec\u003ddrawing\u0026img\u003d1\u0026zoom\u003d1\u0026sig\u003dACfU3U08WiFfgEBRGJy3374yvDbEyPZYdQ"},{"GsearchResultClass":"GpatentSearch","unescapedUrl":"http://www.google.com/patents/about?id\u003dDK4aAAAAEBAJ\u0026dq\u003dfoo\u0026client\u003dinternal-uds\u0026source\u003duds","url":"http://www.google.com/patents/about%3Fid%3DDK4aAAAAEBAJ%26dq%3Dfoo%26client%3Dinternal-uds%26source%3duds","title":"System and methods for optimizing object-oriented compilations","titleNoFormatting":"System and methods for optimizing object-oriented compilations","applicationDate":"Fri, 05 Jun 1992 00:00:00 -0700","patentNumber":"5481708","patentStatus":"issued","content":"\u003cb\u003e...\u003c/b\u003e constant \u003d 8 Cast to \u0026#39;\u003cb\u003efoo\u003c/b\u003e *\u0026#39; Expression at ccp.cpp(ll) \u003cb\u003e...\u003c/b\u003e [338f:0562] O_ID \u0026#39;func(\u003cb\u003efoo\u003c/b\u003e) \u0026#39; Cast to \u0026#39;long\u0026#39; Expression at ccp.cpp{5): \u003cb\u003e...\u003c/b\u003e","assignee":"Borland International, Inc.","tbUrl":"http://bks2.books.google.com/patents?id\u003dDK4aAAAAEBAJ\u0026printsec\u003ddrawing\u0026img\u003d1\u0026zoom\u003d1\u0026sig\u003dACfU3U06zm0mTVrpBKve5JQrUe0AlQuseA"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"1226","currentPageIndex":0,"moreResultsUrl":"http://www.google.com/patents?source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/video-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GvideoSearch","title":"Foo Fighters - The Pretender","titleNoFormatting":"Foo Fighters - The Pretender","published":"Tue, 28 Aug 2007 16:36:23 PDT","content":"Foo Fighters The Pretender\n(C) 2007 Roswell Records, Inc.","publisher":"www.youtube.com","tbUrl":"http://0.gvt0.com/vi/TVboOdX9icA/default.jpg","tbWidth":"320","tbHeight":"240","videoType":"YouTube","url":"http://www.google.com/url?q\u003dhttp://www.youtube.com/watch%3Fv%3DTVboOdX9icA\u0026source\u003dvideo\u0026vgc\u003drss\u0026usg\u003dAFQjCNFvZftyyTO-IswoCPWEmmQbskBMRA","playUrl":"http://www.youtube.com/v/TVboOdX9icA\u0026fs\u003d1\u0026hl\u003den\u0026source\u003duds\u0026autoplay\u003d1","rating":"4.9076071","duration":"269"},{"GsearchResultClass":"GvideoSearch","title":"foo fighters-my hero","titleNoFormatting":"foo fighters-my hero","published":"Sat, 27 Jan 2007 06:18:10 PST","content":"one of foo fighters best songs - My Hero..definately one of my favourite songs.\nwell enjoy :D","publisher":"www.youtube.com","tbUrl":"http://2.gvt0.com/vi/KVKDQgT_b-Y/default.jpg","tbWidth":"320","tbHeight":"240","videoType":"YouTube","url":"http://www.google.com/url?q\u003dhttp://www.youtube.com/watch%3Fv%3DKVKDQgT_b-Y\u0026source\u003dvideo\u0026vgc\u003drss\u0026usg\u003dAFQjCNH9KepO3M5PVNSefDJylTfTGRB8uA","playUrl":"http://www.youtube.com/v/KVKDQgT_b-Y\u0026fs\u003d1\u0026hl\u003den\u0026source\u003duds\u0026autoplay\u003d1","rating":"4.8932624","duration":"247"},{"GsearchResultClass":"GvideoSearch","title":"Foo Fighters: DOA","titleNoFormatting":"Foo Fighters: DOA","published":"Sat, 25 Feb 2006 05:32:29 PST","content":"New Video Of Foo Fighters","publisher":"www.youtube.com","tbUrl":"http://1.gvt0.com/vi/O2_0Rx780Uk/default.jpg","tbWidth":"320","tbHeight":"240","videoType":"YouTube","url":"http://www.google.com/url?q\u003dhttp://www.youtube.com/watch%3Fv%3DO2_0Rx780Uk\u0026source\u003dvideo\u0026vgc\u003drss\u0026usg\u003dAFQjCNE8yH30j_kHOErl8CpozDRNDgEp5w","playUrl":"http://www.youtube.com/v/O2_0Rx780Uk\u0026fs\u003d1\u0026hl\u003den\u0026source\u003duds\u0026autoplay\u003d1","rating":"4.8958893","duration":"269"},{"GsearchResultClass":"GvideoSearch","title":"Foo Fighters Everywhere But Home Tour","titleNoFormatting":"Foo Fighters Everywhere But Home Tour","published":"Sun, 27 Aug 2006 10:46:57 PDT","content":"Foo Fighters Live In Concert\nDave Grohl","publisher":"video.google.com","tbUrl":"http://0.gvt0.com/ThumbnailServer2?app\u003dvss\u0026contentid\u003d6ea5cd582915b590\u0026offsetms\u003d355000\u0026itag\u003dw160\u0026hl\u003den\u0026sigh\u003dqz4THQ9cvyMcp56d6aiQfkG3lLI","tbWidth":"320","tbHeight":"240","videoType":"Google","url":"http://www.google.com/url?q\u003dhttp://video.google.com/videoplay%3Fdocid%3D2671671510864672199\u0026source\u003dvideo\u0026vgc\u003drss\u0026usg\u003dAFQjCNHcl0UGo5jSWXPwzjMgxTMVEfBdHw","playUrl":"http://video.google.com/s/MyL2xl0HXdE/googleplayer.swf?videoUrl\u003dhttp://v1.lscache2.googlevideo.com/videoplayback%3Fid%3D6ea5cd582915b590%26itag%3D5%26begin%3D0%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1248327186%26sparams%3Dip,ipbits,expire,id,itag%26signature%3D1E3D85F02EF1EEB2EF09512BD9441AFAAD979067.0431C0158A8EA1E0523BF2E0F92436398840B178%26key%3Dck1\u0026thumbnailUrl\u003dhttp://0.gvt0.com/ThumbnailServer2%3Fapp%3Dvss%26contentid%3D6ea5cd582915b590%26offsetms%3D355000%26itag%3Dw160%26hl%3Den%26sigh%3Dqz4THQ9cvyMcp56d6aiQfkG3lLI\u0026docid\u003d2671671510864672199\u0026hl\u003den\u0026q\u003dfoo+(site:video.google.com+OR+site:youtube.com)\u0026source\u003duds\u0026playerMode\u003dsimple\u0026autoPlay\u003dtrue","rating":"4.977778","duration":"5568"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"12851","currentPageIndex":0,"moreResultsUrl":"http://video.google.com/videosearch?source\u003duds\u0026type\u003dsearch\u0026q\u003dfoo+%28site%3Avideo.google.com+OR+site%3Ayoutube.com%29\u0026hl\u003den\u0026start\u003d0"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/web-2-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://en.wikipedia.org/wiki/Foobar","url":"http://en.wikipedia.org/wiki/Foobar","visibleUrl":"en.wikipedia.org","cacheUrl":"http://www.google.com/search?q\u003dcache:4styY9qq7tYJ:en.wikipedia.org","title":"foobar - Wikipedia, the free encyclopedia","titleNoFormatting":"foobar - Wikipedia, the free encyclopedia","content":"Foobar is often used alone; \u003cb\u003efoo\u003c/b\u003e, bar, and baz are usually used in that order, \u003cb\u003e...\u003c/b\u003e \u003cb\u003eFoo\u003c/b\u003e has entered the English language as a neologism and is considered by \u003cb\u003e...\u003c/b\u003e"},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://www.foo.com/","url":"http://www.foo.com/","visibleUrl":"www.foo.com","cacheUrl":"http://www.google.com/search?q\u003dcache:aJjqmBB29rgJ:www.foo.com","title":"Get the 411 on Anyone with Free White Pages, People Search and \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"Get the 411 on Anyone with Free White Pages, People Search and ...","content":"Get the free 411, white pages and people search with a new way to search for people."},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://www.foofighters.com/","url":"http://www.foofighters.com/","visibleUrl":"www.foofighters.com","cacheUrl":"http://www.google.com/search?q\u003dcache:mH6Rsc-rjNgJ:www.foofighters.com","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters","titleNoFormatting":"Foo Fighters","content":"Jul 8, 2009 \u003cb\u003e...\u003c/b\u003e Official \u003cb\u003eFoo\u003c/b\u003e Fighters guitar, drum, and bass tabs."},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://searchcio-midmarket.techtarget.com/sDefinition/0,,sid183_gci212139,00.html","url":"http://searchcio-midmarket.techtarget.com/sDefinition/0,,sid183_gci212139,00.html","visibleUrl":"searchcio-midmarket.techtarget.com","cacheUrl":"http://www.google.com/search?q\u003dcache:mdfUdBXGcm0J:searchcio-midmarket.techtarget.com","title":"What is \u003cb\u003efoo\u003c/b\u003e? - a definition from Whatis.com","titleNoFormatting":"What is foo? - a definition from Whatis.com","content":"Dec 14, 2006 \u003cb\u003e...\u003c/b\u003e Just as economists sometimes use the term \u0026#39;widget\u0026#39; as the ultimate substitute for \u0026#39;something\u0026#39; that is being measured, programmers tend to \u003cb\u003e...\u003c/b\u003e"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"33400000","currentPageIndex":1,"moreResultsUrl":"http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseSize" : "small", "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/fixtures/web-response.json:
--------------------------------------------------------------------------------
1 | {"responseData": {"results":[{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://en.wikipedia.org/wiki/Foobar","url":"http://en.wikipedia.org/wiki/Foobar","visibleUrl":"en.wikipedia.org","cacheUrl":"http://www.google.com/search?q\u003dcache:4styY9qq7tYJ:en.wikipedia.org","title":"foobar - Wikipedia, the free encyclopedia","titleNoFormatting":"foobar - Wikipedia, the free encyclopedia","content":"Foobar is often used alone; \u003cb\u003efoo\u003c/b\u003e, bar, and baz are usually used in that order, \u003cb\u003e...\u003c/b\u003e \u003cb\u003eFoo\u003c/b\u003e has entered the English language as a neologism and is considered by \u003cb\u003e...\u003c/b\u003e"},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://www.foo.com/","url":"http://www.foo.com/","visibleUrl":"www.foo.com","cacheUrl":"http://www.google.com/search?q\u003dcache:aJjqmBB29rgJ:www.foo.com","title":"Get the 411 on Anyone with Free White Pages, People Search and \u003cb\u003e...\u003c/b\u003e","titleNoFormatting":"Get the 411 on Anyone with Free White Pages, People Search and ...","content":"Get the free 411, white pages and people search with a new way to search for people."},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://www.foofighters.com/","url":"http://www.foofighters.com/","visibleUrl":"www.foofighters.com","cacheUrl":"http://www.google.com/search?q\u003dcache:mH6Rsc-rjNgJ:www.foofighters.com","title":"\u003cb\u003eFoo\u003c/b\u003e Fighters","titleNoFormatting":"Foo Fighters","content":"Jul 8, 2009 \u003cb\u003e...\u003c/b\u003e Official \u003cb\u003eFoo\u003c/b\u003e Fighters guitar, drum, and bass tabs."},{"GsearchResultClass":"GwebSearch","unescapedUrl":"http://searchcio-midmarket.techtarget.com/sDefinition/0,,sid183_gci212139,00.html","url":"http://searchcio-midmarket.techtarget.com/sDefinition/0,,sid183_gci212139,00.html","visibleUrl":"searchcio-midmarket.techtarget.com","cacheUrl":"http://www.google.com/search?q\u003dcache:mdfUdBXGcm0J:searchcio-midmarket.techtarget.com","title":"What is \u003cb\u003efoo\u003c/b\u003e? - a definition from Whatis.com","titleNoFormatting":"What is foo? - a definition from Whatis.com","content":"Dec 14, 2006 \u003cb\u003e...\u003c/b\u003e Just as economists sometimes use the term \u0026#39;widget\u0026#39; as the ultimate substitute for \u0026#39;something\u0026#39; that is being measured, programmers tend to \u003cb\u003e...\u003c/b\u003e"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"33400000","currentPageIndex":0,"moreResultsUrl":"http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den\u0026q\u003dfoo"}}, "responseDetails": null, "responseStatus": 200}
--------------------------------------------------------------------------------
/spec/item_blog_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Blog do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('blog-response')['responseData']['results'].first
8 | item = Google::Search::Item::Blog.new hash
9 | item.title.should include('Foo (51)')
10 | item.author.should == 'KNews'
11 | item.uri.should == 'http://www.kaieteurnewsonline.com/2009/07/22/foo-51-amsterdam-4-12-shine-for-guyana-on-opening-day/'
12 | item.blog_uri.should == 'http://www.kaieteurnewsonline.com/'
13 | item.content.should include('Jonathon')
14 | item.published.should be_a(DateTime)
15 | end
16 | end
17 | end
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/spec/item_book_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Book do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('book-response')['responseData']['results'].first
8 | item = Google::Search::Item::Book.new hash
9 | item.title.should include('Foo Fighters')
10 | item.author.should == 'Foo Fighters (CRT), Hal Leonard Publishing Corporation'
11 | item.id.should == 'ISBN1423404580'
12 | item.uri.should == 'http://books.google.com/books?id=vUoCAgAACAAJ&dq=foo&client=internal-uds&source=uds'
13 | item.thumbnail_uri.should == 'http://bks6.books.google.com/books?id=vUoCAgAACAAJ&printsec=frontcover&img=1&zoom=5&sig=ACfU3U1NHHhXuERH30Xfn0GC3A0BW5nMPg'
14 | item.published_year.should == 2006
15 | item.pages.should == 69
16 | end
17 | end
18 | end
--------------------------------------------------------------------------------
/spec/item_image_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Image do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('image-response')['responseData']['results'].first
8 | item = Google::Search::Item::Image.new hash
9 | item.id.should == 'IYlLzX-w4vX2AM'
10 | item.title.should == 'foo_fighters.jpg'
11 | item.uri.should == 'http://tomdiaz.files.wordpress.com/2009/06/foo_fighters.jpg'
12 | item.content.should include('Not FBI Agents')
13 | item.context_uri.should == 'http://tomdiaz.wordpress.com/2009/06/'
14 | item.width.should == 883
15 | item.height.should == 891
16 | item.thumbnail_uri.should == 'http://images.google.com/images?q=tbn:IYlLzX-w4vX2AM:tomdiaz.files.wordpress.com/2009/06/foo_fighters.jpg'
17 | item.thumbnail_width.should == 145
18 | item.thumbnail_height.should == 146
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/item_local_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Local do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('local-response')['responseData']['results'].first
8 | item = Google::Search::Item::Local.new hash
9 | item.city.should == 'San Francisco'
10 | item.type.should == 'local'
11 | item.region.should == 'CA'
12 | item.uri.should == 'http://www.google.com/local?source=uds&q=foo&sll=37.795279%2C-122.407451&latlng=37795279%2C-122407451%2C1909516875098392575&near=37.795279%2C-122.407451'
13 | item.directions_from_here_uri.should == 'http://www.google.com/maps?source=uds&saddr=852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451&iwstate1=dir%3Afrom'
14 | item.directions_to_here_uri.should == 'http://www.google.com/maps?source=uds&daddr=852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451&iwstate1=dir%3Ato'
15 | item.directions_uri.should == 'http://www.google.com/maps?source=uds&daddr=852+Washington+St%2C+San+Francisco%2C+CA+%28Foo+Wah+Cheung%29+%4037.795279%2C-122.407451&saddr'
16 | item.title.should == 'Foo Wah Cheung'
17 | item.accuracy.should == 8
18 | item.country.should == 'United States'
19 | item.max_age.should == 604800
20 | item.thumbnail_uri.should == 'http://mt.google.com/mapdata?cc=us&tstyp=5&Point=b&Point.latitude_e6=37795279&Point.longitude_e6=-122407451&Point.iconid=15&Point=e&w=150&h=100&zl=4'
21 | item.long.should == -122.407451
22 | item.street_address.should == '852 Washington St'
23 | item.content.should == ''
24 | item.lat.should == 37.795279
25 | item.viewport_mode.should == 'computed'
26 | item.phone_numbers.should == ['(415) 391-4067']
27 | item.address_lines.should == ['852 Washington St', 'San Francisco, CA']
28 | end
29 | end
30 | end
--------------------------------------------------------------------------------
/spec/item_news_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::News do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('news-response')['responseData']['results'].first
8 | item = Google::Search::Item::News.new hash
9 | item.title.should include('TICKET TO DINING')
10 | item.language.should == 'en'
11 | item.uri.should == 'http://www.montgomerynews.com/articles/2009/07/22/entertainment/doc4a672746b0941650009917.txt'
12 | item.published.should be_a(DateTime)
13 | item.publisher.should == 'Montgomery Newspapers'
14 | item.content.should include('After all, it was')
15 | item.redirect_uri.should == 'http://news.google.com/news/url?sa=T&ct=us/0-0-0&fd=S&url=http://www.montgomerynews.com/articles/2009/07/22/entertainment/doc4a672746b0941650009917.txt&cid=0&ei=4aFnSpnxK474rQPutNHRAQ&usg=AFQjCNGsuTniL5DY24lNJ8qy204ZWjQoKA'
16 | item.location.should == 'Fort Washington,PA,USA'
17 | end
18 | end
19 | end
--------------------------------------------------------------------------------
/spec/item_patent_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Patent do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('patent-response')['responseData']['results'].first
8 | item = Google::Search::Item::Patent.new hash
9 | item.title.should == 'SZE-FOO CHIEN'
10 | item.id.should == 3468158
11 | item.content.should include('METHOD OF AND APPARATUS FOR DETERMINING RH')
12 | item.assignee.should == ''
13 | item.application_date.should be_a(DateTime)
14 | item.uri.should == 'http://www.google.com/patents/about?id=GDMdAAAAEBAJ&dq=foo&client=internal-uds&source=uds'
15 | item.thumbnail_uri.should == 'http://bks9.books.google.com/patents?id=GDMdAAAAEBAJ&printsec=drawing&img=1&zoom=1&sig=ACfU3U10b3w-4hMfKTEykPmtqnoObaLhaA'
16 | item.status.should == 'issued'
17 | end
18 | end
19 | end
--------------------------------------------------------------------------------
/spec/item_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item do
5 | describe ".class_for" do
6 | it "should return a constant" do
7 | Google::Search::Item.class_for('GwebSearch').should == Google::Search::Item::Web
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/spec/item_video_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Video do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('video-response')['responseData']['results'].first
8 | item = Google::Search::Item::Video.new hash
9 | item.title.should include('Foo Fighters')
10 | item.content.should include('Foo Fighters')
11 | item.uri.should == 'http://www.google.com/url?q=http://www.youtube.com/watch%3Fv%3DTVboOdX9icA&source=video&vgc=rss&usg=AFQjCNFvZftyyTO-IswoCPWEmmQbskBMRA'
12 | item.rating.should == 4.9076071
13 | item.type.should == 'YouTube'
14 | item.published.should be_a(DateTime)
15 | item.thumbnail_uri.should == 'http://0.gvt0.com/vi/TVboOdX9icA/default.jpg'
16 | item.publisher.should == 'www.youtube.com'
17 | item.duration.should == 269
18 | end
19 | end
20 | end
--------------------------------------------------------------------------------
/spec/item_web_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Item::Web do
5 | describe "#initialize" do
6 | it "should populate attributes" do
7 | hash = json_fixture('web-response')['responseData']['results'].first
8 | hash['index'] = 0
9 | item = Google::Search::Item::Web.new hash
10 | item.index.should == 0
11 | item.title.should include('foobar - Wikipedia')
12 | item.content.should include('Foobar is often used')
13 | item.uri.should == 'http://en.wikipedia.org/wiki/Foobar'
14 | item.cache_uri.should == 'http://www.google.com/search?q=cache:4styY9qq7tYJ:en.wikipedia.org'
15 | item.visible_uri.should == 'en.wikipedia.org'
16 | end
17 | end
18 | end
--------------------------------------------------------------------------------
/spec/response_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Response do
5 | before :each do
6 | @response = Google::Search::Response.new json_fixture('web-response')
7 | end
8 |
9 | describe "#initialize" do
10 | it "should not throw an error when invalid" do
11 | lambda { Google::Search::Response.new json_fixture('invalid-response') }.should_not raise_error
12 | end
13 |
14 | it "should set #items" do
15 | @response.items.first.should be_a(Google::Search::Item)
16 | @response.items.length.should == 4
17 | end
18 |
19 | it "should set item indices" do
20 | @response.items[0].index.should == 0
21 | @response.items[1].index.should == 1
22 | @response.items[2].index.should == 2
23 | end
24 |
25 | it "should set item indices when page is present" do
26 | @response = Google::Search::Response.new json_fixture('web-2-response')
27 | @response.size.should == :small
28 | @response.page.should == 1
29 | @response.items[0].index.should == 4
30 | @response.items[1].index.should == 5
31 | @response.items[2].index.should == 6
32 | end
33 |
34 | it "should set #estimated_count" do
35 | @response.estimated_count.should == 33400000
36 | end
37 |
38 | it "should set #page" do
39 | @response.page.should == 0
40 | end
41 |
42 | it "should set #status" do
43 | @response.status.should == 200
44 | end
45 |
46 | it "should set #details" do
47 | @response.details.should be_nil
48 | end
49 | end
50 |
51 | describe "#valid?" do
52 | it "should return false when response status is not 200" do
53 | response = Google::Search::Response.new 'responseStatus' => 400
54 | response.should_not be_valid
55 | end
56 |
57 | it "should return true when status is 200" do
58 | response = Google::Search::Response.new 'responseStatus' => 200, 'responseData' => { 'results' => [] }
59 | response.should be_valid
60 | end
61 | end
62 |
63 | end
--------------------------------------------------------------------------------
/spec/search_blog_spec.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visionmedia/google-search/47982299426aabe52b2a9d909b3ae8d7c2eaa8ef/spec/search_blog_spec.rb
--------------------------------------------------------------------------------
/spec/search_book_spec.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visionmedia/google-search/47982299426aabe52b2a9d909b3ae8d7c2eaa8ef/spec/search_book_spec.rb
--------------------------------------------------------------------------------
/spec/search_image_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Image do
5 | before :each do
6 | @search = Google::Search::Image.new :query => 'foo'
7 | end
8 |
9 | describe "#get_uri" do
10 | describe "safety_level" do
11 | it "should validate" do
12 | @search.safety_level = :active
13 | @search.get_uri.should include('safe=active')
14 | @search.safety_level = :foo
15 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /safety_level/)
16 | end
17 |
18 | it "should provide alternative naming :none, :medium, :high" do
19 | @search.safety_level = :none
20 | @search.get_uri.should include('safe=off')
21 | @search.safety_level = :medium
22 | @search.get_uri.should include('safe=moderate')
23 | @search.safety_level = :high
24 | @search.get_uri.should include('safe=active')
25 | end
26 | end
27 |
28 | describe "image_size" do
29 | it "should validate" do
30 | @search.image_size = :icon
31 | @search.get_uri.should include('imgsz=icon')
32 | @search.image_size = :small, :medium, :large
33 | @search.get_uri.should include('imgsz=small%7Cmedium%7Clarge')
34 | @search.image_size = :foo
35 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /image_size/)
36 | end
37 | end
38 |
39 | describe "color" do
40 | it "should validate" do
41 | @search.color = 'blue'
42 | @search.get_uri.should include('imgcolor=blue')
43 | end
44 | end
45 |
46 | describe "image_type" do
47 | it "should validate" do
48 | @search.image_type = :lineart
49 | @search.get_uri.should include('imgtype=lineart')
50 | @search.image_type = :foo
51 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /image_type/)
52 | end
53 | end
54 |
55 | describe "file_type" do
56 | it "should validate" do
57 | @search.file_type = :jpg
58 | @search.get_uri.should include('as_filetype=jpg')
59 | @search.file_type = :foo
60 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /file_type/)
61 | end
62 | end
63 |
64 | describe "uri" do
65 | it "should validate" do
66 | @search.uri = 'http://foo.com'
67 | @search.get_uri.should include('as_sitesearch=http%3A%2F%2Ffoo.com')
68 | end
69 | end
70 | end
71 | end
--------------------------------------------------------------------------------
/spec/search_local_spec.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visionmedia/google-search/47982299426aabe52b2a9d909b3ae8d7c2eaa8ef/spec/search_local_spec.rb
--------------------------------------------------------------------------------
/spec/search_news_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::News do
5 | before :each do
6 | @search = Google::Search::News.new :query => 'foo'
7 | end
8 |
9 | describe "#get_uri" do
10 | describe "relative_to" do
11 | it "should set relative to geo" do
12 | @search.relative_to = 'Edmonton Alberta'
13 | @search.get_uri.should_not include('geo=Edmonton%20Alberta')
14 | end
15 | end
16 |
17 | describe "topic" do
18 | it "should validate" do
19 | @search.topic = :world
20 | @search.get_uri.should include('topic=world')
21 | @search.topic = :foo
22 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /topic/)
23 | end
24 | end
25 |
26 | describe "edition" do
27 | it "should set edition" do
28 | @search.edition = :en
29 | @search.get_uri.should include('ned=en')
30 | end
31 | end
32 | end
33 | end
--------------------------------------------------------------------------------
/spec/search_patent_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Patent do
5 | before :each do
6 | @search = Google::Search::Patent.new :query => 'foo'
7 | end
8 |
9 | describe "#get_uri" do
10 | describe "issued_only" do
11 | it "should return issued and filed by default" do
12 | @search.get_uri.should_not include('as_psrg')
13 | @search.get_uri.should_not include('as_psra')
14 | end
15 |
16 | it "should return issued when true" do
17 | @search.issued_only = true
18 | @search.get_uri.should include('as_psrg=1')
19 | end
20 |
21 | it "should return filed when false" do
22 | @search.issued_only = false
23 | @search.get_uri.should include('as_psra=1')
24 | end
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/spec/search_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search do
5 | before :each do
6 | @search = Google::Search::Web.new :query => 'foo'
7 | end
8 |
9 | it "should throw an error when trying to initialize the base class" do
10 | lambda { Google::Search.new :query => 'foo' }.should raise_error(Google::Search::Error)
11 | end
12 |
13 | it "should be enumerable" do
14 | @search.to_a.first.should be_a(Google::Search::Item)
15 | end
16 |
17 | describe "#get_uri" do
18 | it "should return a uri" do
19 | @search.get_uri.should == 'http://www.google.com/uds/GwebSearch?start=0&rsz=large&hl=en&key=notsupplied&v=1.0&q=foo&filter=1'
20 | end
21 |
22 | it "should allow arbitrary key/value pairs" do
23 | search = Google::Search::Web.new :query => 'foo', :foo => 'bar'
24 | search.get_uri.should == 'http://www.google.com/uds/GwebSearch?start=0&rsz=large&hl=en&key=notsupplied&v=1.0&q=foo&filter=1&foo=bar'
25 | end
26 |
27 | describe "query" do
28 | it "should raise an error when no query string is present" do
29 | @search.query = nil
30 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /query/)
31 | @search.query = ''
32 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /query/)
33 | end
34 | end
35 |
36 | describe "version" do
37 | it "should raise an error when it is not present" do
38 | @search.version = nil
39 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /version/)
40 | end
41 | end
42 | end
43 |
44 | describe "#get_raw" do
45 | it "should return JSON string" do
46 | @search.get_raw.should be_a(String)
47 | end
48 | end
49 |
50 | describe "#get_hash" do
51 | it "should return JSON converted to a hash" do
52 | @search.stub!(:get_raw).and_return fixture('web-response.json')
53 | @search.get_hash.should be_a(Hash)
54 | end
55 | end
56 |
57 | describe "#get_response" do
58 | it "should return a Response object" do
59 | @search.stub!(:get_raw).and_return fixture('web-response.json')
60 | @search.get_response.should be_a(Google::Search::Response)
61 | end
62 |
63 | it "should populate #raw" do
64 | @search.stub!(:get_raw).and_return fixture('web-response.json')
65 | @search.get_response.raw.should be_a(String)
66 | end
67 | end
68 |
69 | describe "#next" do
70 | it "should prepare offset" do
71 | @search.size = :small
72 | @search.next.offset.should == 0; @search.get_raw
73 | @search.next.offset.should == 4; @search.get_raw
74 | @search.next.offset.should == 8
75 | @search.size = :large
76 | @search.sent = false
77 | @search.offset = 0
78 | @search.next.offset.should == 0; @search.get_raw
79 | @search.next.offset.should == 8; @search.get_raw
80 | @search.next.offset.should == 16
81 | end
82 | end
83 |
84 | describe "#response" do
85 | it "should alias #get_response" do
86 | @search.next.response.should be_a(Google::Search::Response)
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/spec/search_video_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require File.dirname(__FILE__) + '/spec_helper'
3 |
4 | describe Google::Search::Video do
5 | before :each do
6 | @search = Google::Search::Video.new :query => 'foo'
7 | end
8 |
9 | describe "#get_uri" do
10 | describe "order_by" do
11 | it "should validate" do
12 | @search.order_by = :date
13 | lambda { @search.get_uri }.should_not raise_error
14 | end
15 |
16 | it "should raise an error when invalid" do
17 | @search.order_by = :foo
18 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /order/)
19 | end
20 | end
21 |
22 | describe "filter" do
23 | it "should default to 1" do
24 | @search.get_uri.should include('filter=1')
25 | end
26 |
27 | it "should consider anything positive as 1" do
28 | @search.filter = true
29 | @search.get_uri.should include('filter=1')
30 | @search.filter = 123
31 | @search.get_uri.should include('filter=1')
32 | end
33 |
34 | it "should consider anything negative as 0" do
35 | @search.filter = false
36 | @search.get_uri.should include('filter=0')
37 | @search.filter = nil
38 | @search.get_uri.should include('filter=0')
39 | end
40 | end
41 | end
42 | end
--------------------------------------------------------------------------------
/spec/search_web_spec.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | require File.dirname(__FILE__) + '/spec_helper'
4 |
5 | describe Google::Search::Web do
6 | before :each do
7 | @search = Google::Search::Web.new :query => 'foo'
8 | end
9 |
10 | describe "#get_uri" do
11 | describe "safety_level" do
12 | it "should validate" do
13 | @search.safety_level = :moderate
14 | lambda { @search.get_uri }.should_not raise_error
15 | end
16 |
17 | it "should raise an error when invalid" do
18 | @search.safety_level = :foo
19 | lambda { @search.get_uri }.should raise_error(Google::Search::Error, /safety/)
20 | end
21 | end
22 |
23 | describe "filter" do
24 | it "should default to 1" do
25 | @search.get_uri.should include('filter=1')
26 | end
27 |
28 | it "should consider anything positive as 1" do
29 | @search.filter = true
30 | @search.get_uri.should include('filter=1')
31 | @search.filter = 123
32 | @search.get_uri.should include('filter=1')
33 | end
34 |
35 | it "should consider anything negative as 0" do
36 | @search.filter = false
37 | @search.get_uri.should include('filter=0')
38 | @search.filter = nil
39 | @search.get_uri.should include('filter=0')
40 | end
41 | end
42 | describe "multibyte string query" do
43 | it "url encoding" do
44 | @search.query = "日本語"
45 | @search.get_uri.should include('%E6%97%A5%E6%9C%AC%E8%AA%9E')
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/spec.opts:
--------------------------------------------------------------------------------
1 | --color
2 | --format specdoc
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 |
2 | $:.unshift File.dirname(__FILE__) + '/../lib'
3 | require 'pp'
4 | require 'rubygems'
5 | require 'google-search'
6 |
7 | def fixture path
8 | File.read File.dirname(__FILE__) + "/fixtures/#{path}"
9 | end
10 |
11 | def json_fixture name
12 | Google::Search.json_decode fixture("#{name}.json")
13 | end
--------------------------------------------------------------------------------
/tasks/docs.rake:
--------------------------------------------------------------------------------
1 |
2 | namespace :docs do
3 |
4 | desc 'Build sdoc'
5 | task :build do
6 | sh "sdoc -d -N -i lib -x spec -x examples -x doc -x Manifest -x Rakefile"
7 | end
8 |
9 | desc 'Remove rdoc products'
10 | task :remove => [:clobber_docs]
11 |
12 | desc 'Build docs, and open in browser for viewing (specify BROWSER)'
13 | task :open => ['docs:build'] do
14 | browser = ENV["BROWSER"] || "safari"
15 | sh "open -a #{browser} doc/index.html"
16 | end
17 |
18 | end
--------------------------------------------------------------------------------
/tasks/gemspec.rake:
--------------------------------------------------------------------------------
1 |
2 | desc 'Build gemspec file'
3 | task :gemspec => [:build_gemspec]
--------------------------------------------------------------------------------
/tasks/spec.rake:
--------------------------------------------------------------------------------
1 |
2 | require 'spec/rake/spectask'
3 |
4 | desc "Run all specifications"
5 | Spec::Rake::SpecTask.new(:spec) do |t|
6 | t.libs << "lib"
7 | t.spec_opts = ["--color", "--require", "spec/spec_helper.rb"]
8 | end
9 |
10 | namespace :spec do
11 |
12 | desc "Run all specifications verbosely"
13 | Spec::Rake::SpecTask.new(:verbose) do |t|
14 | t.libs << "lib"
15 | t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
16 | end
17 |
18 | desc "Run specific specification verbosely (specify SPEC)"
19 | Spec::Rake::SpecTask.new(:select) do |t|
20 | t.libs << "lib"
21 | t.spec_files = [ENV["SPEC"]]
22 | t.spec_opts = ["--color", "--format", "specdoc", "--require", "spec/spec_helper.rb"]
23 | end
24 |
25 | end
--------------------------------------------------------------------------------