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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2a59a907d0d36c0d0686a4b6455df055b334c54d
4
- data.tar.gz: f5e42916903f43b8c06b80d759d1f31771434db8
3
+ metadata.gz: 062e2ed0b9018682964f43fcaf0711c7c9147cc6
4
+ data.tar.gz: ac3392b93c651c531dd6f506ffc9e6d5c1f272fb
5
5
  SHA512:
6
- metadata.gz: 3bb1564f7250614c5d5c9e1413b514661860ff89460fa11f1aa1fddbb11f815ee3d967c95d971ac9f4a7bb396d35f0be43483cf0c9411186eb2762b6836c122a
7
- data.tar.gz: 13cb80adb5b232de7e6d2aa355b1754252d06d64c0d74cff0a53bde0ca9d7385b8a1853e5085921d3f7a67da234af25dd022a5352268c7c3d4e362cdab5b5959
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
@@ -1,5 +1,5 @@
1
1
  module Motion
2
2
  module Addressbook
3
- VERSION = "1.6.3"
3
+ VERSION = "1.7.0"
4
4
  end
5
5
  end
@@ -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"]
@@ -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, context)
147
- ABAddressBookRegisterExternalChangeCallback(ab, callback, context)
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 notify_changes(callback, context)
62
+ def observe!
62
63
  App.notification_center.observe KABDatabaseChangedExternallyNotification do |notification|
63
- callback.call(context)
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 == 'Alex'
21
+ @alex.first_name.should.equal 'Alex'
22
22
  @alex.last_name.should == 'Testy'
23
- @alex.email_values.should == [@data[:emails][0][:value]]
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 == 'Alex Testy'
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 == @alex.uid
42
+ alex.uid.should.equal @alex.uid
43
43
  alex.email_values.should.include? @email
44
- alex.first_name.should == 'Alex'
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 == 'Alex'
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 == 'Alex'
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 == 'Alex'
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 == (initial_people_count + 1)
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 == 'Alex'
124
+ alex.first_name.should.equal 'Alex'
125
125
  alex.last_name.should == 'Testy'
126
- alex.emails.attributes.map{|r| r[:value]}.should == [@email]
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 == [never_before_used_email]
134
- new_person.first_name.should == nil
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 == 'Mr. Alex Q. Testy III'
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 == 'Alex'
329
- @ab_person.department.should == 'Development'
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 == 'New First Name'
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
- `mv \"#{AB_PATH}\" "#{AB_PATH_BAK}"`
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
- `rm -rf \"#{AB_PATH}\"`
29
- `mv \"#{AB_PATH_BAK}\" "#{AB_PATH}"`
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.6.3
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-10-30 00:00:00.000000000 Z
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.0.5
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