google-custom_search 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/google/custom_search/config.rb +57 -0
- data/lib/google/custom_search/json/results.rb +102 -0
- data/lib/google/custom_search/json/service.rb +38 -0
- data/lib/google/custom_search/query.rb +35 -0
- data/lib/google/custom_search/xml/results.rb +95 -0
- data/lib/google/custom_search/xml/service.rb +38 -0
- data/lib/google/custom_search.rb +3 -0
- data/spec/lib/google/custom_search/json/result_spec.rb +9 -0
- data/spec/lib/google/custom_search_spec.rb +163 -0
- data/spec/spec_helper.rb +12 -0
- metadata +109 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Google
|
|
2
|
+
module CustomSearch
|
|
3
|
+
class Config
|
|
4
|
+
attr_accessor :path
|
|
5
|
+
attr_accessor :environment
|
|
6
|
+
|
|
7
|
+
[:key, :cx, :cse_id, :cref, :service].each do |key|
|
|
8
|
+
attr_writer key
|
|
9
|
+
define_method(key) do
|
|
10
|
+
instance_variable_get("@#{key}".to_sym) || read(key)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def service_type
|
|
15
|
+
eval("#{self.service.upcase}::Service")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def read(key)
|
|
21
|
+
env_config[key.to_s] || raise("Key '#{key}' was not found in your config file #{path}. Alternatives: #{env_config.keys.join(',')}")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def env_config
|
|
25
|
+
all_config[environment] || raise("No key for environment '#{environment}' found in #{path}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def all_config
|
|
29
|
+
return @config if @config
|
|
30
|
+
[:path, :environment].each do |param|
|
|
31
|
+
raise "Please set Google::CustomSearch.config.#{param}" unless self.send(param)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
raise "Config file does not exist at #{path}" unless File.exists?(path)
|
|
35
|
+
@config = YAML.load_file(path)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class << self
|
|
40
|
+
attr_accessor :config
|
|
41
|
+
|
|
42
|
+
def configure
|
|
43
|
+
yield config
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
self.config = Config.new
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if defined?(Rails)
|
|
53
|
+
Google::CustomSearch.configure do |config|
|
|
54
|
+
config.path = "#{Rails.root}/config/google.yml"
|
|
55
|
+
config.environment = Rails.env
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
module CustomSearch
|
|
5
|
+
|
|
6
|
+
module JSON
|
|
7
|
+
|
|
8
|
+
class Results
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
def initialize(response)
|
|
12
|
+
@data = ::JSON.parse(response)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def each(&block)
|
|
16
|
+
items.each(&block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def empty?
|
|
20
|
+
items.empty?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def length
|
|
24
|
+
items.length
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def next_page
|
|
28
|
+
Page.new(@data['queries']['nextPage'] || @data['queries']['request'])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def current_page
|
|
32
|
+
Page.new(@data['queries']['request'])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def previous_page
|
|
36
|
+
Page.new(@data['queries']['previousPage'] || @data['queries']['request'])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def items
|
|
42
|
+
@items ||= (@data['items'] || []).map do |item|
|
|
43
|
+
Result.new(item)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Page
|
|
48
|
+
def initialize(data)
|
|
49
|
+
@data = data[0]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def start_index
|
|
53
|
+
@data['startIndex']
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_s
|
|
57
|
+
"results #{start_index}-#{end_index} of #{total}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ==(other)
|
|
61
|
+
other.start_index == start_index
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def total
|
|
67
|
+
@data['totalResults']
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def end_index
|
|
71
|
+
start_index + @data['count'] - 1
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Result
|
|
78
|
+
def initialize(data)
|
|
79
|
+
@data = data
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def title
|
|
83
|
+
@data['title'] || ''
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def uri
|
|
87
|
+
@data['link']
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def content
|
|
91
|
+
@data['htmlSnippet']
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def site
|
|
95
|
+
@data['displayLink']
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'google/custom_search/json/results'
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
module CustomSearch
|
|
5
|
+
module JSON
|
|
6
|
+
|
|
7
|
+
class Service
|
|
8
|
+
|
|
9
|
+
def initialize(config)
|
|
10
|
+
@config = config
|
|
11
|
+
@resource = RestClient::Resource.new('https://www.googleapis.com/customsearch/v1')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def request(query_string, start_index)
|
|
15
|
+
@resource.get(:params => params(query_string, start_index)) do |response, request, result|
|
|
16
|
+
unless response.code == 200
|
|
17
|
+
raise BadRequestError, "Unable to fetch results from Google: #{response}"
|
|
18
|
+
end
|
|
19
|
+
Results.new(response)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def params(query_string, start_index)
|
|
26
|
+
{
|
|
27
|
+
:q => query_string,
|
|
28
|
+
:start => start_index,
|
|
29
|
+
:key => @config.key,
|
|
30
|
+
:cref => @config.cref,
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'google/custom_search/config'
|
|
2
|
+
require 'google/custom_search/json/service'
|
|
3
|
+
require 'google/custom_search/xml/service'
|
|
4
|
+
|
|
5
|
+
module Google
|
|
6
|
+
module CustomSearch
|
|
7
|
+
|
|
8
|
+
class BadRequestError < StandardError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class ConfigurationError < StandardError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Query
|
|
15
|
+
|
|
16
|
+
def initialize(query_string, start_index, config = Google::CustomSearch.config)
|
|
17
|
+
@query_string = query_string
|
|
18
|
+
@start_index = start_index
|
|
19
|
+
@service = config.service_type.new(config)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def results
|
|
23
|
+
attempts = 5
|
|
24
|
+
begin
|
|
25
|
+
@service.request(@query_string, @start_index)
|
|
26
|
+
rescue BadRequestError
|
|
27
|
+
attempts -= 1
|
|
28
|
+
retry if attempts > 0
|
|
29
|
+
raise
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
|
|
4
|
+
module Google
|
|
5
|
+
module CustomSearch
|
|
6
|
+
|
|
7
|
+
module XML
|
|
8
|
+
|
|
9
|
+
class Results
|
|
10
|
+
include Enumerable
|
|
11
|
+
|
|
12
|
+
def initialize(response)
|
|
13
|
+
@doc = Nokogiri::XML.parse(response)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def each(&block)
|
|
17
|
+
items.each(&block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def empty?
|
|
21
|
+
items.empty?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def length
|
|
25
|
+
items.length
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def next_page
|
|
29
|
+
return current_page unless @doc.search('//RES/NB').any?
|
|
30
|
+
Page.new(current_page.end_index + 1, current_page.end_index + 11, 10)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def current_page
|
|
34
|
+
Page.from_xml(@doc.search('//RES').first)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def previous_page
|
|
38
|
+
return current_page if current_page.start_index == 1
|
|
39
|
+
Page.new(current_page.start_index - 10, current_page.start_index, 10)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def items
|
|
45
|
+
@items ||= @doc.search('//RES/R').map do |node|
|
|
46
|
+
Result.new(node)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Page < Struct.new(:start_index, :end_index, :total)
|
|
51
|
+
def self.from_xml(node)
|
|
52
|
+
new(
|
|
53
|
+
node.attributes['SN'].text.to_i,
|
|
54
|
+
node.attributes['EN'].text.to_i,
|
|
55
|
+
node.search('M').text.to_i)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def to_s
|
|
59
|
+
"results #{start_index}-#{end_index} of #{total}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ==(other)
|
|
63
|
+
other.start_index == start_index
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class Result
|
|
71
|
+
def initialize(node)
|
|
72
|
+
@node = node
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def title
|
|
76
|
+
@node.search('T').text
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def uri
|
|
80
|
+
@node.search('U').text
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def content
|
|
84
|
+
@node.search('S').text
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def site
|
|
88
|
+
URI.parse(@node.search('U').text).host
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'google/custom_search/xml/results'
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
module CustomSearch
|
|
5
|
+
module XML
|
|
6
|
+
|
|
7
|
+
class Service
|
|
8
|
+
|
|
9
|
+
def initialize(config)
|
|
10
|
+
@config = config
|
|
11
|
+
@resource = RestClient::Resource.new('http://www.google.com/cse')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def request(query_string, start_index)
|
|
15
|
+
@resource.get(:params => params(query_string, start_index)) do |response, request, result|
|
|
16
|
+
unless response.code == 200
|
|
17
|
+
raise BadRequestError, "Unable to fetch results from Google: #{response}"
|
|
18
|
+
end
|
|
19
|
+
Results.new(response)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def params(query_string, start_index)
|
|
26
|
+
{
|
|
27
|
+
:q => query_string,
|
|
28
|
+
:output => 'xml_no_dtd',
|
|
29
|
+
:start => start_index - 1,
|
|
30
|
+
:cx => @config.cx,
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Google
|
|
4
|
+
describe CustomSearch do
|
|
5
|
+
let(:config) do
|
|
6
|
+
stub \
|
|
7
|
+
:cref => 'https://github.com/mattwynne/google-custom_search/blob/master/spec/fixtures/mcht-only.xml',
|
|
8
|
+
:key => 'AIzaSyA-AayUZh6S5mGMmja3pt2gfpsncLiwqN8',
|
|
9
|
+
:service_type => CustomSearch::JSON::Service
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def search_for(query_string, options = {})
|
|
13
|
+
start_index = options[:start_index] || 1
|
|
14
|
+
query = CustomSearch::Query.new(query_string, start_index, config)
|
|
15
|
+
query.results
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "retry on error" do
|
|
19
|
+
|
|
20
|
+
context "when Google returns a 400 bad request error" do
|
|
21
|
+
|
|
22
|
+
before(:each) do
|
|
23
|
+
stub_request(:any, /.*/).to_return(
|
|
24
|
+
:status => [400, "Bad Request"],
|
|
25
|
+
:body => "A helpful message"
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "raises an error" do
|
|
30
|
+
expect { search_for 'foo' }.to raise_error(CustomSearch::BadRequestError)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "returns the body of the response in the error message" do
|
|
34
|
+
begin
|
|
35
|
+
search_for 'foo'
|
|
36
|
+
rescue => error
|
|
37
|
+
error.to_s.should =~ /A helpful message/
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when Google returns a 500 bad request error for the first four requests but subsequent requests are OK" do
|
|
44
|
+
|
|
45
|
+
before(:each) do
|
|
46
|
+
stub_request(:any, /.*/).to_return(
|
|
47
|
+
{ :status => [500, "Bad Request"] },
|
|
48
|
+
{ :status => [500, "Bad Request"] },
|
|
49
|
+
{ :status => [500, "Bad Request"] },
|
|
50
|
+
{ :status => [500, "Bad Request"] },
|
|
51
|
+
{ :status => [200, "OK"], :body => '[]' }
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "does not raise an error" do
|
|
56
|
+
expect { search_for 'foo' }.to_not raise_error(CustomSearch::BadRequestError)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
{
|
|
63
|
+
:json => {
|
|
64
|
+
:service_type => CustomSearch::JSON::Service,
|
|
65
|
+
:cref => 'https://raw.github.com/mattwynne/google-custom_search/master/spec/fixtures/json_api_annotations.xml',
|
|
66
|
+
:key => 'AIzaSyA-AayUZh6S5mGMmja3pt2gfpsncLiwqN8'
|
|
67
|
+
},
|
|
68
|
+
:xml => {
|
|
69
|
+
:service_type => CustomSearch::XML::Service,
|
|
70
|
+
:cx => '003087164461061609361:-u1ua6laowa'
|
|
71
|
+
}
|
|
72
|
+
}.each do |service, config|
|
|
73
|
+
|
|
74
|
+
context "using the #{service} service" do
|
|
75
|
+
let(:config) { stub config }
|
|
76
|
+
before { config.stub(:service => service) }
|
|
77
|
+
|
|
78
|
+
context "searching for something that exists in the list" do
|
|
79
|
+
let(:results) { search_for 'kath morgan' }
|
|
80
|
+
|
|
81
|
+
it "returns results" do
|
|
82
|
+
results.any?.should be_true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "returns the expected result" do
|
|
86
|
+
results.first.content.should =~ /01270 275215/
|
|
87
|
+
# that's Kath's phone number
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'returns the expected site' do
|
|
91
|
+
results.first.site.should == 'www.mcht.nhs.uk'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "searching for something that doesn't exist" do
|
|
97
|
+
let(:results) { search_for 'bobbins' }
|
|
98
|
+
|
|
99
|
+
it "returns no results" do
|
|
100
|
+
results.should be_empty
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "#next_page" do
|
|
105
|
+
|
|
106
|
+
context "a search that returns multiple pages of results" do
|
|
107
|
+
let(:results) { search_for 'trust' }
|
|
108
|
+
|
|
109
|
+
it "has a start_index of 11" do
|
|
110
|
+
results.next_page.start_index.should == 11
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context "a search for the second of multiple pages" do
|
|
115
|
+
let(:results) { search_for 'trust', :start_index => 11 }
|
|
116
|
+
|
|
117
|
+
it "has a start_index of 21" do
|
|
118
|
+
results.next_page.start_index.should == 21
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
context "a search that returns one page of results" do
|
|
123
|
+
let(:results) { search_for 'kath morgan' }
|
|
124
|
+
|
|
125
|
+
it "returns 1, pointing you back to the same page of results" do
|
|
126
|
+
results.next_page.start_index.should == 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "is equal to the #current_page" do
|
|
130
|
+
results.next_page.should == results.current_page
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe "#current_page" do
|
|
136
|
+
context "a search for the second of multiple pages" do
|
|
137
|
+
let(:results) { search_for 'trust', :start_index => 11 }
|
|
138
|
+
|
|
139
|
+
it "has a start_index of 11" do
|
|
140
|
+
results.current_page.start_index.should == 11
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "converts to a summary string" do
|
|
144
|
+
results.current_page.to_s.should =~ /results 11-20 of \d+/
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
describe "#previous_page" do
|
|
150
|
+
context "a search for the second of multiple pages" do
|
|
151
|
+
let(:results) { search_for 'trust', :start_index => 11 }
|
|
152
|
+
|
|
153
|
+
it "has a start_index of 1" do
|
|
154
|
+
results.previous_page.start_index.should == 1
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
RSpec.configure do |config|
|
|
2
|
+
config.mock_with :rspec
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
require 'webmock/rspec'
|
|
6
|
+
WebMock.allow_net_connect!
|
|
7
|
+
|
|
8
|
+
require 'google/custom_search'
|
|
9
|
+
Google::CustomSearch.configure do |config|
|
|
10
|
+
config.path = File.dirname(__FILE__) + '/fixtures/config/google.yml'
|
|
11
|
+
config.environment = 'test'
|
|
12
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: google-custom_search
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Matt Wynne
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2011-12-02 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rest-client
|
|
16
|
+
requirement: &2152308960 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '1.6'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *2152308960
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: nokogiri
|
|
27
|
+
requirement: &2152307820 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ~>
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.5'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *2152307820
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: rspec
|
|
38
|
+
requirement: &2152306800 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - =
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '2.7'
|
|
44
|
+
type: :development
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *2152306800
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: webmock
|
|
49
|
+
requirement: &2152305660 !ruby/object:Gem::Requirement
|
|
50
|
+
none: false
|
|
51
|
+
requirements:
|
|
52
|
+
- - =
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.7'
|
|
55
|
+
type: :development
|
|
56
|
+
prerelease: false
|
|
57
|
+
version_requirements: *2152305660
|
|
58
|
+
- !ruby/object:Gem::Dependency
|
|
59
|
+
name: guard-rspec
|
|
60
|
+
requirement: &2152305060 !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ! '>='
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
type: :development
|
|
67
|
+
prerelease: false
|
|
68
|
+
version_requirements: *2152305060
|
|
69
|
+
description: Ruby library for querying Google's Custom Search APIs.
|
|
70
|
+
email: matt@mattwynne.net
|
|
71
|
+
executables: []
|
|
72
|
+
extensions: []
|
|
73
|
+
extra_rdoc_files: []
|
|
74
|
+
files:
|
|
75
|
+
- lib/google/custom_search/config.rb
|
|
76
|
+
- lib/google/custom_search/json/results.rb
|
|
77
|
+
- lib/google/custom_search/json/service.rb
|
|
78
|
+
- lib/google/custom_search/query.rb
|
|
79
|
+
- lib/google/custom_search/xml/results.rb
|
|
80
|
+
- lib/google/custom_search/xml/service.rb
|
|
81
|
+
- lib/google/custom_search.rb
|
|
82
|
+
- spec/lib/google/custom_search/json/result_spec.rb
|
|
83
|
+
- spec/lib/google/custom_search_spec.rb
|
|
84
|
+
- spec/spec_helper.rb
|
|
85
|
+
homepage: https://github.com/mattwynne/gooogle-custom_search
|
|
86
|
+
licenses: []
|
|
87
|
+
post_install_message:
|
|
88
|
+
rdoc_options: []
|
|
89
|
+
require_paths:
|
|
90
|
+
- lib
|
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
|
+
none: false
|
|
93
|
+
requirements:
|
|
94
|
+
- - ! '>='
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
|
+
none: false
|
|
99
|
+
requirements:
|
|
100
|
+
- - ! '>='
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
requirements: []
|
|
104
|
+
rubyforge_project:
|
|
105
|
+
rubygems_version: 1.8.10
|
|
106
|
+
signing_key:
|
|
107
|
+
specification_version: 3
|
|
108
|
+
summary: Interface for Google's Custom Search APIs
|
|
109
|
+
test_files: []
|