gmail_contacts 1.7 → 2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/History.txt +7 -0
- data/Rakefile +2 -2
- data/lib/gmail_contacts.rb +96 -21
- data/lib/gmail_contacts/test_stub.rb +39 -56
- data/sample/authsub.rb +14 -3
- data/test/test_gmail_contacts.rb +101 -36
- metadata +111 -24
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -11,8 +11,8 @@ Hoe.spec 'gmail_contacts' do
|
|
11
11
|
self.rubyforge_name = 'seattlerb'
|
12
12
|
self.testlib = :minitest
|
13
13
|
|
14
|
-
extra_deps << ['
|
15
|
-
extra_deps << ['
|
14
|
+
extra_deps << ['nokogiri', '~> 1.4']
|
15
|
+
extra_deps << ['net-http-persistent', '~> 1.2', '> 1.2']
|
16
16
|
extra_dev_deps << ['minitest', '~> 1.3']
|
17
17
|
end
|
18
18
|
|
data/lib/gmail_contacts.rb
CHANGED
@@ -1,16 +1,40 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http/persistent'
|
3
3
|
require 'nokogiri'
|
4
4
|
|
5
5
|
##
|
6
6
|
# GmailContacts sits atop GData and turns the contact feed into
|
7
7
|
# GmailContacts::Contact objects for friendly consumption.
|
8
8
|
#
|
9
|
+
# See sample/authsub.rb for an example which uses GmailContacts.
|
10
|
+
#
|
9
11
|
# GmailContacts was sponsored by AT&T Interactive.
|
12
|
+
#
|
13
|
+
# == Upgrading from 1.x
|
14
|
+
#
|
15
|
+
# gmail_contacts no longer depends on gdata and performs its own AuthSub
|
16
|
+
# handling. Use GmailContacts#authsub_url instead of #authsub_url on
|
17
|
+
# #contact_api.
|
18
|
+
#
|
19
|
+
# gmail_contacts no longer uses gdata to raise exceptions and instead raise
|
20
|
+
# Net::HTTPServerException instead. Rescue Net::HTTPServerException instead
|
21
|
+
# of GData::Client::RequestError. Net::HTTPServerException responds to
|
22
|
+
# #response which you can use to determine what kind of error you got:
|
23
|
+
#
|
24
|
+
# begin
|
25
|
+
# gc.fetch 'nobody@example', false
|
26
|
+
# rescue Net::HTTPServerException => e
|
27
|
+
# case e.response
|
28
|
+
# when Net::HTTPForbidden then
|
29
|
+
# puts "You are not allowed to view contacts for this user"
|
30
|
+
# end
|
31
|
+
# end
|
10
32
|
|
11
33
|
class GmailContacts
|
12
34
|
|
13
|
-
VERSION = '
|
35
|
+
VERSION = '2.0'
|
36
|
+
|
37
|
+
class Error < RuntimeError; end
|
14
38
|
|
15
39
|
Contact = Struct.new :title, :emails, :ims, :phone_numbers, :addresses,
|
16
40
|
:photo_url
|
@@ -40,9 +64,10 @@ class GmailContacts
|
|
40
64
|
attr_reader :author_name
|
41
65
|
|
42
66
|
##
|
43
|
-
#
|
67
|
+
# The current authsub token. If you upgrade a request token to a session
|
68
|
+
# token the value will change.
|
44
69
|
|
45
|
-
|
70
|
+
attr_reader :authsub_token
|
46
71
|
|
47
72
|
##
|
48
73
|
# Contact data
|
@@ -63,11 +88,7 @@ class GmailContacts
|
|
63
88
|
|
64
89
|
##
|
65
90
|
# Creates a new GmailContacts using +authsub_token+. If you don't yet have
|
66
|
-
# an AuthSub token, call
|
67
|
-
# endpoint.
|
68
|
-
#
|
69
|
-
# See GData::Client::Base in the gdata gem and
|
70
|
-
# http://code.google.com/apis/accounts/docs/AuthSub.html for more details.
|
91
|
+
# an AuthSub token, call #authsub_url.
|
71
92
|
|
72
93
|
def initialize(authsub_token = nil, session_token = false)
|
73
94
|
@authsub_token = authsub_token
|
@@ -79,8 +100,38 @@ class GmailContacts
|
|
79
100
|
@author_name = nil
|
80
101
|
@contacts ||= []
|
81
102
|
|
82
|
-
@
|
83
|
-
@
|
103
|
+
@google = URI.parse 'https://www.google.com'
|
104
|
+
@http = Net::HTTP::Persistent.new "gmail_contacts_#{object_id}"
|
105
|
+
@http.debug_output = $stderr
|
106
|
+
@http.headers['Authorization'] = "AuthSub token=\"#{@authsub_token}\""
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Returns a URL that will allow a user to authorize contact retrieval.
|
111
|
+
# Redirect the user to this URL and they will (should) approve your contact
|
112
|
+
# retrieval request.
|
113
|
+
#
|
114
|
+
# +next_url+ is where Google will redirect the user after they grant your
|
115
|
+
# request.
|
116
|
+
#
|
117
|
+
# See http://code.google.com/apis/accounts/docs/AuthSub.html for more
|
118
|
+
# details.
|
119
|
+
|
120
|
+
def authsub_url next_url, secure = false, session = true, domain = nil
|
121
|
+
query = {
|
122
|
+
'next' => CGI.escape(next_url),
|
123
|
+
'scope' => 'http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F',
|
124
|
+
'secure' => (secure ? 1 : 0),
|
125
|
+
'session' => (session ? 1 : 0),
|
126
|
+
}
|
127
|
+
|
128
|
+
query['hd'] = CGI.escape domain if domain
|
129
|
+
|
130
|
+
query = query.map do |key, value|
|
131
|
+
"#{key}=#{value}"
|
132
|
+
end.sort.join '&'
|
133
|
+
|
134
|
+
"https://www.google.com/accounts/AuthSubRequest?#{query}"
|
84
135
|
end
|
85
136
|
|
86
137
|
##
|
@@ -89,10 +140,10 @@ class GmailContacts
|
|
89
140
|
def fetch(email, revoke = true)
|
90
141
|
get_token
|
91
142
|
|
92
|
-
uri = "http://www.google.com/m8/feeds/contacts/#{email}/full"
|
143
|
+
uri = URI.parse "http://www.google.com/m8/feeds/contacts/#{email}/full"
|
93
144
|
|
94
145
|
loop do
|
95
|
-
res =
|
146
|
+
res = request uri
|
96
147
|
|
97
148
|
xml = Nokogiri::XML res.body
|
98
149
|
|
@@ -101,7 +152,7 @@ class GmailContacts
|
|
101
152
|
next_uri = xml.xpath('//xmlns:feed/xmlns:link[@rel="next"]').first
|
102
153
|
break unless next_uri
|
103
154
|
|
104
|
-
uri
|
155
|
+
uri += next_uri['href']
|
105
156
|
end
|
106
157
|
|
107
158
|
yield if block_given?
|
@@ -118,17 +169,24 @@ class GmailContacts
|
|
118
169
|
else
|
119
170
|
contact.photo_url
|
120
171
|
end
|
121
|
-
|
172
|
+
response = request URI.parse photo_url
|
122
173
|
|
123
|
-
|
174
|
+
response.body
|
124
175
|
end
|
125
176
|
|
126
177
|
##
|
127
|
-
# Fetches an AuthSub session token
|
178
|
+
# Fetches an AuthSub session token. Changes the value of #authsub_token so
|
179
|
+
# you can store it in a database or wherever.
|
128
180
|
|
129
181
|
def get_token
|
130
182
|
return if @session_token
|
131
|
-
|
183
|
+
|
184
|
+
response = request @google + '/accounts/AuthSubSessionToken'
|
185
|
+
|
186
|
+
response.body =~ /^Token=(.*)/
|
187
|
+
|
188
|
+
@authsub_token = $1
|
189
|
+
@http.headers['Authorization'] = "AuthSub token=\"#{@authsub_token}\""
|
132
190
|
@session_token = true
|
133
191
|
end
|
134
192
|
|
@@ -181,10 +239,27 @@ class GmailContacts
|
|
181
239
|
end
|
182
240
|
|
183
241
|
##
|
184
|
-
#
|
242
|
+
# Performs a GET for +uri+ and returns the Net::HTTPResponse. Raises
|
243
|
+
# Net::HTTPError if the response wasn't a success (OK, Created, Found).
|
244
|
+
|
245
|
+
def request uri
|
246
|
+
response = @http.request uri
|
247
|
+
|
248
|
+
case response
|
249
|
+
when Net::HTTPOK, Net::HTTPCreated, Net::HTTPFound then
|
250
|
+
response
|
251
|
+
else
|
252
|
+
response.error!
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
##
|
257
|
+
# Revokes our AuthSub session token
|
185
258
|
|
186
259
|
def revoke_token
|
187
|
-
@
|
260
|
+
request @google + '/accounts/AuthSubRevokeToken'
|
261
|
+
|
262
|
+
@session_token = false
|
188
263
|
end
|
189
264
|
|
190
265
|
##
|
@@ -8,13 +8,13 @@ require 'gmail_contacts'
|
|
8
8
|
#
|
9
9
|
# require 'gmail_contacts'
|
10
10
|
# require 'gmail_contacts/test_stub'
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# class TestMyClass < Test::Unit::TestCase
|
13
13
|
# def test_something
|
14
14
|
# GmailContacts.stub
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# # ... your code using gc
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# end
|
19
19
|
# end
|
20
20
|
#
|
@@ -23,6 +23,15 @@ require 'gmail_contacts'
|
|
23
23
|
#
|
24
24
|
# If you set the authsub token to 'wrong_user_authsub_token', the test stub
|
25
25
|
# will raise a GData::Client::AuthorizationError when you call #fetch.
|
26
|
+
#
|
27
|
+
# If you set the authsub token to 'authsub_token', #get_token will change it
|
28
|
+
# to 'authsub_token-upgraded' to indicate it was upgraded to a session token.
|
29
|
+
#
|
30
|
+
# If you fetch a photo with 404 in the url, #fetch_photo will raise a
|
31
|
+
# Net::HTTPServerException with a 404 response inside.
|
32
|
+
#
|
33
|
+
# #revoke_token will set the token to 'authsub_token-revoked' to indicate it
|
34
|
+
# was revoked.
|
26
35
|
|
27
36
|
class GmailContacts::TestStub
|
28
37
|
|
@@ -138,6 +147,8 @@ class GmailContacts
|
|
138
147
|
|
139
148
|
@stubbed = false
|
140
149
|
|
150
|
+
attr_reader :http
|
151
|
+
|
141
152
|
def self.stub
|
142
153
|
return if @stubbed
|
143
154
|
@stubbed = true
|
@@ -146,25 +157,23 @@ class GmailContacts
|
|
146
157
|
|
147
158
|
def get_token
|
148
159
|
if @authsub_token == 'recycled_authsub_token' then
|
149
|
-
|
150
|
-
res.status_code = 403
|
151
|
-
res.body = 'recycled token'
|
152
|
-
raise GData::Client::AuthorizationError, res
|
160
|
+
Net::HTTPForbidden.new(nil, '403', 'Forbidden').error!
|
153
161
|
end
|
154
|
-
|
155
|
-
@
|
156
|
-
|
157
|
-
@
|
162
|
+
|
163
|
+
@authsub_token = 'authsub_token-upgraded' if
|
164
|
+
@authsub_token == 'authsub_token'
|
165
|
+
@session_token = true
|
166
|
+
|
167
|
+
@http.stub_reset
|
168
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
169
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
158
170
|
end
|
159
171
|
|
160
172
|
alias old_fetch fetch
|
161
173
|
|
162
174
|
def fetch(*args)
|
163
175
|
if @authsub_token == 'wrong_user_authsub_token' then
|
164
|
-
|
165
|
-
res.status_code = 403
|
166
|
-
res.body = 'wrong user'
|
167
|
-
raise GData::Client::AuthorizationError, res
|
176
|
+
Net::HTTPForbidden.new(nil, '403', 'Forbidden').error!
|
168
177
|
end
|
169
178
|
|
170
179
|
old_fetch(*args)
|
@@ -179,77 +188,51 @@ class GmailContacts
|
|
179
188
|
contact.photo_url
|
180
189
|
end
|
181
190
|
|
182
|
-
|
183
|
-
|
184
|
-
def res.status_code() 404 end
|
185
|
-
def res.body() 'Photo not found' end
|
186
|
-
raise GData::Client::UnknownError, res
|
187
|
-
end
|
191
|
+
Net::HTTPNotFound.new(nil, '404', 'Not Found').error! if
|
192
|
+
photo_url =~ /404/
|
188
193
|
|
189
194
|
old_fetch_photo contact
|
190
195
|
end
|
191
196
|
|
197
|
+
alias old_revoke_token revoke_token
|
198
|
+
|
199
|
+
def revoke_token
|
200
|
+
@authsub_token = 'authsub_token-revoked'
|
201
|
+
@session_token = false
|
202
|
+
end
|
203
|
+
|
192
204
|
end
|
193
205
|
|
194
206
|
end
|
195
207
|
# :startdoc:
|
196
208
|
|
197
|
-
|
198
|
-
# Extension that provides a stub for testing GmailContacts
|
199
|
-
#
|
200
|
-
# See GmailContacts::TestStub for usage details
|
201
|
-
|
202
|
-
class GData::Client::Contacts
|
209
|
+
class Net::HTTP::Persistent
|
203
210
|
|
204
211
|
##
|
205
212
|
# Accessor for data the stub will return
|
206
213
|
|
207
214
|
attr_accessor :stub_data
|
208
215
|
|
209
|
-
##
|
210
|
-
# Accessor for the stub AuthSub token
|
211
|
-
|
212
|
-
attr_accessor :stub_token
|
213
|
-
|
214
216
|
##
|
215
217
|
# Accessor for URLs the stub accessed
|
216
218
|
|
217
219
|
attr_accessor :stub_urls
|
218
220
|
|
219
|
-
|
220
|
-
# Sets the authsub token to +token+, but does no HTTP requests
|
221
|
-
|
222
|
-
def authsub_token=(token)
|
223
|
-
@stub_token = token
|
224
|
-
auth_handler = Object.new
|
225
|
-
auth_handler.instance_variable_set :@revoked, nil
|
226
|
-
auth_handler.instance_variable_set :@upgraded, nil
|
227
|
-
auth_handler.instance_variable_set :@token, token
|
228
|
-
def auth_handler.revoke() @revoked = true end
|
229
|
-
def auth_handler.revoked?() @revoked end
|
230
|
-
def auth_handler.upgrade() @upgraded = true end
|
231
|
-
def auth_handler.upgraded?() @upgraded end
|
232
|
-
def auth_handler.token()
|
233
|
-
[@token,
|
234
|
-
(@revoked ? 'revoked' : nil),
|
235
|
-
(@upgraded ? 'upgraded' : nil)].compact.join '-'
|
236
|
-
end
|
237
|
-
self.auth_handler = auth_handler
|
238
|
-
end
|
221
|
+
alias old_request request
|
239
222
|
|
240
223
|
##
|
241
|
-
# Fetches +url+, records in
|
224
|
+
# Fetches +url+, records in stub_urls, and returns data if there's still
|
242
225
|
# data in stub_data, or raises an exception
|
243
226
|
|
244
|
-
def
|
245
|
-
@stub_urls << url
|
227
|
+
def request(url)
|
228
|
+
@stub_urls << url.to_s
|
246
229
|
raise 'stub data empty' if @stub_data.empty?
|
247
230
|
|
248
231
|
data = @stub_data.shift
|
249
232
|
|
250
233
|
return data.call if Proc === data
|
251
234
|
|
252
|
-
res =
|
235
|
+
res = Net::HTTPOK.new nil, '200', 'OK'
|
253
236
|
def res.body() @data end
|
254
237
|
res.instance_variable_set :@data, data
|
255
238
|
res
|
data/sample/authsub.rb
CHANGED
@@ -7,6 +7,9 @@ webrick = WEBrick::HTTPServer.new :Port => 3000
|
|
7
7
|
webrick.mount_proc '/' do |req, res|
|
8
8
|
res.content_type = 'text/html'
|
9
9
|
|
10
|
+
##
|
11
|
+
# This is the initial page, a form with an email to fetch contacts for
|
12
|
+
|
10
13
|
if req.path == '/' then
|
11
14
|
res.body = <<-BODY
|
12
15
|
<form action="http://#{Socket.gethostname}:3000/go">
|
@@ -15,12 +18,20 @@ webrick.mount_proc '/' do |req, res|
|
|
15
18
|
</form>
|
16
19
|
BODY
|
17
20
|
|
21
|
+
##
|
22
|
+
# This is where we redirect the user to Google for approval, click "grant"
|
23
|
+
# on that page.
|
24
|
+
|
18
25
|
elsif req.path == '/go' then
|
19
26
|
gmail_contacts = GmailContacts.new
|
20
|
-
url = gmail_contacts.
|
21
|
-
"http
|
27
|
+
url = gmail_contacts.authsub_url \
|
28
|
+
"http://localhost:3000/return?email=#{req.query['email']}"
|
22
29
|
res.set_redirect WEBrick::HTTPStatus::SeeOther, url
|
23
30
|
|
31
|
+
##
|
32
|
+
# Google sends us back here, so we create a new GmailContacts with the token
|
33
|
+
# they gave us and fetch the contacts for the email provided to /go
|
34
|
+
|
24
35
|
elsif req.path == '/return' then
|
25
36
|
res.body = "<h1>contacts</h1>\n"
|
26
37
|
|
@@ -37,7 +48,7 @@ webrick.mount_proc '/' do |req, res|
|
|
37
48
|
res.body << "<li>#{contact.title} - #{contact.primary_email}\n"
|
38
49
|
end
|
39
50
|
|
40
|
-
res.body << "
|
51
|
+
res.body << "</ul>\n"
|
41
52
|
rescue => e
|
42
53
|
res.body << <<-BODY
|
43
54
|
<h1>error</h1>
|
data/test/test_gmail_contacts.rb
CHANGED
@@ -7,9 +7,9 @@ require 'pp'
|
|
7
7
|
class TestGmailContacts < MiniTest::Unit::TestCase
|
8
8
|
|
9
9
|
def setup
|
10
|
-
@gc = GmailContacts.new 'token'
|
11
|
-
@
|
12
|
-
@
|
10
|
+
@gc = GmailContacts.new 'token', true
|
11
|
+
@http = @gc.http
|
12
|
+
@http.stub_reset
|
13
13
|
|
14
14
|
@eric =
|
15
15
|
GmailContacts::Contact.new('Eric', %w[eric@example.com eric@example.net],
|
@@ -20,64 +20,70 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
20
20
|
"http://www.google.com/m8/feeds/photos/media/eric%40example.com/18")
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_initialize
|
24
|
+
assert_equal 'AuthSub token="token"', @http.headers['Authorization']
|
25
|
+
assert_match %r%_\d+$%, @http.name
|
26
|
+
end
|
27
|
+
|
23
28
|
def test_fetch
|
24
|
-
@
|
25
|
-
@
|
29
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
30
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
31
|
+
@http.stub_data << ''
|
26
32
|
|
27
33
|
@gc.fetch 'eric@example.com'
|
28
34
|
|
29
35
|
assert_equal 3, @gc.contacts.length
|
30
36
|
|
31
|
-
assert_equal
|
37
|
+
assert_equal 3, @http.stub_urls.length
|
32
38
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
33
|
-
@
|
39
|
+
@http.stub_urls.shift
|
34
40
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
35
|
-
@
|
36
|
-
|
37
|
-
|
38
|
-
assert @api.auth_handler.revoked?
|
41
|
+
@http.stub_urls.shift
|
42
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
43
|
+
@http.stub_urls.shift
|
39
44
|
end
|
40
45
|
|
41
|
-
def
|
42
|
-
@
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
46
|
+
def test_fetch_auto_upgrade
|
47
|
+
@gc = GmailContacts.new 'token'
|
48
|
+
@http = @gc.http
|
49
|
+
@http.stub_reset
|
50
|
+
@http.stub_data << ''
|
51
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
52
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
53
|
+
@http.stub_data << ''
|
50
54
|
|
51
|
-
|
55
|
+
@gc.fetch 'eric@example.com'
|
52
56
|
|
53
|
-
assert_equal
|
54
|
-
assert_equal 'http://www.google.com/m8/feeds/contacts/notme@example.com/full',
|
55
|
-
@api.stub_urls.shift
|
57
|
+
assert_equal 3, @gc.contacts.length
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
assert_equal 4, @http.stub_urls.length
|
60
|
+
assert_equal 'https://www.google.com/accounts/AuthSubSessionToken',
|
61
|
+
@http.stub_urls.shift
|
62
|
+
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
63
|
+
@http.stub_urls.shift
|
64
|
+
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
65
|
+
@http.stub_urls.shift
|
66
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
67
|
+
@http.stub_urls.shift
|
59
68
|
end
|
60
69
|
|
61
70
|
def test_fetch_no_revoke
|
62
|
-
@
|
63
|
-
@
|
71
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS
|
72
|
+
@http.stub_data << GmailContacts::TestStub::CONTACTS2
|
64
73
|
|
65
74
|
@gc.fetch 'eric@example.com', false
|
66
75
|
|
67
76
|
assert_equal 3, @gc.contacts.length
|
68
77
|
|
69
|
-
assert_equal 2, @
|
78
|
+
assert_equal 2, @http.stub_urls.length
|
70
79
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric@example.com/full',
|
71
|
-
@
|
80
|
+
@http.stub_urls.shift
|
72
81
|
assert_equal 'http://www.google.com/m8/feeds/contacts/eric%40example.com/full?start-index=3&max-results=2',
|
73
|
-
@
|
74
|
-
|
75
|
-
assert @api.auth_handler.upgraded?
|
76
|
-
refute @api.auth_handler.revoked?
|
82
|
+
@http.stub_urls.shift
|
77
83
|
end
|
78
84
|
|
79
85
|
def test_fetch_photo
|
80
|
-
@
|
86
|
+
@http.stub_data << 'THIS IS A PHOTO!'
|
81
87
|
|
82
88
|
photo = @gc.fetch_photo @eric
|
83
89
|
|
@@ -85,13 +91,36 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
85
91
|
end
|
86
92
|
|
87
93
|
def test_fetch_photo_url
|
88
|
-
@
|
94
|
+
@http.stub_data << 'THIS IS A PHOTO!'
|
89
95
|
|
90
96
|
photo = @gc.fetch_photo @eric.photo_url
|
91
97
|
|
92
98
|
assert_equal 'THIS IS A PHOTO!', photo
|
93
99
|
end
|
94
100
|
|
101
|
+
def test_get_token
|
102
|
+
assert @gc.token?, 'sanity, we should already have a session token'
|
103
|
+
|
104
|
+
assert_nil @gc.get_token
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_get_token_non_session
|
108
|
+
@gc = GmailContacts.new 'token'
|
109
|
+
@http = @gc.http
|
110
|
+
@http.stub_reset
|
111
|
+
@http.stub_data << 'Token=new token'
|
112
|
+
|
113
|
+
@gc.get_token
|
114
|
+
|
115
|
+
assert @gc.token?
|
116
|
+
assert_equal 'new token', @gc.authsub_token
|
117
|
+
assert_equal 'AuthSub token="new token"', @http.headers['Authorization']
|
118
|
+
|
119
|
+
assert_equal 1, @http.stub_urls.length
|
120
|
+
assert_equal 'https://www.google.com/accounts/AuthSubSessionToken',
|
121
|
+
@http.stub_urls.shift
|
122
|
+
end
|
123
|
+
|
95
124
|
def test_parse
|
96
125
|
@gc.parse Nokogiri::XML(GmailContacts::TestStub::CONTACTS)
|
97
126
|
|
@@ -134,5 +163,41 @@ class TestGmailContacts < MiniTest::Unit::TestCase
|
|
134
163
|
assert_equal expected, @gc.contacts
|
135
164
|
end
|
136
165
|
|
166
|
+
def test_request
|
167
|
+
@http.stub_data << 'blah'
|
168
|
+
|
169
|
+
res = @gc.request 'http://example'
|
170
|
+
|
171
|
+
assert_equal 'blah', res.body
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_request_unsuccessful
|
175
|
+
@http.stub_data << proc do
|
176
|
+
Net::HTTPForbidden.new nil, '403', 'Forbidden'
|
177
|
+
end
|
178
|
+
|
179
|
+
assert_raises Net::HTTPServerException do
|
180
|
+
@gc.request 'http://example'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_revoke_token
|
185
|
+
@http.stub_data << ''
|
186
|
+
|
187
|
+
@gc.revoke_token
|
188
|
+
|
189
|
+
refute @gc.token?
|
190
|
+
|
191
|
+
assert_equal 1, @http.stub_urls.length
|
192
|
+
assert_equal 'https://www.google.com/accounts/AuthSubRevokeToken',
|
193
|
+
@http.stub_urls.shift
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_token_eh
|
197
|
+
assert @gc.token?
|
198
|
+
|
199
|
+
refute GmailContacts.new.token?
|
200
|
+
end
|
201
|
+
|
137
202
|
end
|
138
203
|
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gmail_contacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 3
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: "2.0"
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Eric Hodel
|
@@ -30,49 +35,125 @@ cert_chain:
|
|
30
35
|
x52qPcexcYZR7w==
|
31
36
|
-----END CERTIFICATE-----
|
32
37
|
|
33
|
-
date:
|
38
|
+
date: 2010-06-03 00:00:00 -07:00
|
34
39
|
default_executable:
|
35
40
|
dependencies:
|
36
41
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
name: nokogiri
|
43
|
+
prerelease: false
|
44
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
41
46
|
requirements:
|
42
47
|
- - ~>
|
43
48
|
- !ruby/object:Gem::Version
|
44
|
-
|
45
|
-
|
46
|
-
-
|
47
|
-
|
49
|
+
hash: 7
|
50
|
+
segments:
|
51
|
+
- 1
|
52
|
+
- 4
|
53
|
+
version: "1.4"
|
48
54
|
type: :runtime
|
49
|
-
|
50
|
-
|
55
|
+
version_requirements: *id001
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: net-http-persistent
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
51
61
|
requirements:
|
52
62
|
- - ~>
|
53
63
|
- !ruby/object:Gem::Version
|
64
|
+
hash: 11
|
65
|
+
segments:
|
66
|
+
- 1
|
67
|
+
- 2
|
68
|
+
version: "1.2"
|
69
|
+
- - ">"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 11
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 2
|
54
75
|
version: "1.2"
|
55
|
-
|
76
|
+
type: :runtime
|
77
|
+
version_requirements: *id002
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rubyforge
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 9
|
87
|
+
segments:
|
88
|
+
- 2
|
89
|
+
- 0
|
90
|
+
- 3
|
91
|
+
version: 2.0.3
|
92
|
+
type: :development
|
93
|
+
version_requirements: *id003
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: gemcutter
|
96
|
+
prerelease: false
|
97
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 11
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
- 5
|
106
|
+
- 0
|
107
|
+
version: 0.5.0
|
108
|
+
type: :development
|
109
|
+
version_requirements: *id004
|
56
110
|
- !ruby/object:Gem::Dependency
|
57
111
|
name: minitest
|
112
|
+
prerelease: false
|
113
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 1
|
121
|
+
- 5
|
122
|
+
- 0
|
123
|
+
version: 1.5.0
|
58
124
|
type: :development
|
59
|
-
|
60
|
-
|
125
|
+
version_requirements: *id005
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: minitest
|
128
|
+
prerelease: false
|
129
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
61
131
|
requirements:
|
62
132
|
- - ~>
|
63
133
|
- !ruby/object:Gem::Version
|
134
|
+
hash: 9
|
135
|
+
segments:
|
136
|
+
- 1
|
137
|
+
- 3
|
64
138
|
version: "1.3"
|
65
|
-
|
139
|
+
type: :development
|
140
|
+
version_requirements: *id006
|
66
141
|
- !ruby/object:Gem::Dependency
|
67
142
|
name: hoe
|
68
|
-
|
69
|
-
|
70
|
-
|
143
|
+
prerelease: false
|
144
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
71
146
|
requirements:
|
72
147
|
- - ">="
|
73
148
|
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
|
149
|
+
hash: 27
|
150
|
+
segments:
|
151
|
+
- 2
|
152
|
+
- 5
|
153
|
+
- 0
|
154
|
+
version: 2.5.0
|
155
|
+
type: :development
|
156
|
+
version_requirements: *id007
|
76
157
|
description: |-
|
77
158
|
Simple Gmail contacts extraction using GData.
|
78
159
|
|
@@ -109,21 +190,27 @@ rdoc_options:
|
|
109
190
|
require_paths:
|
110
191
|
- lib
|
111
192
|
required_ruby_version: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
112
194
|
requirements:
|
113
195
|
- - ">="
|
114
196
|
- !ruby/object:Gem::Version
|
197
|
+
hash: 3
|
198
|
+
segments:
|
199
|
+
- 0
|
115
200
|
version: "0"
|
116
|
-
version:
|
117
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
118
203
|
requirements:
|
119
204
|
- - ">="
|
120
205
|
- !ruby/object:Gem::Version
|
206
|
+
hash: 3
|
207
|
+
segments:
|
208
|
+
- 0
|
121
209
|
version: "0"
|
122
|
-
version:
|
123
210
|
requirements: []
|
124
211
|
|
125
212
|
rubyforge_project: seattlerb
|
126
|
-
rubygems_version: 1.3.
|
213
|
+
rubygems_version: 1.3.7
|
127
214
|
signing_key:
|
128
215
|
specification_version: 3
|
129
216
|
summary: Simple Gmail contacts extraction using GData
|
metadata.gz.sig
CHANGED
Binary file
|