googlecontacts 0.1.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/.document +5 -0
- data/.gitignore +10 -0
- data/LICENSE +20 -0
- data/README.md +41 -0
- data/README.rdoc +17 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/google_contacts.rb +15 -0
- data/lib/google_contacts/auth.rb +28 -0
- data/lib/google_contacts/base.rb +163 -0
- data/lib/google_contacts/contact.rb +32 -0
- data/lib/google_contacts/group.rb +9 -0
- data/lib/google_contacts/proxies/array.rb +46 -0
- data/lib/google_contacts/proxies/emails.rb +125 -0
- data/lib/google_contacts/proxies/hash.rb +41 -0
- data/lib/google_contacts/wrapper.rb +126 -0
- data/spec/assets/contacts_full.xml +60 -0
- data/spec/assets/groups_full.xml +58 -0
- data/spec/base_spec.rb +78 -0
- data/spec/contact_spec.rb +80 -0
- data/spec/group_spec.rb +18 -0
- data/spec/proxies/array_spec.rb +105 -0
- data/spec/proxies/emails_spec.rb +161 -0
- data/spec/proxies/hash_spec.rb +78 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/wrapper_spec.rb +75 -0
- metadata +129 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Contact do
|
4
|
+
describe "when loaded" do
|
5
|
+
before(:each) do
|
6
|
+
entries = parsed_asset('contacts_full').search('feed > entry')
|
7
|
+
@contacts = entries.map { |entry| Contact.new(wrapper, entry) }
|
8
|
+
@contact = @contacts.first
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should know its id" do
|
12
|
+
@contact.id.should == 'http://www.google.com/m8/feeds/contacts/liz%40gmail.com/base/c9012de'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should know when it was updated" do
|
16
|
+
@contact.updated_at.should == Time.utc(2008, 12, 10, 04, 45, 03, 331000)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should initialize with groups from xml" do
|
20
|
+
@contact.groups.should have(1).group
|
21
|
+
@contact.groups[0].should == 'http://www.google.com/m8/feeds/groups/liz%40gmail.com/base/270f'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should initialize extended properties" do
|
25
|
+
@contact[:pet].should == 'hamster'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not be changed? initially" do
|
29
|
+
@contact.changed?.should be_false
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "urls" do
|
33
|
+
it "should know its self url" do
|
34
|
+
@contact.url(:self).should == 'http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full/c9012de'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should know its edit url" do
|
38
|
+
@contact.url(:edit).should == 'http://www.google.com/m8/feeds/contacts/liz%40gmail.com/full/c9012de'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should know its photo url" do
|
42
|
+
@contact.url(:photo).should == 'http://www.google.com/m8/feeds/photos/media/liz%40gmail.com/c9012de'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "initializing" do
|
48
|
+
before(:each) do
|
49
|
+
@contact = Contact.new(wrapper)
|
50
|
+
@root = @contact.xml.document.root
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should create a new xml root node" do
|
54
|
+
@root.name.should == 'entry'
|
55
|
+
@root.namespace.href.should == 'http://www.w3.org/2005/Atom'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set the right category term" do
|
59
|
+
@root.at_xpath('./category')['term'].should == 'http://schemas.google.com/contact/2008#contact'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not have an id" do
|
63
|
+
@contact.id.should be_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not have an updated entry" do
|
67
|
+
@contact.updated_at.should be_nil
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should always be changed" do
|
71
|
+
@contact.changed?.should be_true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should be possible to set the default email address" do
|
75
|
+
@contact.email = 'foo@bar.com'
|
76
|
+
@contact.emails['foo@bar.com'].should be_primary
|
77
|
+
@contact.emails.size.should == 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/spec/group_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Group do
|
4
|
+
before(:each) do
|
5
|
+
entries = parsed_asset('groups_full').search('feed > entry')
|
6
|
+
@groups = entries.map { |entry| Group.new(wrapper, entry) }
|
7
|
+
@group = @groups.first
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should know its id" do
|
11
|
+
@group.id.should == 'http://www.google.com/m8/feeds/groups/jo%40gmail.com/base/6'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should know when it is a system group" do
|
15
|
+
@groups[0].system_group?.should be_true
|
16
|
+
@groups[1].system_group?.should be_false
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Proxies::Array do
|
4
|
+
describe "with existing entries" do
|
5
|
+
before(:each) do
|
6
|
+
create_proxy_from_xml %{<entry><group href="http://some.group" /></entry>}
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should initialize on creation" do
|
10
|
+
@proxy.size.should == 1
|
11
|
+
@proxy[0].should == 'http://some.group'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "without existing entries" do
|
16
|
+
before(:each) do
|
17
|
+
create_proxy_from_xml "<entry></entry>"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should allow pushing a plain value" do
|
21
|
+
@proxy << 'http://foo'
|
22
|
+
@proxy.should have(1).group
|
23
|
+
@proxy[0].should == 'http://foo'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should allow pushing an object that responds to href" do
|
27
|
+
@proxy << mock('Group', :href => 'http://foo')
|
28
|
+
@proxy.should have(1).group
|
29
|
+
@proxy[0].should == 'http://foo'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should filter duplicates" do
|
33
|
+
@proxy << 'http://foo'
|
34
|
+
@proxy << 'http://foo'
|
35
|
+
@proxy.should have(1).group
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should filter nils" do
|
39
|
+
@proxy << nil
|
40
|
+
@proxy.should have(:no).groups
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should allow clearing" do
|
44
|
+
@proxy << 'http://foo'
|
45
|
+
@proxy.clear
|
46
|
+
@proxy.should have(:no).groups
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "knows when it is changed" do
|
51
|
+
before(:each) do
|
52
|
+
create_proxy_from_xml <<-XML
|
53
|
+
<entry>
|
54
|
+
<group href="http://some.group" />
|
55
|
+
<group href="http://another.group" />
|
56
|
+
</entry>
|
57
|
+
XML
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should work after pushing a new entry" do
|
61
|
+
lambda {
|
62
|
+
@proxy << 'http://foo'
|
63
|
+
}.should change(@proxy, :changed?).from(false).to(true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not be changed when a duplicate is added" do
|
67
|
+
lambda {
|
68
|
+
@proxy << 'http://some.group'
|
69
|
+
}.should_not change(@proxy, :changed?).from(false)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not be changed when nils are added" do
|
73
|
+
lambda {
|
74
|
+
@proxy.concat [nil, nil]
|
75
|
+
}.should_not change(@proxy, :changed?).from(false)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not be influenced by order" do
|
79
|
+
lambda {
|
80
|
+
@proxy.replace ['http://another.group', 'http://some.group']
|
81
|
+
}.should_not change(@proxy, :changed?).from(false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "synchronize to xml document" do
|
86
|
+
before(:each) do
|
87
|
+
create_proxy_from_xml "<entry></entry>"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should update the group entries" do
|
91
|
+
@proxy << 'http://another.group'
|
92
|
+
@proxy << 'http://some.group'
|
93
|
+
@parent.expects(:remove_xml).with('./group')
|
94
|
+
@parent.expects(:insert_xml).with('group', { 'href' => 'http://another.group' })
|
95
|
+
@parent.expects(:insert_xml).with('group', { 'href' => 'http://some.group' })
|
96
|
+
@proxy.synchronize
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def create_proxy_from_xml(str)
|
101
|
+
@parent = mock('parent', :xml => Nokogiri::XML.parse(str).root)
|
102
|
+
@proxy = Proxies::Array.new(@parent, :tag => 'group', :attr => 'href')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Proxies::Emails do
|
4
|
+
describe "with existing entries" do
|
5
|
+
before(:each) do
|
6
|
+
create_proxy_from_xml <<-XML
|
7
|
+
<entry xmlns:gd="http://schemas.google.com/g/2005">
|
8
|
+
<gd:email label="Personal" displayName="Foo Bar"
|
9
|
+
address="foo@bar.example.com" />
|
10
|
+
<gd:email rel="http://schemas.google.com/g/2005#home"
|
11
|
+
address="fubar@gmail.com" primary="true"/>
|
12
|
+
</entry>
|
13
|
+
XML
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should initialize on creation" do
|
17
|
+
@proxy['foo@bar.example.com'].address .should == 'foo@bar.example.com'
|
18
|
+
@proxy['foo@bar.example.com'].name .should == 'Foo Bar'
|
19
|
+
@proxy['foo@bar.example.com'].label .should == 'Personal'
|
20
|
+
@proxy['foo@bar.example.com'].rel .should be_nil
|
21
|
+
@proxy['foo@bar.example.com'] .should_not be_primary
|
22
|
+
|
23
|
+
@proxy['fubar@gmail.com' ].address .should == 'fubar@gmail.com'
|
24
|
+
@proxy['fubar@gmail.com' ].name .should be_nil
|
25
|
+
@proxy['fubar@gmail.com' ].label .should be_nil
|
26
|
+
@proxy['fubar@gmail.com' ].rel .should == 'http://schemas.google.com/g/2005#home'
|
27
|
+
@proxy['fubar@gmail.com' ] .should be_primary
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should initially be unchanged" do
|
31
|
+
@proxy.changed?.should be_false
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "should be changed" do
|
35
|
+
after(:each) do
|
36
|
+
@proxy.changed?.should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "when switching primary" do
|
40
|
+
@proxy['foo@bar.example.com'].primary!
|
41
|
+
end
|
42
|
+
|
43
|
+
it "when modifying name" do
|
44
|
+
@proxy['foo@bar.example.com'].name = 'Quux'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "when modifying rel" do
|
48
|
+
@proxy['foo@bar.example.com'].rel = 'http://some.rel'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "when adding a new address" do
|
52
|
+
@proxy << 'john@doe.com'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "when removing an address" do
|
56
|
+
@proxy.delete 'foo@bar.example.com'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "without existing entries" do
|
62
|
+
before(:each) do
|
63
|
+
create_proxy_from_xml <<-XML
|
64
|
+
<entry xmlns:gd="http://schemas.google.com/g/2005">
|
65
|
+
</entry>
|
66
|
+
XML
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should be possible to add email address" do
|
70
|
+
lambda {
|
71
|
+
@proxy['foo@bar.com']
|
72
|
+
}.should change(@proxy, :size).by(1)
|
73
|
+
|
74
|
+
lambda {
|
75
|
+
@proxy << 'quux@bar.com'
|
76
|
+
}.should change(@proxy, :size).by(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise when adding a duplicate" do
|
80
|
+
@proxy << 'quux@bar.com'
|
81
|
+
lambda {
|
82
|
+
@proxy << 'quux@bar.com'
|
83
|
+
}.should raise_error
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should provide sensible defaults for new addresses" do
|
87
|
+
@proxy['john@doe.com'].address.should == 'john@doe.com'
|
88
|
+
@proxy['john@doe.com'].rel.should == 'http://schemas.google.com/g/2005#home'
|
89
|
+
@proxy['john@doe.com'].label.should be_nil
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should set the first created entry to be primary" do
|
93
|
+
@proxy['john@doe.com'].should be_primary
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should only allow one entry to be primary" do
|
97
|
+
@proxy['john@doe.com'].should be_primary
|
98
|
+
@proxy['jane@doe.com'].should_not be_primary
|
99
|
+
@proxy['jane@doe.com'].primary!
|
100
|
+
@proxy['john@doe.com'].should_not be_primary
|
101
|
+
@proxy['jane@doe.com'].should be_primary
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should only allow either rel or label to be set" do
|
105
|
+
@proxy['john@doe.com'].rel = 'foo'
|
106
|
+
@proxy['john@doe.com'].label = 'foo'
|
107
|
+
@proxy['john@doe.com'].rel.should be_nil
|
108
|
+
|
109
|
+
@proxy['john@doe.com'].label = 'foo'
|
110
|
+
@proxy['john@doe.com'].rel = 'foo'
|
111
|
+
@proxy['john@doe.com'].label.should be_nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should raise when attempting to modify the address" do
|
115
|
+
lambda {
|
116
|
+
@proxy['john@doe.com'].address = 'foo'
|
117
|
+
}.should raise_error(/cannot modify/i)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should allow email addresses to be removed" do
|
121
|
+
@proxy << 'john@doe.com'
|
122
|
+
lambda {
|
123
|
+
@proxy.delete('john@doe.com')
|
124
|
+
}.should change(@proxy, :size).from(1).to(0)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "synchronize to xml document" do
|
129
|
+
before(:each) do
|
130
|
+
create_proxy_from_xml <<-XML
|
131
|
+
<entry xmlns:gd="http://schemas.google.com/g/2005">
|
132
|
+
</entry>
|
133
|
+
XML
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should clear existing email tags" do
|
137
|
+
@proxy << 'john@doe.com'
|
138
|
+
@parent.expects(:remove_xml).with('./gd:email')
|
139
|
+
@parent.stubs(:insert_xml)
|
140
|
+
@proxy.synchronize
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should add every email address" do
|
144
|
+
@proxy << 'john@doe.com'
|
145
|
+
@proxy << 'jane@doe.com'
|
146
|
+
|
147
|
+
@parent.stubs(:remove_xml)
|
148
|
+
@parent.expects(:insert_xml).with('gd:email', has_entries(
|
149
|
+
'address' => 'john@doe.com',
|
150
|
+
'primary' => 'true'))
|
151
|
+
@parent.expects(:insert_xml).with('gd:email', has_entries(
|
152
|
+
'address' => 'jane@doe.com'))
|
153
|
+
@proxy.synchronize
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def create_proxy_from_xml(str)
|
158
|
+
@parent = stub('parent', :xml => Nokogiri::XML.parse(str).root)
|
159
|
+
@proxy = Proxies::Emails.new(@parent)
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Proxies::Hash do
|
4
|
+
describe "with existing entries" do
|
5
|
+
before(:each) do
|
6
|
+
create_proxy_from_xml <<-XML
|
7
|
+
<entry>
|
8
|
+
<prop name="foo" value="bar" />
|
9
|
+
</entry>
|
10
|
+
XML
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should initialize on creation" do
|
14
|
+
@proxy[:foo].should == 'bar'
|
15
|
+
@proxy.should have(1).entry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "without existing entries" do
|
20
|
+
before(:each) do
|
21
|
+
create_proxy_from_xml "<entry></entry>"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow setting a value" do
|
25
|
+
@proxy[:foo] = 'bar'
|
26
|
+
@proxy.should have(1).entry
|
27
|
+
@proxy[:foo].should == 'bar'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow clearing" do
|
31
|
+
@proxy[:foo] = 'bar'
|
32
|
+
@proxy.clear
|
33
|
+
@proxy.should have(:no).entries
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "knows when it is changed" do
|
38
|
+
before(:each) do
|
39
|
+
create_proxy_from_xml <<-XML
|
40
|
+
<entry>
|
41
|
+
<prop name="foo" value="foo" />
|
42
|
+
</entry>
|
43
|
+
XML
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should work when a new value was set" do
|
47
|
+
lambda {
|
48
|
+
@proxy[:foo] = 'quux'
|
49
|
+
}.should change(@proxy, :changed?).from(false).to(true)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not be changed when the new value equals the old one" do
|
53
|
+
lambda {
|
54
|
+
@proxy[:foo] = 'foo'
|
55
|
+
}.should_not change(@proxy, :changed?).from(false)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "synchronize to xml document" do
|
60
|
+
before(:each) do
|
61
|
+
create_proxy_from_xml "<entry></entry>"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should update the group entries" do
|
65
|
+
@proxy[:foo] = 'quux'
|
66
|
+
@proxy[:baz] = 'bar'
|
67
|
+
@parent.expects(:remove_xml).with('./prop')
|
68
|
+
@parent.expects(:insert_xml).with('prop', { 'name' => 'foo', 'value' => 'quux' })
|
69
|
+
@parent.expects(:insert_xml).with('prop', { 'name' => 'baz', 'value' => 'bar' })
|
70
|
+
@proxy.synchronize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_proxy_from_xml(str)
|
75
|
+
@parent = stub('parent', :xml => Nokogiri::XML.parse(str).root)
|
76
|
+
@proxy = Proxies::Hash.new(@parent, :tag => 'prop', :key => 'name', :value => 'value')
|
77
|
+
end
|
78
|
+
end
|
data/spec/spec.opts
ADDED