muck-portablecontacts 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Pelle Braendgaard
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.
@@ -0,0 +1,53 @@
1
+ = Portable Contacts
2
+
3
+ This is a slightly modified fork of the original project primarily using changes from: https://github.com/kickstarter/portablecontacts.
4
+ To install this gem use:
5
+
6
+ gem install muck-portablecontacts
7
+
8
+ This is a ruby client implementation of Portable Contacts a standard for exchanging profile and address book data.
9
+
10
+ The current draft of the standard is http://portablecontacts.net/draft-spec.html
11
+
12
+ Portable Contacts is currently supported by Plaxo, Google, Yahoo, and most OpenSocial containers.
13
+
14
+ This client uses OAuth and JSON exclusively. There are no plans for supporting basic authentication or xml.
15
+
16
+ To use it you need an OAuth AccessToken (see http://oauth.rubyforge.org/). If you are using Rails, you may find the easiest way of doing this as using the OAuth Plugin http://stakeventures.com/articles/2009/07/21/consuming-oauth-intelligently-in-rails
17
+
18
+ The Gem requires:
19
+
20
+ * ActiveSupport
21
+ * OAuth Gem
22
+ * JSON gem
23
+
24
+ == Example Code
25
+
26
+ @access_token = ... # instantiate access token
27
+
28
+ @client = PortableContacts::Client.new "http://www-opensocial.googleusercontent.com/api/people", @access_token
29
+
30
+ # Get users profile
31
+
32
+ @profile = @client.me
33
+
34
+ puts @profile.display_name
35
+ => "Bob Sample"
36
+
37
+ # Get users contacts
38
+ @contacts = @client.all
39
+
40
+ == Note on Patches/Pull Requests
41
+
42
+ * Fork the project.
43
+ * Make your feature addition or bug fix.
44
+ * Add tests for it. This is important so I don't break it in a
45
+ future version unintentionally.
46
+ * Commit, do not mess with rakefile, version, or history.
47
+ (if you want to have your own version, that is fine but
48
+ bump version in a commit by itself I can ignore when I pull)
49
+ * Send me a pull request. Bonus points for topic branches.
50
+
51
+ == Copyright
52
+
53
+ Copyright (c) 2009 Pelle Braendgaard. See LICENSE for details.
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "muck-portablecontacts"
8
+ gem.summary = %Q{Portable Contacts client for Ruby}
9
+ gem.description = %Q{A client library for the portable contacts standard}
10
+ gem.email = "pelleb@gmail.com"
11
+ gem.homepage = "http://github.com/pelle/portablecontacts"
12
+ gem.authors = ["Pelle Braendgaard"]
13
+ gem.rubyforge_project = "portablecontact"
14
+ gem.add_dependency "activesupport"
15
+ gem.add_dependency('oauth', '>= 0.3.6')
16
+ gem.add_dependency('json')
17
+ gem.add_development_dependency "rspec"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :spec => :check_dependencies
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ if File.exist?('VERSION')
44
+ version = File.read('VERSION')
45
+ else
46
+ version = ""
47
+ end
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "portablecontacts #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,228 @@
1
+ require 'uri'
2
+ require 'json'
3
+
4
+ begin
5
+ require 'active_support/core_ext/string' # Rails 3+
6
+ rescue LoadError
7
+ require 'activesupport' # older versions of Rails
8
+ end
9
+
10
+ module PortableContacts
11
+
12
+ # This is the main PortableContacts Client.
13
+ #
14
+ # == query options
15
+ #
16
+ # The library supports the various filter and sorting parameters. The format of this may change for this library, so limit use to :
17
+ # :count and :start_index for now.
18
+ #
19
+ class Client
20
+ attr :base_url, :access_token
21
+
22
+ # First parameter is the portable contacts base_url. Find this on your PortableContact providers documentation or through XRDS.
23
+ #
24
+ # * Google's is http://www-opensocial.googleusercontent.com/api/people
25
+ # * Yahoo's is http://appstore.apps.yahooapis.com/social/rest/people
26
+ #
27
+ # The second parameter is an OAuth::AccessToken instantiated for the provider.
28
+ #
29
+ def initialize(base_url, access_token)
30
+ @base_url = base_url
31
+ @access_token = access_token
32
+ end
33
+
34
+ # Returns the AccessToken users contact details. Note this requests all fields from provider
35
+ # Returns an PortableContacts::Person object
36
+ def me(options={})
37
+ single(get("/@me/@self", options.reverse_merge(:fields => :all)))
38
+ end
39
+
40
+ # Returns the contacts of the user. It defaults to all fields and 100 entries
41
+ #
42
+ # @contacts = @client.all # return 100 contacts
43
+ # @contacts = @client.all :count=>10 # return 10 contacts
44
+ # @contacts = @client.all :count=>10, :start_index=>10 # returns the second page of 10 contacts
45
+ # puts @contacts.total_entries # returns the total amount of contacts on the server
46
+ #
47
+ # Returns a PortableContacts::Collection which is a subclass of Array
48
+ def all(options={})
49
+ collection(get("/@me/@all", options.reverse_merge(:fields => :all, :count => 100)))
50
+ end
51
+
52
+ # Returns the full contact infor for a particular userid. TODO This is not tested well
53
+ # Returns an PortableContacts::Person object
54
+ def find(id, options={})
55
+ single(get("/@me/@all/#{id}", options.reverse_merge(:fields => :all)))
56
+ end
57
+
58
+ private
59
+
60
+ def get(path, options={})
61
+ parse(@access_token.get(url_for(path) + options_for(options), {'Accept' => 'application/json'}))
62
+ end
63
+
64
+ def url_for(path)
65
+ "#{@base_url}#{path}"
66
+ end
67
+
68
+ def options_for(options={})
69
+ return "" if options.nil? || options.empty?
70
+ options.symbolize_keys! if options.respond_to? :symbolize_keys!
71
+ "?#{(fields_options(options[:fields]) + filter_options(options[:filter]) + sort_options(options[:sort]) + pagination_options(options)).sort.join("&")}"
72
+ end
73
+
74
+ def single(data)
75
+ if data.is_a?(Hash) && data['entry']
76
+ PortableContacts::Person.new(data['entry'])
77
+ else
78
+ data
79
+ end
80
+ end
81
+
82
+ def collection(data)
83
+ if data.is_a?(Hash)
84
+ PortableContacts::Collection.new data
85
+ else
86
+ data
87
+ end
88
+ end
89
+
90
+ def parse(response)
91
+ return false unless response
92
+ if ["200","201"].include? response.code
93
+ unless response.body.blank?
94
+ JSON.parse(response.body)
95
+ else
96
+ true
97
+ end
98
+ else
99
+ false
100
+ end
101
+ end
102
+
103
+ def fields_options(options = nil)
104
+ return [] if options.nil?
105
+ if options.is_a? Symbol
106
+ return ["fields=#{(options == :all ? "@all": URI.escape(options.to_s))}"]
107
+ elsif options.respond_to?(:collect)
108
+ ["fields=#{options.collect{|f| f.to_s}.join(',')}"]
109
+ else
110
+ []
111
+ end
112
+ end
113
+
114
+ def sort_options(options = nil)
115
+ return [] if options.nil?
116
+ if options.is_a? Symbol
117
+ return ["sortBy=#{URI.escape(options.to_s)}"]
118
+ end
119
+ if options.is_a?(Hash) and options[:by] || options['by']
120
+ return to_query_list(options, "sort")
121
+ end
122
+ return []
123
+ end
124
+
125
+ def pagination_options(options = nil)
126
+ return [] if options.nil? || options.empty?
127
+ params = []
128
+ if options[:count]
129
+ params << "count=#{options[:count]}"
130
+ end
131
+ if options[:start_index]
132
+ params << "startIndex=#{options[:start_index]}"
133
+ end
134
+ params
135
+ end
136
+
137
+ def filter_options(options = {})
138
+ return [] if options.nil? || options.empty?
139
+ options[:op] ||= "equals"
140
+ to_query_list(options, "filter")
141
+ end
142
+
143
+ def to_query_list(params, pre_fix = '')
144
+ params.collect{ |k,v| "#{pre_fix}#{k.to_s.capitalize}=#{URI.escape(v.to_s)}"}
145
+ end
146
+ end
147
+
148
+ class Person
149
+
150
+ # Encapsulates a person. Each of the portable contact and opensocial contact fields has a rubyfied (underscored) accessor method.
151
+ #
152
+ # @person = @person.display_name
153
+ #
154
+
155
+ def initialize(data={})
156
+ @data = data
157
+ end
158
+
159
+ SINGULAR_FIELDS = [
160
+ # Portable contacts singular fields
161
+ :id, :display_name, :name, :nickname, :published, :updated, :birthday, :anniversary,
162
+ :gender, :note, :preferred_username, :utc_offset, :connected,
163
+
164
+ # OpenSocial singular fields
165
+ :about_me, :body_type, :current_location, :drinker, :ethnicity, :fashion, :happiest_when,
166
+ :humor, :living_arrangement, :looking_for, :profile_song, :profile_video, :relationship_status,
167
+ :religion, :romance, :scared_of, :sexual_orientation, :smoker, :status
168
+ ]
169
+ PLURAL_FIELDS = [
170
+ # Portable contacts plural fields
171
+ :emails, :urls, :phone_numbers, :ims, :photos, :tags, :relationships, :addresses,
172
+ :organizations, :accounts,
173
+
174
+ # OpenSocial plural fields
175
+ :activities, :books, :cars, :children, :food, :heroes, :interests, :job_interests,
176
+ :languages, :languages_spoken, :movies, :music, :pets, :political_views, :quotes,
177
+ :sports, :turn_offs, :turn_ons, :tv_shows
178
+ ]
179
+
180
+ ENTRY_FIELDS = SINGULAR_FIELDS + PLURAL_FIELDS
181
+
182
+ def self.define_getter(field)
183
+ class_eval <<-END, __FILE__, __LINE__
184
+ def #{field}
185
+ @data['#{field.to_s.camelize(:lower)}']
186
+ end
187
+ END
188
+ end
189
+
190
+ ENTRY_FIELDS.each do |f|
191
+ define_getter(f)
192
+ end
193
+
194
+ def [](key)
195
+ @data[key.to_s.camelize(:lower)]
196
+ end
197
+
198
+ # primary email address
199
+ def email
200
+ @email ||= begin
201
+ (emails.detect {|e| e['primary'] == 'true'} || emails.first)["value"] unless emails.blank?
202
+ end
203
+ end
204
+
205
+ protected
206
+
207
+ def method_missing(method, *args)
208
+ if @data.has_key?(method.to_s.camelize(:lower))
209
+ self.class.define_getter(method)
210
+ return send(method)
211
+ end
212
+ super
213
+ end
214
+ end
215
+
216
+ class Collection < Array
217
+ attr_reader :total_entries, :per_page, :start_index
218
+
219
+ def initialize(data)
220
+ super data["entry"].collect{|e| PortableContacts::Person.new(e) }
221
+ @total_entries = data["totalResults"].to_i
222
+ @per_page = data["itemsPerPage"].to_i
223
+ @start_index = data["startIndex"].to_i
224
+ end
225
+
226
+ end
227
+
228
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__),'portable_contacts')
@@ -0,0 +1,64 @@
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{muck-portablecontacts}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pelle Braendgaard"]
12
+ s.date = %q{2011-04-21}
13
+ s.description = %q{A client library for the portable contacts standard}
14
+ s.email = %q{pelleb@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/portable_contacts.rb",
26
+ "lib/portablecontacts.rb",
27
+ "muck-portablecontacts.gemspec",
28
+ "spec/fixtures/multiple.json",
29
+ "spec/fixtures/single.json",
30
+ "spec/portable_contacts_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/pelle/portablecontacts}
34
+ s.require_paths = ["lib"]
35
+ s.rubyforge_project = %q{portablecontact}
36
+ s.rubygems_version = %q{1.6.0}
37
+ s.summary = %q{Portable Contacts client for Ruby}
38
+ s.test_files = [
39
+ "spec/portable_contacts_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
47
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
48
+ s.add_runtime_dependency(%q<oauth>, [">= 0.3.6"])
49
+ s.add_runtime_dependency(%q<json>, [">= 0"])
50
+ s.add_development_dependency(%q<rspec>, [">= 0"])
51
+ else
52
+ s.add_dependency(%q<activesupport>, [">= 0"])
53
+ s.add_dependency(%q<oauth>, [">= 0.3.6"])
54
+ s.add_dependency(%q<json>, [">= 0"])
55
+ s.add_dependency(%q<rspec>, [">= 0"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<activesupport>, [">= 0"])
59
+ s.add_dependency(%q<oauth>, [">= 0.3.6"])
60
+ s.add_dependency(%q<json>, [">= 0"])
61
+ s.add_dependency(%q<rspec>, [">= 0"])
62
+ end
63
+ end
64
+
@@ -0,0 +1,96 @@
1
+ {
2
+ "startIndex": 10,
3
+ "itemsPerPage": 10,
4
+ "totalResults": 12,
5
+ "entry": [
6
+ {
7
+ "id": "123",
8
+ "displayName": "Minimal Contact"
9
+ },
10
+ {
11
+ "id": "703887",
12
+ "displayName": "Mork Hashimoto",
13
+ "name": {
14
+ "familyName": "Hashimoto",
15
+ "givenName": "Mork"
16
+ },
17
+ "birthday": "0000-01-16",
18
+ "gender": "male",
19
+ "drinker": "heavily",
20
+ "tags": [
21
+ "plaxo guy",
22
+ "favorite"
23
+ ],
24
+ "emails": [
25
+ {
26
+ "value": "mhashimoto-04@plaxo.com",
27
+ "type": "work",
28
+ "primary": "true"
29
+ },
30
+ {
31
+ "value": "mhashimoto-04@plaxo.com",
32
+ "type": "home"
33
+ },
34
+ {
35
+ "value": "mhashimoto@plaxo.com",
36
+ "type": "home"
37
+ }
38
+ ],
39
+ "urls": [
40
+ {
41
+ "value": "http://www.seeyellow.com",
42
+ "type": "work"
43
+ },
44
+ {
45
+ "value": "http://www.angryalien.com",
46
+ "type": "home"
47
+ }
48
+ ],
49
+ "phoneNumbers": [
50
+ {
51
+ "value": "KLONDIKE5",
52
+ "type": "work"
53
+ },
54
+ {
55
+ "value": "650-123-4567",
56
+ "type": "mobile"
57
+ }
58
+ ],
59
+ "photos": [
60
+ {
61
+ "value": "http://sample.site.org/photos/12345.jpg",
62
+ "type": "thumbnail"
63
+ }
64
+ ],
65
+ "ims": [
66
+ {
67
+ "value": "plaxodev8",
68
+ "type": "aim"
69
+ }
70
+ ],
71
+ "addresses": [
72
+ {
73
+ "type": "home",
74
+ "streetAddress": "742 Evergreen Terrace\nSuite 123",
75
+ "locality": "Springfield",
76
+ "region": "VT",
77
+ "postalCode": "12345",
78
+ "country": "USA",
79
+ "formatted": "742 Evergreen Terrace\nSuite 123\nSpringfield, VT 12345 USA"
80
+ }
81
+ ],
82
+ "organizations": [
83
+ {
84
+ "name": "Burns Worldwide",
85
+ "title": "Head Bee Guy"
86
+ }
87
+ ],
88
+ "accounts": [
89
+ {
90
+ "domain": "plaxo.com",
91
+ "userid": "2706"
92
+ }
93
+ ]
94
+ }
95
+ ]
96
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "entry":
3
+ {
4
+ "id": "703887",
5
+ "displayName": "Mork Hashimoto",
6
+ "name": {
7
+ "familyName": "Hashimoto",
8
+ "givenName": "Mork"
9
+ },
10
+ "birthday": "0000-01-16",
11
+ "gender": "male",
12
+ "drinker": "heavily",
13
+ "tags": [
14
+ "plaxo guy",
15
+ "favorite"
16
+ ],
17
+ "emails": [
18
+ {
19
+ "value": "mhashimoto-work@plaxo.com",
20
+ "type": "work"
21
+ },
22
+ {
23
+ "value": "mhashimoto-home@plaxo.com",
24
+ "type": "home"
25
+ },
26
+ {
27
+ "value": "mhashimoto@plaxo.com",
28
+ "type": "home",
29
+ "primary": "true"
30
+ }
31
+ ],
32
+ "urls": [
33
+ {
34
+ "value": "http://www.seeyellow.com",
35
+ "type": "work"
36
+ },
37
+ {
38
+ "value": "http://www.angryalien.com",
39
+ "type": "home"
40
+ }
41
+ ],
42
+ "phoneNumbers": [
43
+ {
44
+ "value": "KLONDIKE5",
45
+ "type": "work"
46
+ },
47
+ {
48
+ "value": "650-123-4567",
49
+ "type": "mobile"
50
+ }
51
+ ],
52
+ "photos": [
53
+ {
54
+ "value": "http://sample.site.org/photos/12345.jpg",
55
+ "type": "thumbnail"
56
+ }
57
+ ],
58
+ "ims": [
59
+ {
60
+ "value": "plaxodev8",
61
+ "type": "aim"
62
+ }
63
+ ],
64
+ "addresses": [
65
+ {
66
+ "type": "home",
67
+ "streetAddress": "742 Evergreen Terrace\nSuite 123",
68
+ "locality": "Springfield",
69
+ "region": "VT",
70
+ "postalCode": "12345",
71
+ "country": "USA",
72
+ "formatted": "742 Evergreen Terrace\nSuite 123\nSpringfield, VT 12345 USA"
73
+ }
74
+ ],
75
+ "organizations": [
76
+ {
77
+ "name": "Burns Worldwide",
78
+ "title": "Head Bee Guy"
79
+ }
80
+ ],
81
+ "accounts": [
82
+ {
83
+ "domain": "plaxo.com",
84
+ "userid": "2706"
85
+ }
86
+ ]
87
+ }
88
+ }
@@ -0,0 +1,232 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe PortableContacts::Client do
4
+
5
+ def access_token
6
+ @access_token ||= mock("accesstoken")
7
+ end
8
+
9
+ before(:each) do
10
+ @client = PortableContacts::Client.new "http://sample.com/portable_contacts", access_token
11
+ end
12
+
13
+ ["/@me/@all", "/@me/@all/(id)", "/@me/@self"].each do |path|
14
+
15
+ it "should generate url for #{path}" do
16
+ @client.send( :url_for, path).should=="http://sample.com/portable_contacts#{path}"
17
+ end
18
+
19
+ end
20
+
21
+ it "should return empty string for no options" do
22
+ @client.send(:options_for).should==""
23
+ end
24
+
25
+ describe "fields" do
26
+ it "should handle all" do
27
+ @client.send(:options_for, :fields=>:all).should=="?fields=@all"
28
+ end
29
+
30
+ it "should handle single field" do
31
+ @client.send(:options_for, :fields=>:name).should=="?fields=name"
32
+ end
33
+
34
+ it "should handle array of fields" do
35
+ @client.send(:options_for, :fields=>[:name,:emails,:nickname,:id]).should=="?fields=name,emails,nickname,id"
36
+ end
37
+
38
+ end
39
+
40
+ describe "filtering" do
41
+
42
+ it "should handle default operation" do
43
+ @client.send(:options_for, :filter=>{:by=>:name,:value=>"Bob"}).should=="?filterBy=name&filterOp=equals&filterValue=Bob"
44
+ end
45
+
46
+ ["displayName","id","nickname"].each do |field|
47
+ ["equals", "contains", "startsWith", "present"].each do |op|
48
+
49
+ it "should create filter for #{field} with #{op}" do
50
+ @client.send(:options_for, :filter=>{:by=>field, :op=>op, :value=>"bb"}).should=="?filterBy=#{field}&filterOp=#{op}&filterValue=bb"
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "sorting" do
58
+
59
+ it "should handle straight sort" do
60
+ @client.send(:options_for, :sort=>:name).should=="?sortBy=name"
61
+ end
62
+
63
+ it "should handle sort as a hash" do
64
+ @client.send(:options_for, :sort=>{:by=>:name}).should=="?sortBy=name"
65
+ end
66
+
67
+ it "should handle sort as a hash" do
68
+ @client.send(:options_for, :sort=>{:by=>:name,:order=>:descending}).should=="?sortBy=name&sortOrder=descending"
69
+ end
70
+
71
+ end
72
+
73
+ describe "paging" do
74
+
75
+ it "should handle count" do
76
+ @client.send(:options_for, :count=>133).should=="?count=133"
77
+ end
78
+
79
+ it "should handle startIndex" do
80
+ @client.send(:options_for, :start_index=>20).should=="?startIndex=20"
81
+ end
82
+
83
+ it "should handle count with startIndex" do
84
+ @client.send(:options_for, :count=>10,:start_index=>40).should=="?count=10&startIndex=40"
85
+ end
86
+
87
+ end
88
+
89
+ it "should handle all parameters at once" do
90
+ @client.send(:options_for,
91
+ :fields=>[:name,:emails,:nickname,:id],
92
+ :filter=>{:by=>:name,:value=>"Bob"},
93
+ :sort=>{:by=>:name,:order=>:descending},
94
+ :count=>10,:start_index=>40).should=="?count=10&fields=name,emails,nickname,id&filterBy=name&filterOp=equals&filterValue=Bob&sortBy=name&sortOrder=descending&startIndex=40"
95
+ end
96
+
97
+ describe "Rails Specific" do
98
+ it "should handle all parameters at once with string keys" do
99
+ @client.send(:options_for,
100
+ 'fields'=>['name','emails','nickname','id'],
101
+ 'filter'=>{'by'=>'name','value'=>"Bob"},
102
+ 'sort'=>{'by'=>'name','order'=>'descending'},
103
+ 'count'=>10,'start_index'=>40).should=="?count=10&fields=name,emails,nickname,id&filterBy=name&filterOp=equals&filterValue=Bob&sortBy=name&sortOrder=descending&startIndex=40"
104
+ end
105
+ end
106
+
107
+ describe "parsing" do
108
+
109
+ def parse_json_file(name)
110
+ File.open File.join(File.dirname(__FILE__),'fixtures', name) do |f|
111
+ JSON.parse f.read
112
+ end
113
+ end
114
+
115
+ describe "single entry response" do
116
+ before(:each) do
117
+ @entry = @client.send(:single,parse_json_file('single.json'))
118
+ end
119
+
120
+ it "should contain displayName" do
121
+ @entry.display_name.should=="Mork Hashimoto"
122
+ end
123
+
124
+ it "should contain tags" do
125
+ @entry.tags.should == [
126
+ "plaxo guy",
127
+ "favorite"
128
+ ]
129
+ end
130
+
131
+ it "should emails" do
132
+ @entry.emails.should == [
133
+ {
134
+ "value"=> "mhashimoto-work@plaxo.com",
135
+ "type"=> "work"
136
+ },
137
+ {
138
+ "value"=> "mhashimoto-home@plaxo.com",
139
+ "type"=> "home"
140
+ },
141
+ {
142
+ "value"=> "mhashimoto@plaxo.com",
143
+ "type"=> "home",
144
+ "primary"=> "true"
145
+ }
146
+ ]
147
+ end
148
+
149
+ it "should have email" do
150
+ @entry.email.should=="mhashimoto@plaxo.com"
151
+ end
152
+ end
153
+
154
+ describe "multiple entries" do
155
+ before(:each) do
156
+ @entries = @client.send(:collection,parse_json_file('multiple.json'))
157
+ end
158
+
159
+ it "should have correct start index" do
160
+ @entries.start_index.should == 10
161
+ end
162
+
163
+ it "should have correct per page" do
164
+ @entries.per_page.should == 10
165
+ end
166
+
167
+ it "should have correct total entries" do
168
+ @entries.total_entries.should == 12
169
+ end
170
+
171
+ it "should have 2 enties" do
172
+ @entries.length.should==2
173
+ end
174
+
175
+ describe "first entry" do
176
+
177
+ before(:each) do
178
+ @entry=@entries.first
179
+ end
180
+
181
+ it "should have correct id" do
182
+ @entry.id.should=="123"
183
+ end
184
+
185
+ it "should contain displayName" do
186
+ @entry.display_name.should=="Minimal Contact"
187
+ end
188
+
189
+ end
190
+
191
+ # The same as data in single entry
192
+ describe "last entry" do
193
+
194
+ before(:each) do
195
+ @entry=@entries.last
196
+ end
197
+ it "should contain displayName" do
198
+ @entry.display_name.should=="Mork Hashimoto"
199
+ end
200
+
201
+ it "should contain tags" do
202
+ @entry.tags.should == [
203
+ "plaxo guy",
204
+ "favorite"
205
+ ]
206
+ end
207
+
208
+ it "should emails" do
209
+ @entry.emails.should == [
210
+ {
211
+ "value"=> "mhashimoto-04@plaxo.com",
212
+ "type"=> "work",
213
+ "primary"=> "true"
214
+ },
215
+ {
216
+ "value"=> "mhashimoto-04@plaxo.com",
217
+ "type"=> "home"
218
+ },
219
+ {
220
+ "value"=> "mhashimoto@plaxo.com",
221
+ "type"=> "home"
222
+ }
223
+ ]
224
+ end
225
+
226
+ it "should have email" do
227
+ @entry.email.should=="mhashimoto-04@plaxo.com"
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ require 'portablecontacts'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: muck-portablecontacts
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Pelle Braendgaard
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-21 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: oauth
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 31
44
+ segments:
45
+ - 0
46
+ - 3
47
+ - 6
48
+ version: 0.3.6
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: json
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :runtime
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: rspec
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: A client library for the portable contacts standard
80
+ email: pelleb@gmail.com
81
+ executables: []
82
+
83
+ extensions: []
84
+
85
+ extra_rdoc_files:
86
+ - LICENSE
87
+ - README.rdoc
88
+ files:
89
+ - .document
90
+ - LICENSE
91
+ - README.rdoc
92
+ - Rakefile
93
+ - VERSION
94
+ - lib/portable_contacts.rb
95
+ - lib/portablecontacts.rb
96
+ - muck-portablecontacts.gemspec
97
+ - spec/fixtures/multiple.json
98
+ - spec/fixtures/single.json
99
+ - spec/portable_contacts_spec.rb
100
+ - spec/spec_helper.rb
101
+ has_rdoc: true
102
+ homepage: http://github.com/pelle/portablecontacts
103
+ licenses: []
104
+
105
+ post_install_message:
106
+ rdoc_options: []
107
+
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ hash: 3
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project: portablecontact
131
+ rubygems_version: 1.6.0
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Portable Contacts client for Ruby
135
+ test_files:
136
+ - spec/portable_contacts_spec.rb
137
+ - spec/spec_helper.rb