contact-list 0.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/README +0 -0
- data/lib/contact_list.rb +13 -0
- data/lib/contacts/contact/facebook.rb +11 -0
- data/lib/contacts/contact/google.rb +11 -0
- data/lib/contacts/contact/linkedin.rb +7 -0
- data/lib/contacts/contact/twitter.rb +7 -0
- data/lib/contacts/contact/yahoo.rb +17 -0
- data/lib/contacts/contact.rb +9 -0
- data/lib/contacts/provider/base.rb +73 -0
- data/lib/contacts/provider/facebook.rb +13 -0
- data/lib/contacts/provider/google.rb +18 -0
- data/lib/contacts/provider/linkedin.rb +13 -0
- data/lib/contacts/provider/oauth.rb +18 -0
- data/lib/contacts/provider/oauth2.rb +18 -0
- data/lib/contacts/provider/twitter.rb +33 -0
- data/lib/contacts/provider/yahoo.rb +13 -0
- data/lib/contacts/provider.rb +21 -0
- data/lib/contacts.rb +14 -0
- metadata +189 -0
data/README
ADDED
File without changes
|
data/lib/contact_list.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/slice'
|
4
|
+
require 'active_support/core_ext/class/inheritable_attributes'
|
5
|
+
require 'active_support/core_ext/module/delegation'
|
6
|
+
require 'active_support/core_ext/object/blank'
|
7
|
+
require 'active_support/inflector'
|
8
|
+
|
9
|
+
class Hash
|
10
|
+
alias_method :only, :slice
|
11
|
+
alias_method :only!, :slice!
|
12
|
+
end
|
13
|
+
require File.expand_path('../contacts', __FILE__)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Contacts::Contact::Google < Struct.new(:email, :name)
|
2
|
+
|
3
|
+
def self.parse xml
|
4
|
+
name = xml.css("title").text
|
5
|
+
email_node = xml.xpath("gd:email").first
|
6
|
+
return nil unless email_node.present?
|
7
|
+
email = email_node['address']
|
8
|
+
new(email, name)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Contacts::Contact::Yahoo < Struct.new(:email, :name)
|
2
|
+
|
3
|
+
def self.parse hash
|
4
|
+
email, name = '', nil
|
5
|
+
hash['fields'].each do |field|
|
6
|
+
case field['type']
|
7
|
+
when 'email'
|
8
|
+
email = field['value']
|
9
|
+
when 'name'
|
10
|
+
name = [field['value']['givenName'], field['value']['familyName']].join(' ') rescue ''
|
11
|
+
end
|
12
|
+
end
|
13
|
+
name ||= email
|
14
|
+
new(email, name) unless email.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Contacts
|
2
|
+
module Contact
|
3
|
+
autoload :Google, 'contacts/contact/google'
|
4
|
+
autoload :Yahoo, 'contacts/contact/yahoo'
|
5
|
+
autoload :Facebook, 'contacts/contact/facebook'
|
6
|
+
autoload :Twitter, 'contacts/contact/twitter'
|
7
|
+
autoload :Linkedin, 'contacts/contact/linkedin'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Contacts
|
2
|
+
module Provider
|
3
|
+
class Base
|
4
|
+
|
5
|
+
class_inheritable_accessor :site_url
|
6
|
+
self.site_url = nil
|
7
|
+
delegate :site_url, :to => "self.class"
|
8
|
+
|
9
|
+
class_inheritable_accessor :valid_attributes
|
10
|
+
self.valid_attributes = []
|
11
|
+
delegate :import_type, :valid_attributes, :to => "self.class"
|
12
|
+
|
13
|
+
def self.set_site_url url
|
14
|
+
self.site_url = url
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.set_valid_attributes *attrs
|
18
|
+
self.valid_attributes = attrs.map!(&:to_sym)
|
19
|
+
attr_accessor *attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.provider_id
|
23
|
+
self.name.demodulize.underscore
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.all attrs={}
|
27
|
+
new(attrs).contacts
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize attrs={}
|
31
|
+
parse_attributes attrs
|
32
|
+
end
|
33
|
+
|
34
|
+
def connect!
|
35
|
+
raise "implement in subclass"
|
36
|
+
end
|
37
|
+
|
38
|
+
def connection
|
39
|
+
@connection ||= connect!
|
40
|
+
end
|
41
|
+
|
42
|
+
def retrieve_contacts!
|
43
|
+
raise "implement in subclass"
|
44
|
+
end
|
45
|
+
|
46
|
+
def contacts_response
|
47
|
+
@contacts_response ||= retrieve_contacts!
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_contacts!
|
51
|
+
raise "implement in subclass"
|
52
|
+
end
|
53
|
+
|
54
|
+
def contacts
|
55
|
+
@contacts ||= parse_contacts!
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_attributes attrs = {}
|
59
|
+
self.attributes = attrs.only(*valid_attributes)
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes= attrs = {}
|
63
|
+
attrs.each do |attr_name, attr_value|
|
64
|
+
send("#{attr_name}=", attr_value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def attributes
|
69
|
+
valid_attributes.inject({}) {|result, attr| result.merge attr => send(attr) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
class Contacts::Provider::Facebook < Contacts::Provider::OAuth2
|
3
|
+
set_site_url 'https://graph.facebook.com'
|
4
|
+
|
5
|
+
def retrieve_contacts!
|
6
|
+
@contacts_response = connection.get("/me/friends")
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_contacts!
|
10
|
+
@contacts = MultiJson.decode(contacts_response)['data'].map { |contact| Contacts::Contact::Facebook.parse(contact) }.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class Contacts::Provider::Google < Contacts::Provider::OAuth
|
4
|
+
set_site_url 'https://www.google.com'
|
5
|
+
|
6
|
+
def retrieve_contacts!
|
7
|
+
@contacts_response = connection.get("/m8/feeds/contacts/#{uid||'default'}/full?max-results=999")
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_contacts!
|
11
|
+
if contacts_response.code.to_i == 401
|
12
|
+
raise "Error 401".inspect
|
13
|
+
else
|
14
|
+
@contacts = Nokogiri::XML(contacts_response.body).css("entry").map {|entry| Contacts::Contact::Google.parse(entry)}.compact
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
class Contacts::Provider::Linkedin < Contacts::Provider::OAuth
|
3
|
+
set_site_url 'http://api.linkedin.com'
|
4
|
+
|
5
|
+
def retrieve_contacts!
|
6
|
+
@connections_response = connection.get("/v1/people/~/connections:(first-name,last-name,id,headline,picture-url)")
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_contacts!
|
10
|
+
MultiJson.decode(contacts_response.body)['values'].map { |contact| Contacts::Contact::Linkedin.parse(contact) }.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
|
3
|
+
module Contacts
|
4
|
+
module Provider
|
5
|
+
class OAuth < Contacts::Provider::Base
|
6
|
+
set_valid_attributes :token, :secret, :consumer_key, :consumer_secret, :uid
|
7
|
+
|
8
|
+
def consumer
|
9
|
+
@consumer ||= ::OAuth::Consumer.new(consumer_key, consumer_secret, :site => site_url)
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect!
|
13
|
+
::OAuth::AccessToken.new(consumer, token, secret)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module Contacts
|
4
|
+
module Provider
|
5
|
+
class OAuth2 < Contacts::Provider::Base
|
6
|
+
set_valid_attributes :token, :consumer_key, :consumer_secret
|
7
|
+
|
8
|
+
def client
|
9
|
+
@client ||= ::OAuth2::Client.new(consumer_key, consumer_secret, :site => site_url)
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect!
|
13
|
+
::OAuth2::AccessToken.new(client, token)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
class Contacts::Provider::Twitter < Contacts::Provider::OAuth
|
3
|
+
set_site_url 'http://api.twitter.com'
|
4
|
+
|
5
|
+
def retrieve_contacts!
|
6
|
+
{:followers_response => followers_response, :following_response => following_response}
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_contacts!
|
10
|
+
followers & following
|
11
|
+
end
|
12
|
+
|
13
|
+
def followers_response
|
14
|
+
@followers_response ||= connection.get("/1/statuses/followers.json")
|
15
|
+
end
|
16
|
+
|
17
|
+
def following_response
|
18
|
+
@following_response ||= connection.get("/1/statuses/friends.json")
|
19
|
+
end
|
20
|
+
|
21
|
+
def followers
|
22
|
+
@followers ||= parse_response!(followers_response)
|
23
|
+
end
|
24
|
+
|
25
|
+
def following
|
26
|
+
@following ||= parse_response!(following_response)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_response! response
|
30
|
+
MultiJson.decode(response.body).map { |contact| Contacts::Contact::Twitter.parse(contact) }.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
class Contacts::Provider::Yahoo < Contacts::Provider::OAuth
|
3
|
+
set_site_url 'http://social.yahooapis.com'
|
4
|
+
|
5
|
+
def retrieve_contacts!
|
6
|
+
@contacts_response = connection.get("/v1/user/me/contacts?format=json")
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_contacts!
|
10
|
+
@contacts = ((MultiJson.decode(contacts_response.body)['contacts']||{})['contact']||[]).map { |contact| Contacts::Contact::Yahoo.parse(contact) }.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Contacts
|
2
|
+
module Provider
|
3
|
+
autoload :Base, 'contacts/provider/base'
|
4
|
+
autoload :OAuth, 'contacts/provider/oauth'
|
5
|
+
autoload :Google, 'contacts/provider/google'
|
6
|
+
autoload :Yahoo, 'contacts/provider/yahoo'
|
7
|
+
autoload :Twitter, 'contacts/provider/twitter'
|
8
|
+
autoload :OAuth2, 'contacts/provider/oauth2'
|
9
|
+
autoload :Facebook, 'contacts/provider/facebook'
|
10
|
+
autoload :Linkedin, 'contacts/provider/linkedin'
|
11
|
+
|
12
|
+
def self.all
|
13
|
+
[Google, Yahoo, Twitter, Facebook, Linkedin]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find provider_id
|
17
|
+
all.find { |provider| provider.provider_id == provider_id.to_s }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/contacts.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Contacts
|
2
|
+
autoload :Provider, 'contacts/provider'
|
3
|
+
autoload :Contact, 'contacts/contact'
|
4
|
+
|
5
|
+
def self.[] provider_id
|
6
|
+
Provider.find(provider_id.to_s) || error_with!(provider_id)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def self.error_with! provider_id
|
12
|
+
raise("Invalid provider_id #{provider_id.to_s.inspect}, available provider_id; #{Provider.all.map(&:provider_id).join(', ')}")
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: contact-list
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alex Neill
|
9
|
+
- Tom Warner
|
10
|
+
- Paul Bowsher
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2012-02-14 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: contact-list
|
18
|
+
requirement: &70198657387760 !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: *70198657387760
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: &70198657387140 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '2.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *70198657387140
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
requirement: &70198657386660 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.0'
|
46
|
+
type: :development
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *70198657386660
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
requirement: &70198657386040 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '2.0'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *70198657386040
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rspec
|
62
|
+
requirement: &70198657385400 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '2.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *70198657385400
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: activesupport
|
73
|
+
requirement: &70198657384880 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.1.0
|
79
|
+
type: :runtime
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: *70198657384880
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: multi_json
|
84
|
+
requirement: &70198657384340 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.0.4
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: *70198657384340
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: nokogiri
|
95
|
+
requirement: &70198657383640 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ~>
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: 1.5.0
|
101
|
+
type: :runtime
|
102
|
+
prerelease: false
|
103
|
+
version_requirements: *70198657383640
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: oauth
|
106
|
+
requirement: &70198657383040 !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ~>
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 0.4.5
|
112
|
+
type: :runtime
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: *70198657383040
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: oauth2
|
117
|
+
requirement: &70198657382440 !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ~>
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 0.5.2
|
123
|
+
type: :runtime
|
124
|
+
prerelease: false
|
125
|
+
version_requirements: *70198657382440
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rspec
|
128
|
+
requirement: &70198657381900 !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: *70198657381900
|
137
|
+
description: Find contacts from multiple providers
|
138
|
+
email:
|
139
|
+
- alex@rawnet.com
|
140
|
+
- tom@rawnet.com
|
141
|
+
- paul.bowsher@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files:
|
145
|
+
- README
|
146
|
+
files:
|
147
|
+
- lib/contact_list.rb
|
148
|
+
- lib/contacts.rb
|
149
|
+
- lib/contacts/contact.rb
|
150
|
+
- lib/contacts/contact/facebook.rb
|
151
|
+
- lib/contacts/contact/google.rb
|
152
|
+
- lib/contacts/contact/linkedin.rb
|
153
|
+
- lib/contacts/contact/twitter.rb
|
154
|
+
- lib/contacts/contact/yahoo.rb
|
155
|
+
- lib/contacts/provider.rb
|
156
|
+
- lib/contacts/provider/base.rb
|
157
|
+
- lib/contacts/provider/facebook.rb
|
158
|
+
- lib/contacts/provider/google.rb
|
159
|
+
- lib/contacts/provider/linkedin.rb
|
160
|
+
- lib/contacts/provider/oauth.rb
|
161
|
+
- lib/contacts/provider/oauth2.rb
|
162
|
+
- lib/contacts/provider/twitter.rb
|
163
|
+
- lib/contacts/provider/yahoo.rb
|
164
|
+
- README
|
165
|
+
homepage:
|
166
|
+
licenses: []
|
167
|
+
post_install_message:
|
168
|
+
rdoc_options: []
|
169
|
+
require_paths:
|
170
|
+
- lib
|
171
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ! '>='
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
none: false
|
179
|
+
requirements:
|
180
|
+
- - ! '>='
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
requirements: []
|
184
|
+
rubyforge_project:
|
185
|
+
rubygems_version: 1.8.15
|
186
|
+
signing_key:
|
187
|
+
specification_version: 3
|
188
|
+
summary: Find contacts from multiple providers
|
189
|
+
test_files: []
|