google_contacts_api 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +42 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/google_contacts_api.gemspec +80 -0
- data/lib/google_contacts_api.rb +304 -0
- data/test/helper.rb +18 -0
- data/test/test_google_contacts_api.rb +7 -0
- metadata +179 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
gem "activesupport"
|
5
|
+
gem "json"
|
6
|
+
gem "hashie"
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "shoulda", ">= 0"
|
12
|
+
gem "bundler", "~> 1.0.0"
|
13
|
+
gem "jeweler", "~> 1.5.2"
|
14
|
+
gem "rcov", ">= 0"
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Alvin Liang
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# google_contacts_api
|
2
|
+
|
3
|
+
An unofficial Google Contacts API for ruby. Might not be stable (but probably is). In active usage at [thirsst.com](http://thirsst.com/). (Shameless plug: We help you manage your RSS and group bookmarking!)
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
You need to provide an OAuth access token from one of the major OAuth libraries to this library.
|
8
|
+
Then you can instantiate a GoogleContactsApi::Api object for direct posting and parsing, or a
|
9
|
+
GoogleContactsApi::User object for easier stuff.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
google_contacts_user = GoogleContactsApi::User(oauth_access_token_for_user)
|
13
|
+
contacts = google_contacts_user.contacts
|
14
|
+
groups = google_contacts_user.groups
|
15
|
+
groups.first.contacts
|
16
|
+
contacts.first.photo
|
17
|
+
contacts.first.title
|
18
|
+
contacts.first.id
|
19
|
+
```
|
20
|
+
|
21
|
+
## TODO
|
22
|
+
|
23
|
+
I welcome patches and pull requests, see the guidelines below (handily auto-generated
|
24
|
+
by jeweler).
|
25
|
+
|
26
|
+
* Tests! (using RSpec, please)
|
27
|
+
* Posting/putting/deleting groups, contacts and their photos
|
28
|
+
* Support ClientLogin
|
29
|
+
|
30
|
+
## Contributing to google_contacts_api
|
31
|
+
|
32
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
33
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
34
|
+
* Fork the project
|
35
|
+
* Start a feature/bugfix branch
|
36
|
+
* Commit and push until you are happy with your contribution
|
37
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
38
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
39
|
+
|
40
|
+
## Copyright
|
41
|
+
|
42
|
+
Copyright (c) 2011 Alvin Liang. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "google_contacts_api"
|
16
|
+
gem.homepage = "http://github.com/aliang/google_contacts_api"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Lets you read from the Google Contacts API}
|
19
|
+
gem.description = %Q{Lets you read from the Google Contacts API. Posting to come later. Tests to come later.}
|
20
|
+
gem.email = "ayliang@gmail.com"
|
21
|
+
gem.authors = ["Alvin Liang"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
gem.add_runtime_dependency 'activesupport'
|
25
|
+
gem.add_runtime_dependency 'hashie'
|
26
|
+
gem.add_runtime_dependency 'json'
|
27
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
28
|
+
end
|
29
|
+
Jeweler::RubygemsDotOrgTasks.new
|
30
|
+
|
31
|
+
require 'rake/testtask'
|
32
|
+
Rake::TestTask.new(:test) do |test|
|
33
|
+
test.libs << 'lib' << 'test'
|
34
|
+
test.pattern = 'test/**/test_*.rb'
|
35
|
+
test.verbose = true
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'rcov/rcovtask'
|
39
|
+
Rcov::RcovTask.new do |test|
|
40
|
+
test.libs << 'test'
|
41
|
+
test.pattern = 'test/**/test_*.rb'
|
42
|
+
test.verbose = true
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
require 'rdoc/task'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "google_contacts_api #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{google_contacts_api}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Alvin Liang"]
|
12
|
+
s.date = %q{2011-07-08}
|
13
|
+
s.description = %q{Lets you read from the Google Contacts API. Posting to come later. Tests to come later.}
|
14
|
+
s.email = %q{ayliang@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"google_contacts_api.gemspec",
|
27
|
+
"lib/google_contacts_api.rb",
|
28
|
+
"test/helper.rb",
|
29
|
+
"test/test_google_contacts_api.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/aliang/google_contacts_api}
|
32
|
+
s.licenses = ["MIT"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.6.2}
|
35
|
+
s.summary = %q{Lets you read from the Google Contacts API}
|
36
|
+
s.test_files = [
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/test_google_contacts_api.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
46
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
47
|
+
s.add_runtime_dependency(%q<hashie>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
51
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
52
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
53
|
+
s.add_runtime_dependency(%q<hashie>, [">= 0"])
|
54
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
57
|
+
s.add_dependency(%q<json>, [">= 0"])
|
58
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
59
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
60
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
61
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
62
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
63
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
64
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
65
|
+
s.add_dependency(%q<json>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
69
|
+
s.add_dependency(%q<json>, [">= 0"])
|
70
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
71
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
74
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
76
|
+
s.add_dependency(%q<hashie>, [">= 0"])
|
77
|
+
s.add_dependency(%q<json>, [">= 0"])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,304 @@
|
|
1
|
+
# TODO: Use more than one file
|
2
|
+
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'json'
|
5
|
+
require 'hashie'
|
6
|
+
|
7
|
+
module GoogleContactsApi
|
8
|
+
class Api
|
9
|
+
# keep separate in case of new auth method
|
10
|
+
BASE_URL = "https://www.google.com/m8/feeds/"
|
11
|
+
|
12
|
+
attr_reader :oauth
|
13
|
+
def initialize(oauth)
|
14
|
+
# TODO: Later, accept ClientLogin
|
15
|
+
@oauth = oauth
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get request to specified link, with query params
|
19
|
+
# For get, post, put, delete, always use JSON, it's simpler
|
20
|
+
# and lets us use Hashie::Mash. Note that in the JSON conversion from XML,
|
21
|
+
# ":" is replaced with $, element content is keyed with $t
|
22
|
+
def get(link, params = {}, headers = {})
|
23
|
+
params["alt"] = "json"
|
24
|
+
@oauth.get("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Post request to specified link, with query params
|
28
|
+
# Not tried yet, might be issues with params
|
29
|
+
def post(link, params = {}, headers = {})
|
30
|
+
params["alt"] = "json"
|
31
|
+
@oauth.post("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Put request to specified link, with query params
|
35
|
+
# Not tried yet
|
36
|
+
def put(link, params = {}, headers = {})
|
37
|
+
params["alt"] = "json"
|
38
|
+
@oauth.put("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Delete request to specified link, with query params
|
42
|
+
# Not tried yet
|
43
|
+
def delete(link, params = {}, headers = {})
|
44
|
+
params["alt"] = "json"
|
45
|
+
@oauth.delete("#{BASE_URL}#{link}?#{params.to_query}", headers)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Contacts
|
50
|
+
# Retrieve the contacts for this user or group
|
51
|
+
def contacts(params = {})
|
52
|
+
params = params.with_indifferent_access
|
53
|
+
|
54
|
+
# compose params into a string
|
55
|
+
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
56
|
+
# alt, q, max-results, start-index, updated-min,
|
57
|
+
# orderby, showdeleted, requirealldeleted, sortorder, group
|
58
|
+
params["max-results"] = 100000 unless params.key?("max-results")
|
59
|
+
url = "contacts/default/full"
|
60
|
+
response = @api.get(url, params)
|
61
|
+
|
62
|
+
# TODO: Define some fancy exceptions
|
63
|
+
case response.code
|
64
|
+
when 401; raise
|
65
|
+
when 403; raise
|
66
|
+
when 404; raise
|
67
|
+
when 400...500; raise
|
68
|
+
when 500...600; raise
|
69
|
+
end
|
70
|
+
ContactSet.new(response.body, @api)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class User
|
75
|
+
include Contacts
|
76
|
+
|
77
|
+
attr_reader :api
|
78
|
+
def initialize(oauth)
|
79
|
+
@api = GoogleContactsApi::Api.new(oauth)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Retrieve the groups for this user
|
83
|
+
# TODO: Handle 403, 404, 401
|
84
|
+
def groups(params = {})
|
85
|
+
params = params.with_indifferent_access
|
86
|
+
# compose params into a string
|
87
|
+
# See http://code.google.com/apis/contacts/docs/3.0/reference.html#Parameters
|
88
|
+
# alt, q, max-results, start-index, updated-min,
|
89
|
+
# orderby, showdeleted, requirealldeleted, sortorder
|
90
|
+
params["max-results"] = 100000 unless params.key?("max-results")
|
91
|
+
url = "groups/default/full"
|
92
|
+
# TODO: So weird thing, version 3 doesn't return system groups
|
93
|
+
# When it does, uncomment this line and use it to request instead
|
94
|
+
# response = @api.get(url, params)
|
95
|
+
response = @api.get(url, params, {"GData-Version" => "2"})
|
96
|
+
|
97
|
+
case response.code
|
98
|
+
when 401; raise
|
99
|
+
when 403; raise
|
100
|
+
when 404; raise
|
101
|
+
when 400...500; raise
|
102
|
+
when 500...600; raise
|
103
|
+
end
|
104
|
+
GroupSet.new(response.body, @api)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Base class for GroupSet and ContactSet
|
109
|
+
class ResultSet
|
110
|
+
include Enumerable
|
111
|
+
attr_reader :api
|
112
|
+
attr_accessor :total_results, :start_index, :items_per_page, :parsed
|
113
|
+
|
114
|
+
def initialize(response_body, api = nil)
|
115
|
+
@api = api
|
116
|
+
@parsed = Hashie::Mash.new(JSON.parse(response_body))
|
117
|
+
@total_results = @parsed.feed["openSearch$totalResults"]["$t"].to_i
|
118
|
+
@start_index = @parsed.feed["openSearch$startIndex"]["$t"].to_i
|
119
|
+
@items_per_page = @parsed.feed["openSearch$itemsPerPage"]["$t"].to_i
|
120
|
+
@results = []
|
121
|
+
end
|
122
|
+
|
123
|
+
def each
|
124
|
+
@results.each { |x| yield x }
|
125
|
+
end
|
126
|
+
|
127
|
+
def has_more?
|
128
|
+
# 1-based indexing
|
129
|
+
@start_index - 1 + @items_per_page <= @total_results
|
130
|
+
end
|
131
|
+
|
132
|
+
def inspect
|
133
|
+
"<#{self.class}: @start_index=#{@start_index}, @items_per_page=#{@items_per_page}, @total_results=#{@total_results}>"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class GroupSet < ResultSet
|
138
|
+
# Populate from a response that contains contacts
|
139
|
+
def initialize(response_body, api = nil)
|
140
|
+
super
|
141
|
+
@results = @parsed.feed.entry.map { |e| Group.new(e, nil, api) }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class ContactSet < ResultSet
|
146
|
+
# Populate from a response that contains contacts
|
147
|
+
def initialize(response_body, api = nil)
|
148
|
+
super
|
149
|
+
@results = @parsed.feed.entry.map { |e| Contact.new(e, nil, api) }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Base class for Group and Contact
|
154
|
+
class Result < Hashie::Mash
|
155
|
+
# Note that the title is really just the (full) name
|
156
|
+
# ":" replaced with $, element content is keyed with $t
|
157
|
+
|
158
|
+
# These are the accessors we can write
|
159
|
+
# :id, :title, :updated, :content
|
160
|
+
|
161
|
+
attr_reader :api
|
162
|
+
# Populate from a single result Hash/Hashie
|
163
|
+
def initialize(source_hash = nil, default = nil, api = nil, &blk)
|
164
|
+
@api = api if api
|
165
|
+
super(source_hash, default, &blk)
|
166
|
+
end
|
167
|
+
|
168
|
+
# TODO: Conditional retrieval? There might not be an etag in the
|
169
|
+
# JSON representation, there is in the XML representation
|
170
|
+
def etag
|
171
|
+
end
|
172
|
+
|
173
|
+
def id
|
174
|
+
_id = self["id"]
|
175
|
+
_id ? _id["$t"] : nil
|
176
|
+
end
|
177
|
+
|
178
|
+
def title
|
179
|
+
_title = self["title"]
|
180
|
+
_title ? _title["$t"] : nil
|
181
|
+
end
|
182
|
+
|
183
|
+
def content
|
184
|
+
_content = self["content"]
|
185
|
+
_content ? content["$t"] : nil
|
186
|
+
end
|
187
|
+
|
188
|
+
def updated
|
189
|
+
_updated = self["updated"]
|
190
|
+
_updated ? DateTime.parse(_updated["$t"]) : nil
|
191
|
+
end
|
192
|
+
|
193
|
+
# Returns the array of categories, as category is an array for Hashie.
|
194
|
+
def categories
|
195
|
+
category
|
196
|
+
end
|
197
|
+
|
198
|
+
def deleted?
|
199
|
+
raise NotImplementedError
|
200
|
+
end
|
201
|
+
|
202
|
+
def inspect
|
203
|
+
"<#{self.class}: #{title}>"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class Group < Result
|
208
|
+
include Contacts
|
209
|
+
# Populate from a single entry element in the result response
|
210
|
+
# when requesting a set of Contacts
|
211
|
+
|
212
|
+
def system_group?
|
213
|
+
!self["gContact$systemGroup"].nil?
|
214
|
+
end
|
215
|
+
|
216
|
+
def contacts(params = {})
|
217
|
+
# contacts in this group
|
218
|
+
@contacts ||= super({"group" => self.id}.merge(params))
|
219
|
+
end
|
220
|
+
|
221
|
+
def contacts!(params = {})
|
222
|
+
# contacts in this group
|
223
|
+
@contacts = super({"group" => self.id}.merge(params))
|
224
|
+
end
|
225
|
+
|
226
|
+
# Returns the array of links, as link is an array for Hashie.
|
227
|
+
def links
|
228
|
+
self["link"].map { |l| l.href }
|
229
|
+
end
|
230
|
+
|
231
|
+
def self_link
|
232
|
+
_link = self["link"].find { |l| l.rel == "self" }
|
233
|
+
_link ? _link.href : nil
|
234
|
+
end
|
235
|
+
|
236
|
+
def edit_link
|
237
|
+
_link = self["link"].find { |l| l.rel == "edit" }
|
238
|
+
_link ? _link.href : nil
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class Contact < Result
|
243
|
+
# :categories, (:content again), :links, (:title again), :email
|
244
|
+
# :extended_properties, :deleted, :im, :name,
|
245
|
+
# :organizations, :phone_numbers, :structured_postal_addresses, :where
|
246
|
+
|
247
|
+
# Returns the array of links, as link is an array for Hashie.
|
248
|
+
def links
|
249
|
+
self["link"].map { |l| l.href }
|
250
|
+
end
|
251
|
+
|
252
|
+
def self_link
|
253
|
+
_link = self["link"].find { |l| l.rel == "self" }
|
254
|
+
_link ? _link.href : nil
|
255
|
+
end
|
256
|
+
|
257
|
+
def alternate_link
|
258
|
+
_link = self["link"].find { |l| l.rel == "alternate" }
|
259
|
+
_link ? _link.href : nil
|
260
|
+
end
|
261
|
+
|
262
|
+
def photo_link
|
263
|
+
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#photo" }
|
264
|
+
_link ? _link.href : nil
|
265
|
+
end
|
266
|
+
|
267
|
+
# Returns binary data for the photo. You can probably
|
268
|
+
# use it in a data-uri. This is in PNG format.
|
269
|
+
def photo
|
270
|
+
return nil unless photo_link
|
271
|
+
response = @api.oauth.get(photo_link)
|
272
|
+
|
273
|
+
case response.code
|
274
|
+
# maybe return a placeholder instead of nil
|
275
|
+
when 400; return nil
|
276
|
+
when 401; return nil
|
277
|
+
when 403; return nil
|
278
|
+
when 404; return nil
|
279
|
+
when 400...500; return nil
|
280
|
+
when 500...600; return nil
|
281
|
+
else; return response.body
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def edit_photo_link
|
286
|
+
_link = self["link"].find { |l| l.rel == "http://schemas.google.com/contacts/2008/rel#edit_photo" }
|
287
|
+
_link ? _link.href : nil
|
288
|
+
end
|
289
|
+
|
290
|
+
def edit_link
|
291
|
+
_link = self["link"].find { |l| l.rel == "edit" }
|
292
|
+
_link ? _link.href : nil
|
293
|
+
end
|
294
|
+
|
295
|
+
def emails
|
296
|
+
self["gd$email"].map { |e| e.address }
|
297
|
+
end
|
298
|
+
|
299
|
+
def primary_email
|
300
|
+
_email = self["gd$email"].find { |e| e.primary == "true" }
|
301
|
+
_email ? _email.address : nil
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'google_contacts_api'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: google_contacts_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alvin Liang
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-08 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: hashie
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: shoulda
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: bundler
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 1.0.0
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: jeweler
|
73
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.5.2
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: rcov
|
84
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: activesupport
|
95
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
type: :runtime
|
102
|
+
prerelease: false
|
103
|
+
version_requirements: *id008
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: hashie
|
106
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: "0"
|
112
|
+
type: :runtime
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: *id009
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: json
|
117
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: "0"
|
123
|
+
type: :runtime
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: *id010
|
126
|
+
description: Lets you read from the Google Contacts API. Posting to come later. Tests to come later.
|
127
|
+
email: ayliang@gmail.com
|
128
|
+
executables: []
|
129
|
+
|
130
|
+
extensions: []
|
131
|
+
|
132
|
+
extra_rdoc_files:
|
133
|
+
- LICENSE.txt
|
134
|
+
- README.markdown
|
135
|
+
files:
|
136
|
+
- .document
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.markdown
|
140
|
+
- Rakefile
|
141
|
+
- VERSION
|
142
|
+
- google_contacts_api.gemspec
|
143
|
+
- lib/google_contacts_api.rb
|
144
|
+
- test/helper.rb
|
145
|
+
- test/test_google_contacts_api.rb
|
146
|
+
has_rdoc: true
|
147
|
+
homepage: http://github.com/aliang/google_contacts_api
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
post_install_message:
|
151
|
+
rdoc_options: []
|
152
|
+
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
hash: 3049273964521607278
|
161
|
+
segments:
|
162
|
+
- 0
|
163
|
+
version: "0"
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
none: false
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: "0"
|
170
|
+
requirements: []
|
171
|
+
|
172
|
+
rubyforge_project:
|
173
|
+
rubygems_version: 1.6.2
|
174
|
+
signing_key:
|
175
|
+
specification_version: 3
|
176
|
+
summary: Lets you read from the Google Contacts API
|
177
|
+
test_files:
|
178
|
+
- test/helper.rb
|
179
|
+
- test/test_google_contacts_api.rb
|