motion-addressbook 1.6.3 → 1.7.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.
- checksums.yaml +4 -4
- data/README.md +30 -0
- data/lib/motion-addressbook/version.rb +1 -1
- data/motion-addressbook.gemspec +1 -0
- data/motion/address_book.rb +6 -1
- data/motion/address_book/ios/addr_book.rb +10 -2
- data/motion/address_book/osx/addr_book.rb +3 -2
- data/spec/ios/address_book/person_spec.rb +41 -19
- data/spec/ios/helpers/spec_helper.rb +24 -8
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 062e2ed0b9018682964f43fcaf0711c7c9147cc6
|
4
|
+
data.tar.gz: ac3392b93c651c531dd6f506ffc9e6d5c1f272fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe803b3bf9eeae54d44b33ce8bd8f1c9016ca5ce62ba36c47a15da3b2fa0a09cca2141e7314c10b756a0a42afa0fbd9b64df8cf5b3b523963858de94721ef85a
|
7
|
+
data.tar.gz: 0e3dd574fd3eb184f6408843613315816095cb69f4653465d056f29d0c8ae2d128c03eb782fbfe516d7eb9b4f616fc270971927914d61df16e6b942d362980ec
|
data/README.md
CHANGED
@@ -175,6 +175,15 @@ alex.job_title = 'RubyMotion Developer'
|
|
175
175
|
alex.save
|
176
176
|
```
|
177
177
|
|
178
|
+
Or to alter all the attributes at once (preserve the record identifier
|
179
|
+
but change some or all of the values):
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
alex = AddressBook::Person.find_by_email('alex@example.com')
|
183
|
+
alex.replace({:first_name=>"Alex", :last_name=>"Rider", ...})
|
184
|
+
alex.save
|
185
|
+
```
|
186
|
+
|
178
187
|
### Contact Groups
|
179
188
|
|
180
189
|
```ruby
|
@@ -186,6 +195,27 @@ g.members
|
|
186
195
|
=> [#<AddressBook::Person:2: {:first_name=>"Daniel", :last_name=>"Higgins", ...}>]
|
187
196
|
```
|
188
197
|
|
198
|
+
### Notifications (\* iOS only \*)
|
199
|
+
|
200
|
+
The iOS Address Book does not deliver notifications of changes through
|
201
|
+
the standard Notification Center. `motion-addressbook` wraps the
|
202
|
+
framework `ABAddressBookRegisterExternalChangeCallback` call with an
|
203
|
+
optional handler that converts the update event to an iOS
|
204
|
+
notification.
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
ab.observe!
|
208
|
+
|
209
|
+
App.notification_center.observe :addressbook_updated do |notification|
|
210
|
+
NSLog "Address Book was changed!"
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
The notification must be explicitly enabled in your application. In
|
215
|
+
some cases iOS appears to trigger multiple notifications for the same
|
216
|
+
change event, and if you are doing many changes at once you will
|
217
|
+
receive a long stream of notifications.
|
218
|
+
|
189
219
|
## Contributing
|
190
220
|
|
191
221
|
1. Fork it
|
data/motion-addressbook.gemspec
CHANGED
@@ -4,6 +4,7 @@ require File.expand_path('../lib/motion-addressbook/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = "motion-addressbook"
|
6
6
|
gem.version = Motion::Addressbook::VERSION
|
7
|
+
gem.license = 'MIT'
|
7
8
|
|
8
9
|
gem.authors = ["Alex Rothenberg", "Jason May"]
|
9
10
|
gem.email = ["alex@alexrothenberg.com", "jmay@pobox.com"]
|
data/motion/address_book.rb
CHANGED
@@ -13,9 +13,14 @@ module AddressBook
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def instance
|
17
|
+
@instance ||= AddrBook.new
|
18
|
+
end
|
19
|
+
|
16
20
|
def count
|
17
21
|
if App.ios?
|
18
|
-
ABAddressBookGetPersonCount(address_book)
|
22
|
+
# ABAddressBookGetPersonCount(address_book)
|
23
|
+
instance.count
|
19
24
|
else
|
20
25
|
address_book.count
|
21
26
|
end
|
@@ -28,6 +28,14 @@ module AddressBook
|
|
28
28
|
def activate!
|
29
29
|
@ab = LiveAddrBook.new(AddressBook.address_book)
|
30
30
|
end
|
31
|
+
|
32
|
+
def observe!
|
33
|
+
@notifier = Proc.new do |ab_instance, always_nil, context|
|
34
|
+
App.notification_center.post :addressbook_updated, self
|
35
|
+
end
|
36
|
+
ab.register_callback(@notifier)
|
37
|
+
end
|
38
|
+
|
31
39
|
def authorized?
|
32
40
|
AddressBook.authorized?
|
33
41
|
end
|
@@ -143,8 +151,8 @@ module AddressBook
|
|
143
151
|
def sources
|
144
152
|
ABAddressBookCopyArrayOfAllSources(ab)
|
145
153
|
end
|
146
|
-
def register_callback(callback
|
147
|
-
ABAddressBookRegisterExternalChangeCallback(ab, callback,
|
154
|
+
def register_callback(callback)
|
155
|
+
ABAddressBookRegisterExternalChangeCallback(ab, callback, nil)
|
148
156
|
end
|
149
157
|
end
|
150
158
|
end
|
@@ -4,6 +4,7 @@ module AddressBook
|
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@ab = ABAddressBook.addressBook
|
7
|
+
yield self if block_given?
|
7
8
|
end
|
8
9
|
def people(opts = {})
|
9
10
|
if opts[:local]
|
@@ -58,9 +59,9 @@ module AddressBook
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
def
|
62
|
+
def observe!
|
62
63
|
App.notification_center.observe KABDatabaseChangedExternallyNotification do |notification|
|
63
|
-
|
64
|
+
App.notification_center.post :addressbook_updated, self
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
@@ -18,12 +18,12 @@ describe AddressBook::Person do
|
|
18
18
|
@alex.should.not.exists?
|
19
19
|
end
|
20
20
|
it 'should have initial values' do
|
21
|
-
@alex.first_name.should
|
21
|
+
@alex.first_name.should.equal 'Alex'
|
22
22
|
@alex.last_name.should == 'Testy'
|
23
|
-
@alex.email_values.should
|
23
|
+
@alex.email_values.should.equal [@data[:emails][0][:value]]
|
24
24
|
end
|
25
25
|
it 'should have a composite name' do
|
26
|
-
@alex.composite_name.should
|
26
|
+
@alex.composite_name.should.equal 'Alex Testy'
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -39,9 +39,9 @@ describe AddressBook::Person do
|
|
39
39
|
it 'should find match' do
|
40
40
|
@alex.uid.should.not.be.nil
|
41
41
|
alex = AddressBook::Person.find_by_uid @alex.uid
|
42
|
-
alex.uid.should
|
42
|
+
alex.uid.should.equal @alex.uid
|
43
43
|
alex.email_values.should.include? @email
|
44
|
-
alex.first_name.should
|
44
|
+
alex.first_name.should.equal 'Alex'
|
45
45
|
alex.last_name.should == 'Testy'
|
46
46
|
end
|
47
47
|
end
|
@@ -52,13 +52,13 @@ describe AddressBook::Person do
|
|
52
52
|
alexes.each do |alex|
|
53
53
|
alex.uid.should != nil
|
54
54
|
alex.email_values.should.include? @email
|
55
|
-
alex.first_name.should
|
55
|
+
alex.first_name.should.equal 'Alex'
|
56
56
|
alex.last_name.should == 'Testy'
|
57
57
|
end
|
58
58
|
end
|
59
59
|
it 'should give empty list when nothing matches' do
|
60
60
|
alexes = AddressBook::Person.find_all_by_email unique_email
|
61
|
-
alexes.should
|
61
|
+
alexes.should.equal []
|
62
62
|
end
|
63
63
|
end
|
64
64
|
describe '.find_by_email' do
|
@@ -66,7 +66,7 @@ describe AddressBook::Person do
|
|
66
66
|
alex = AddressBook::Person.find_by_email @email
|
67
67
|
alex.uid.should.not.be.nil
|
68
68
|
alex.email_values.should.include? @email
|
69
|
-
alex.first_name.should
|
69
|
+
alex.first_name.should.equal 'Alex'
|
70
70
|
alex.last_name.should == 'Testy'
|
71
71
|
end
|
72
72
|
it 'should give empty list when nothing matches' do
|
@@ -81,13 +81,13 @@ describe AddressBook::Person do
|
|
81
81
|
alexes.each do |alex|
|
82
82
|
alex.uid.should != nil
|
83
83
|
alex.email_values.should.include? @email
|
84
|
-
alex.first_name.should
|
84
|
+
alex.first_name.should.equal 'Alex'
|
85
85
|
alex.last_name.should == 'Testy'
|
86
86
|
end
|
87
87
|
end
|
88
88
|
it 'should give empty list when nothing matches' do
|
89
89
|
alexes = AddressBook::Person.where(:email => unique_email)
|
90
|
-
alexes.should
|
90
|
+
alexes.should.equal []
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -102,7 +102,7 @@ describe AddressBook::Person do
|
|
102
102
|
it 'should get bigger when we create another' do
|
103
103
|
initial_people_count = AddressBook::Person.all.size
|
104
104
|
@person = AddressBook::Person.create({:first_name => 'Alex2', :last_name=>'Rothenberg2'})
|
105
|
-
AddressBook::Person.all.size.should
|
105
|
+
AddressBook::Person.all.size.should.equal (initial_people_count + 1)
|
106
106
|
@person.delete!
|
107
107
|
end
|
108
108
|
end
|
@@ -121,17 +121,17 @@ describe AddressBook::Person do
|
|
121
121
|
alex = AddressBook::Person.find_or_new_by_email(@email)
|
122
122
|
alex.should.not.be.new_record
|
123
123
|
alex.uid.should != nil
|
124
|
-
alex.first_name.should
|
124
|
+
alex.first_name.should.equal 'Alex'
|
125
125
|
alex.last_name.should == 'Testy'
|
126
|
-
alex.emails.attributes.map{|r| r[:value]}.should
|
126
|
+
alex.emails.attributes.map{|r| r[:value]}.should.equal [@email]
|
127
127
|
end
|
128
128
|
it 'should return new person when no match found' do
|
129
129
|
never_before_used_email = unique_email
|
130
130
|
new_person = AddressBook::Person.find_or_new_by_email(never_before_used_email)
|
131
131
|
new_person.should.be.new_record
|
132
132
|
new_person.should.not.exists
|
133
|
-
new_person.email_values.should
|
134
|
-
new_person.first_name.should
|
133
|
+
new_person.email_values.should.equal [never_before_used_email]
|
134
|
+
new_person.first_name.should.equal nil
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|
@@ -284,7 +284,7 @@ describe AddressBook::Person do
|
|
284
284
|
end
|
285
285
|
|
286
286
|
it 'should have a composite name' do
|
287
|
-
@ab_person.composite_name.should
|
287
|
+
@ab_person.composite_name.should.equal 'Mr. Alex Q. Testy III'
|
288
288
|
end
|
289
289
|
|
290
290
|
it 'should be able to count the emails' do
|
@@ -325,8 +325,8 @@ describe AddressBook::Person do
|
|
325
325
|
it 'should know it is not new' do
|
326
326
|
@ab_person.should.not.be.new_record
|
327
327
|
@ab_person.should.be.exists
|
328
|
-
@ab_person.first_name.should
|
329
|
-
@ab_person.department.should
|
328
|
+
@ab_person.first_name.should.equal 'Alex'
|
329
|
+
@ab_person.department.should.equal 'Development'
|
330
330
|
end
|
331
331
|
|
332
332
|
it 'should not change ID' do
|
@@ -341,7 +341,7 @@ describe AddressBook::Person do
|
|
341
341
|
|
342
342
|
it 'should be able to get each of the single value fields' do
|
343
343
|
@match = AddressBook::Person.find_by_email(@ab_person.email_values.first)
|
344
|
-
@match.first_name.should
|
344
|
+
@match.first_name.should.equal 'New First Name'
|
345
345
|
@match.uid.should.equal @ab_person.uid
|
346
346
|
end
|
347
347
|
end
|
@@ -494,4 +494,26 @@ describe AddressBook::Person do
|
|
494
494
|
ordered.should.equal [@p1, @p2, @p4, @p5, @p3]
|
495
495
|
end
|
496
496
|
end
|
497
|
+
|
498
|
+
describe "notifications" do
|
499
|
+
before do
|
500
|
+
@ab1 = AddressBook::AddrBook.new
|
501
|
+
@ab2 = AddressBook::AddrBook.new
|
502
|
+
@ab1.observe!
|
503
|
+
@ab2.observe!
|
504
|
+
@notifications = 0
|
505
|
+
App.notification_center.observe :addressbook_updated do |notification|
|
506
|
+
@notifications += 1
|
507
|
+
end
|
508
|
+
|
509
|
+
@alice = @ab2.create_person({first_name: 'Alice'})
|
510
|
+
@bob = @ab1.create_person({first_name: 'Bob'})
|
511
|
+
@alice.delete!
|
512
|
+
@bob.delete!
|
513
|
+
end
|
514
|
+
|
515
|
+
it "should be notified of every change" do
|
516
|
+
@notifications.should.equal 4
|
517
|
+
end
|
518
|
+
end
|
497
519
|
end
|
@@ -2,6 +2,15 @@
|
|
2
2
|
# instance from destruction when the spec suite runs. Specifically,
|
3
3
|
# the contents of the iOS Address Book, which is global to all
|
4
4
|
# applications.
|
5
|
+
#
|
6
|
+
# WARNING: Altering the simulator configuration at runtime is a risky
|
7
|
+
# practice. If we use `Kernel.system` instead of backquotes when
|
8
|
+
# invoking `mv` and `rm` below, the simulator throws a warning:
|
9
|
+
#
|
10
|
+
# The iOS Simulator libSystem was initialized out of order. This
|
11
|
+
# is most often caused by running host executables or inserting
|
12
|
+
# host dylibs. In the future, this will cause an abort.
|
13
|
+
#
|
5
14
|
|
6
15
|
SIMULATOR_ROOT = "#{ENV['HOME']}/../.."
|
7
16
|
AB_PATH = SIMULATOR_ROOT + "/Library/AddressBook"
|
@@ -12,21 +21,28 @@ def protect_existing_address_book
|
|
12
21
|
# iOS layer protects them, but shelling out is still allowed so we
|
13
22
|
# can alter the world that way.
|
14
23
|
|
15
|
-
unless AddressBook.authorized?
|
16
|
-
warn "BLOCKING FOR AUTHORIZATION"
|
17
|
-
AddressBook.request_authorization
|
18
|
-
end
|
19
|
-
|
20
24
|
warn "PROTECTING EXISTING ADDRESS BOOK IN SIMULATOR"
|
21
25
|
|
22
|
-
`
|
26
|
+
`rm -rf \"#{AB_PATH_BAK}\"`
|
27
|
+
`mv \"#{AB_PATH}\" \"#{AB_PATH_BAK}\"`
|
28
|
+
# Kernel.system "rm -rf \"#{AB_PATH_BAK}\""
|
29
|
+
# Kernel.system "mv \"#{AB_PATH}\" \"#{AB_PATH_BAK}\""
|
23
30
|
end
|
24
31
|
|
25
32
|
at_exit do
|
26
33
|
warn "RESTORING ORIGINAL ADDRESS BOOK IN SIMULATOR"
|
27
34
|
|
28
|
-
|
29
|
-
|
35
|
+
Kernel.system "rm -rf \"#{AB_PATH}\""
|
36
|
+
Kernel.system "mv \"#{AB_PATH_BAK}\" \"#{AB_PATH}\""
|
37
|
+
end
|
38
|
+
|
39
|
+
def wait_for_authorization
|
40
|
+
@semaphore = Dispatch::Semaphore.new(0)
|
41
|
+
AddressBook::AddrBook.new do
|
42
|
+
@semaphore.signal
|
43
|
+
end
|
44
|
+
@semaphore.wait
|
30
45
|
end
|
31
46
|
|
32
47
|
protect_existing_address_book
|
48
|
+
wait_for_authorization
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-addressbook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Rothenberg
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bubble-wrap
|
@@ -95,7 +95,8 @@ files:
|
|
95
95
|
- spec/osx/helpers/hacks.rb
|
96
96
|
- spec/osx/helpers/person_helpers.rb
|
97
97
|
homepage: ''
|
98
|
-
licenses:
|
98
|
+
licenses:
|
99
|
+
- MIT
|
99
100
|
metadata: {}
|
100
101
|
post_install_message:
|
101
102
|
rdoc_options: []
|
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
114
|
version: '0'
|
114
115
|
requirements: []
|
115
116
|
rubyforge_project:
|
116
|
-
rubygems_version: 2.
|
117
|
+
rubygems_version: 2.1.11
|
117
118
|
signing_key:
|
118
119
|
specification_version: 4
|
119
120
|
summary: A RubyMotion wrapper around the iOS & OSX Address Book frameworks
|