motion-addressbook 1.5.0 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c5f98fa75e972433a15e036925c3411517e2c6d6
4
+ data.tar.gz: 7585741f2762ec9275c74b2a40e70075dee8a2fd
5
+ SHA512:
6
+ metadata.gz: 6d3f794f0adefee07007dd44591f274a34b1fae7b06c341ba73b5dea7d2136962711be09818ff27d8adef86525d900e95a6c599b40ce16c9665fced6c651ec40
7
+ data.tar.gz: 192065725a196bd2bb8e05bddb436b458c479bbea4933a9870a84c40e37f96e34adc5d2a41a034878fe8b56a92c55283d338170cbb28b1faf15aff42683635c1
data/.gitignore CHANGED
@@ -8,8 +8,9 @@ Gemfile.lock
8
8
  vendor/Pods/Pods.xcodeproj/project.pbxproj
9
9
  vendor/Pods/build*
10
10
 
11
- abhack/*.bridgesupport
12
- abhack/build*
13
-
14
11
  .dat*.00*
15
12
  pkg
13
+ .projectile
14
+ doc
15
+
16
+ TAGS
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
- # Addressbook for RubyMotion[![Build Status](https://secure.travis-ci.org/alexrothenberg/motion-addressbook.png)](http://travis-ci.org/alexrothenberg/motion-addressbook) [![Code Climate](https://codeclimate.com/github/alexrothenberg/motion-addressbook.png)](https://codeclimate.com/github/alexrothenberg/motion-addressbook) [![Gem Version](https://badge.fury.io/rb/motion-addressbook.png)](http://badge.fury.io/rb/motion-addressbook)
1
+ # Addressbook for RubyMotion
2
2
 
3
- A RubyMotion wrapper around the iOS Address Book framework for RubyMotion apps.
3
+ [![Build Status](https://secure.travis-ci.org/alexrothenberg/motion-addressbook.png)](http://travis-ci.org/alexrothenberg/motion-addressbook)
4
+ [![Code Climate](https://codeclimate.com/github/alexrothenberg/motion-addressbook.png)](https://codeclimate.com/github/alexrothenberg/motion-addressbook)
5
+ [![Gem Version](https://badge.fury.io/rb/motion-addressbook.png)](http://badge.fury.io/rb/motion-addressbook)
6
+
7
+ A RubyMotion wrapper around the iOS and OSX Address Book frameworks for RubyMotion apps.
4
8
 
5
9
  Apple's Address Book Programming Guide for [iOS](http://developer.apple.com/library/ios/#DOCUMENTATION/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Introduction.html)
6
10
  or for [OSX](https://developer.apple.com/library/mac/#documentation/userexperience/Conceptual/AddressBook/AddressBook.html#//apple_ref/doc/uid/10000117i)
@@ -33,26 +37,30 @@ Or install it yourself (remember to add the bubble-wrap dependency) as:
33
37
 
34
38
  ### Requesting access
35
39
 
36
- iOS 6 requires asking the user for permission before it allows an app to access the AddressBook. There are 3 ways to interact with this
40
+ iOS 6/7 requires that the user give permission before it allows an app to access the AddressBook.
37
41
 
38
42
  1 - Let the gem take care of it for you
39
43
 
40
44
  ```ruby
41
- people = AddressBook::Person.all
42
- # A dialog may be presented to the user before "people" was returned
45
+ ab = AddressBook::AddrBook.new
46
+ # ...do something else...
47
+ people = ab.people
43
48
  ```
44
49
 
50
+ The `people` method will raise an exception if called while
51
+ authorization has not been granted.
52
+
45
53
  2 - Manually decide when to ask the user for authorization
46
54
 
47
55
  ```ruby
48
56
  # asking whether we are already authorized
49
57
  if AddressBook.authorized?
50
- puts "This app is authorized?"
58
+ puts "This app is authorized!"
51
59
  else
52
- puts "This app is not authorized?"
60
+ puts "This app is not authorized!"
53
61
  end
54
62
 
55
- # ask the user to authorize us
63
+ # ask the user to authorize us (blocking)
56
64
  if AddressBook.request_authorization
57
65
  # do something now that the user has said "yes"
58
66
  else
@@ -75,6 +83,9 @@ end
75
83
  # do something here before the user has decided
76
84
  ```
77
85
 
86
+ The iOS6 simulator does not demand AddressBook authorization. The iOS7
87
+ simulator does.
88
+
78
89
  ### Showing the ABPeoplePicker
79
90
 
80
91
  ```ruby
@@ -87,67 +98,76 @@ AddressBook.pick { |person|
87
98
  }
88
99
  ```
89
100
 
90
- ### Instantiating a person object
101
+ You can also specify the presenting controller:
91
102
 
92
- There are 3 ways to instantiate a person object
103
+ ```ruby
104
+ AddressBook.pick presenter: self do |person|
105
+ ...
106
+ end
107
+ ```
108
+
109
+ ### Working with Person objects
93
110
 
94
- ### To get a new person not yet connected to the iOS Address Book
111
+ Get a list of existing people from the Address Book. On IOS, results
112
+ are sorted using the sort order (First/Last or Last/First) chosen by
113
+ the user in iOS Settings.
95
114
 
96
115
  ```ruby
97
- AddressBook::Person.new
98
- # => #<AddressBook::Person:0x8c67ca0 @attributes={:first_name=>nil, :last_name=>nil, :job_title=>nil, :department=>nil, :organization=>nil} @new_record=true @ab_person=#<__NSCFType:0x6d832e0>>
116
+ ab = AddressBook::AddrBook.new
117
+ ab.people
118
+ => [#<AddressBook::Person:3: {:first_name=>"John", :last_name=>"Appleseed", ...}>, ...]
99
119
  ```
100
120
 
101
- ### To get a list of existing people from the iOS Address Book
121
+ Create a new Person and save to the Address Book.
122
+
123
+ Note that Person records can take multiple values for email addresses, phone
124
+ numbers, postal address, social profiles, and instant messaging
125
+ profiles.
126
+
127
+ ```ruby
128
+ ab.create_person(:first_name => 'Alex', :last_name => 'Rothenberg', :emails => [{ :value => 'alex@example.com', :label => 'Home'}], :phones => [{ :value => '9920149993', :label => 'Mobile'}])
129
+ => #<AddressBook::Person:7: {:first_name=>"Alex", :last_name=>"Rothenberg", ...}>
130
+ ```
102
131
 
103
- Get all people with `.all`
132
+ Construct a new blank Person but do not store it immediately in the Address Book.
104
133
 
105
134
  ```ruby
106
- AddressBook::Person.all
107
- # => [#<AddressBook::Person:0x6d55e90 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0x6df8bf0>>,
108
- # #<AddressBook::Person:0x6d550a0 @attributes={:first_name=>"Laurent", :last_name=>"Sansonetti", :job_title=>nil, :department=>nil, :organization=>"HipByte"} @ab_person=#<__NSCFType:0x6df97d0>>]
135
+ ab.new_person(:first_name => "Bob")
136
+ => #<AddressBook::Person:-1: {:first_name=>"Bob"}>
137
+ ab.last_name = 'Brown'
138
+ ab.save
139
+ => #<AddressBook::Person:9: {:first_name=>"Bob", :last_name=>"Brown"}>
109
140
  ```
110
141
 
111
142
  Get a list of all people matching one attribute with `.find_all_by_XXX`
112
143
 
113
144
  ```ruby
114
145
  AddressBook::Person.find_all_by_email('alex@example.com')
115
- # => [#<AddressBook::Person:0x6d55e90 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0x6df8bf0>>]
146
+ => [#<AddressBook::Person:14: {:first_name=>"Alex", :last_name=>"Rothenberg", ...}>]
116
147
  ```
117
148
 
118
- Get the first person matching one attribute with `find_by_XXX`
149
+ Get the first person matching one attribute with `.find_by_XXX`
119
150
 
120
151
  ```ruby
121
152
  AddressBook::Person.find_by_email('alex@example.com')
122
- # => #<AddressBook::Person:0x6d55e90 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0x6df8bf0>>
153
+ => #<AddressBook::Person:14: {:first_name=>"Alex", :last_name=>"Rothenberg", ...}>]
123
154
  ```
124
155
 
125
156
  Get a list of all people matching several attributes with `.where`
126
157
 
127
158
  ```ruby
128
159
  AddressBook::Person.where(:email => 'alex@example.com', :first_name => 'Alex')
129
- # => [#<AddressBook::Person:0x6d55e90 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0x6df8bf0>>]
160
+ => [#<AddressBook::Person:14: {:first_name=>"Alex", :last_name=>"Rothenberg", ...}>]
130
161
  ```
131
162
 
132
- To look for an existing person or get a new one if none is found `find_or_new_by_XXX`
163
+ Look for an existing person or get a new one if none is found `find_or_new_by_XXX`
133
164
 
134
165
  ```ruby
135
166
  AddressBook::Person.find_or_new_by_email('alex@example.com')
136
- # => #<AddressBook::Person:0xe4e3a80 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0xe4bbef0>>
167
+ => #<AddressBook::Person:17: {:first_name=>"Alex", :last_name=>"Rothenberg", ...}>]
137
168
  ```
138
169
 
139
- ### Create a new Contact and save in Contacts app
140
-
141
- ```ruby
142
- AddressBook::Person.create(:first_name => 'Alex', :last_name => 'Rothenberg', :email => [{ :value => 'alex@example.com', :label => 'Home'}], , :phones => [{ :value => '9920149993', :label => 'Mobile'}])
143
- # => #<AddressBook::Person:0xe4e3a80 @attributes={:first_name=>"Alex", :last_name=>"Rothenberg", :job_title=>nil, :department=>nil, :organization=>nil} @ab_person=#<__NSCFType:0xe4bbef0>>
144
-
145
- # Multiple emails/phones ex.
146
-
147
- AddressBook::Person.create(:first_name => 'Alex', :last_name => 'Rothenberg', :emails => ["a@mail.com", "b@gmail.com", "c@gmail.com", {:value => 'ashish@gmail.com', :label => 'Personal'} ], :phones => ['1234','2345','4567'])
148
- => #<AddressBook::Person:0x9ce23b0 @address_book=#<__NSCFType:0x9ce2660> @ab_person=#<__NSCFType:0x9ce2450> @attributes=nil>
149
- ```
150
- ### Update existing contact
170
+ ### Update existing Person
151
171
 
152
172
  ```ruby
153
173
  alex = AddressBook::Person.find_by_email('alex@example.com')
@@ -155,6 +175,17 @@ alex.job_title = 'RubyMotion Developer'
155
175
  alex.save
156
176
  ```
157
177
 
178
+ ### Contact Groups
179
+
180
+ ```ruby
181
+ ab.groups
182
+ => [#<AddressBook::Group:1:Friends: 1 members>, #<AddressBook::Group:2:Work: 0 members>]
183
+
184
+ g = ab.groups.first
185
+ g.members
186
+ => [#<AddressBook::Person:2: {:first_name=>"Daniel", :last_name=>"Higgins", ...}>]
187
+ ```
188
+
158
189
  ## Contributing
159
190
 
160
191
  1. Fork it
@@ -1,5 +1,5 @@
1
1
  module Motion
2
2
  module Addressbook
3
- VERSION = "1.5.0"
3
+ VERSION = "1.6.2"
4
4
  end
5
5
  end
@@ -1,5 +1,18 @@
1
1
  require "motion-addressbook/version"
2
2
 
3
+ # RubyMotion bug RM-81 was fixed for 2.8; motion-addressbook
4
+ if Gem::Version.new(Motion::Version) < Gem::Version.new("2.8")
5
+ raise <<EOT
6
+ motion-addressbook requires at least RubyMotion version 2.8.
7
+
8
+ If you cannot upgrade RubyMotion please use an older version of this gem.
9
+ Add the following to your Gemfile:
10
+
11
+ gem 'motion-addressbook', '<= 1.5.0'
12
+
13
+ EOT
14
+ end
15
+
3
16
  BubbleWrap.require 'motion/address_book.rb' do
4
17
  file('motion/address_book.rb').uses_framework('AddressBook')
5
18
  end
@@ -12,11 +25,6 @@ BubbleWrap.require_ios do
12
25
  BW.require 'motion/address_book/ios/multi_valued.rb'
13
26
  BW.require 'motion/address_book/ios/source.rb'
14
27
 
15
- # This is an iOS-specific RubyMotion bug workaround.
16
- Motion::Project::App.setup do |app|
17
- app.vendor_project(File.expand_path(File.join(File.dirname(__FILE__), '../abhack')), :static)
18
- end
19
-
20
28
  BW.require 'motion/address_book/ios/picker.rb' do
21
29
  file('motion/address_book/ios/picker.rb').uses_framework('AddressBookUI')
22
30
  end
@@ -2,57 +2,149 @@ module AddressBook
2
2
  class AddrBook
3
3
  attr_reader :ab
4
4
 
5
- def initialize
6
- @ab = AddressBook.address_book
7
- end
8
- def people(opts = {})
9
- if opts[:source]
10
- ABAddressBookCopyArrayOfAllPeopleInSource(ab, opts[:source].ab_source).map do |ab_person|
11
- AddressBook::Person.new({}, ab_person, :address_book => ab)
5
+ def initialize(&block)
6
+ @ab = NullAddrBook
7
+ if authorized?
8
+ activate!
9
+ if block_given?
10
+ yield self
11
+ end
12
+ elsif block
13
+ # asynchronous auth
14
+ AddressBook.request_authorization do |granted|
15
+ if granted
16
+ activate!
17
+ block.call(self)
18
+ end
12
19
  end
13
20
  else
14
- ABAddressBookCopyArrayOfAllPeople(ab).map do |ab_person|
15
- AddressBook::Person.new({}, ab_person, :address_book => ab)
21
+ # synchronous auth
22
+ if native_ab = AddressBook.address_book
23
+ @ab = LiveAddrBook.new(native_ab)
16
24
  end
17
25
  end
18
26
  end
27
+
28
+ def activate!
29
+ @ab = LiveAddrBook.new(AddressBook.address_book)
30
+ end
31
+ def authorized?
32
+ AddressBook.authorized?
33
+ end
34
+
35
+ def auth!
36
+ raise "iOS Address Book authorization is required." if @ab.nil?
37
+ end
38
+
39
+ def people(opts = {}, &block)
40
+ ordered_list = ab_people(opts).map { |p| Person.new(nil, p, address_book: ab.ab) }
41
+ if block
42
+ ordered_list.sort_by { |p| block.call(p) }
43
+ else
44
+ ordered_list
45
+ end
46
+ end
19
47
  def count
20
- ABAddressBookGetPersonCount(@ab)
48
+ ab.person_count
21
49
  end
22
50
  def new_person(attributes)
23
- Person.new(attributes, nil, :address_book => @ab)
51
+ Person.new(attributes, nil, :address_book => ab.ab)
24
52
  end
25
53
  def create_person(attributes)
26
- p = Person.new(attributes, nil, :address_book => @ab)
54
+ p = new_person(attributes)
27
55
  p.save
28
56
  p
29
57
  end
30
58
  def person(id)
31
- (p = ABAddressBookGetPersonWithRecordID(ab, id)) && Person.new(nil, p, :address_book => ab)
59
+ (p = ab.person_with_id(id)) && Person.new(nil, p, :address_book => ab.ab)
32
60
  end
33
61
  def changedSince(timestamp)
34
62
  people.select {|p| p.modification_date > timestamp}
35
63
  end
36
64
 
37
65
  def groups
38
- ABAddressBookCopyArrayOfAllGroups(@ab).map do |ab_group|
39
- AddressBook::Group.new(:ab_group => ab_group, :address_book => @ab)
66
+ ab.all_groups.map do |ab_group|
67
+ AddressBook::Group.new(:ab_group => ab_group, :address_book => ab.ab)
40
68
  end
41
69
  end
70
+ def group_count
71
+ ab.group_count
72
+ end
42
73
  def new_group(attributes)
43
- AddressBook::Group.new(:attributes => attributes, :address_book => @ab)
74
+ AddressBook::Group.new(:attributes => attributes, :address_book => ab.ab)
44
75
  end
45
76
  def group(id)
46
- (g = ABAddressBookGetGroupWithRecordID(ab, id)) && Group.new(:ab_group => g, :address_book => @ab)
77
+ (g = ab.group_with_id(id)) && Group.new(:ab_group => g, :address_book => ab.ab)
47
78
  end
48
79
 
49
80
  def notify_changes(callback, context)
50
- ABAddressBookRegisterExternalChangeCallback(ab, callback, context)
81
+ ab.register_callback(callback, context)
82
+ end
83
+
84
+ def sources
85
+ ab.sources.map {|s| Source.new(s)}
86
+ end
87
+
88
+ def inspect
89
+ "#<#{self.class}:#{"0x%0x" % object_id} #{ab.status}>"
90
+ end
91
+
92
+ private
93
+
94
+ def ab_people(opts = {})
95
+ ab_source = opts[:source]
96
+ ordering = opts.fetch(:ordering) { ABPersonGetSortOrdering() }
97
+
98
+ ab_people = if ab_source
99
+ ab.all_people_in_source(ab_source)
100
+ else
101
+ ab.all_people
102
+ end
103
+
104
+ ab_people.sort! { |x, y| ABPersonComparePeopleByName(x, y, ordering) }
105
+ ab_people
106
+ end
107
+ end
108
+
109
+ class NullAddrBook
110
+ def self.status; "pending"; end
111
+ def self.method_missing(*args)
112
+ raise SecurityError, "iOS Address Book authorization is required."
51
113
  end
114
+ end
52
115
 
116
+ class LiveAddrBook
117
+ attr_reader :ab
118
+ def initialize(ab)
119
+ @ab = ab
120
+ end
121
+ def status; "live"; end
122
+ def all_people
123
+ ABAddressBookCopyArrayOfAllPeople(ab)
124
+ end
125
+ def all_people_in_source(source)
126
+ ABAddressBookCopyArrayOfAllPeopleInSource(ab, source)
127
+ end
128
+ def person_with_id(id)
129
+ ABAddressBookGetPersonWithRecordID(ab, id)
130
+ end
131
+ def person_count
132
+ ABAddressBookGetPersonCount(ab)
133
+ end
134
+ def all_groups
135
+ ABAddressBookCopyArrayOfAllGroups(ab)
136
+ end
137
+ def group_count
138
+ ABAddressBookGetGroupCount(ab)
139
+ end
140
+ def group_with_id(id)
141
+ ABAddressBookGetGroupWithRecordID(ab, id)
142
+ end
53
143
  def sources
54
- # ABAddressBookCopyArrayOfAllSources(ab).map {|s| ABRecordCopyValue(s, KABSourceTypeProperty)}
55
- ABAddressBookCopyArrayOfAllSources(ab).map {|s| Source.new(s)}
144
+ ABAddressBookCopyArrayOfAllSources(ab)
145
+ end
146
+ def register_callback(callback, context)
147
+ ABAddressBookRegisterExternalChangeCallback(ab, callback, context)
56
148
  end
57
149
  end
58
150
  end
@@ -5,23 +5,12 @@
5
5
  #
6
6
  module AddressBook
7
7
  class Group
8
- attr_reader :attributes, :error
8
+ attr_reader :attributes, :error, :address_book
9
9
 
10
10
  def initialize(opts)
11
- @address_book = opts[:address_book]
12
- if opts[:ab_group]
13
- # import existing
14
- @ab_group = opts[:ab_group]
15
- @attributes = nil
16
- else
17
- # create new
18
- @ab_group = nil
19
- @attributes = opts[:attributes]
20
- end
21
- end
22
-
23
- def address_book
24
- @address_book ||= AddressBook.address_book
11
+ @address_book = opts.fetch(:address_book) { AddressBook.address_book }
12
+ @ab_group = opts[:ab_group]
13
+ @attributes = opts[:attributes]
25
14
  end
26
15
 
27
16
  def save
@@ -41,23 +30,30 @@ module AddressBook
41
30
  unless new?
42
31
  ABAddressBookRemoveRecord(address_book, ab_group, error)
43
32
  ABAddressBookSave(address_book, error)
44
- @ab_group = nil
33
+ @ab_group = :deleted
45
34
  self
46
35
  end
47
36
  end
48
37
 
38
+ def deleted?
39
+ @ab_group == :deleted
40
+ end
41
+
49
42
  def ab_group
50
43
  @ab_group || convert_dict_to_ab
51
44
  end
52
45
  alias :ab_record :ab_group
53
46
 
54
47
  def uid
55
- ABRecordGetRecordID(ab_group)
48
+ deleted? ? nil : ABRecordGetRecordID(ab_group)
56
49
  end
57
50
 
58
51
  def name
59
52
  ABRecordCopyValue(ab_group, KABGroupNameProperty)
60
53
  end
54
+ def name=(newname)
55
+ ABRecordSetValue(ab_group, KABGroupNameProperty, newname, error)
56
+ end
61
57
 
62
58
  def size
63
59
  members.count
@@ -77,11 +73,30 @@ module AddressBook
77
73
  end
78
74
  end
79
75
 
76
+ def add(*items)
77
+ items.each { |item| self << item }
78
+ self
79
+ end
80
+
81
+ def remove(person_or_group)
82
+ ABGroupRemoveMember(ab_group, person_or_group.ab_record, error)
83
+ self
84
+ end
85
+
80
86
  def <<(person_or_group)
81
87
  raise ArgumentError, "Must save member before adding to group" if person_or_group.new?
82
88
  ABGroupAddMember(ab_group, person_or_group.ab_record, error)
83
89
  end
84
90
 
91
+ def to_s
92
+ if deleted?
93
+ "#<#{self.class}:DELETED>"
94
+ else
95
+ "#<#{self.class}:#{uid}:#{name}: #{size} members>"
96
+ end
97
+ end
98
+ alias :inspect :to_s
99
+
85
100
  private
86
101
 
87
102
  def convert_dict_to_ab
@@ -1,5 +1,7 @@
1
1
  module AddressBook
2
2
  class MultiValued
3
+ include Enumerable
4
+
3
5
  attr_reader :mv_type
4
6
 
5
7
  def initialize(opts)
@@ -23,6 +25,19 @@ module AddressBook
23
25
  def attributes
24
26
  @attributes ||= convert_multi_value_into_dictionary
25
27
  end
28
+ def to_ary
29
+ attributes
30
+ end
31
+ def [](index)
32
+ attributes[index]
33
+ end
34
+ def each
35
+ attributes.each { |i| yield i }
36
+ end
37
+ def to_s
38
+ "#<#{self.class}: #{attributes}>"
39
+ end
40
+ alias :inspect :to_s
26
41
 
27
42
  def convert_multi_value_into_dictionary
28
43
  count.times.map do |i|
@@ -122,10 +137,10 @@ module AddressBook
122
137
 
123
138
  def ab_record_to_dict(i)
124
139
  case multi_value_property_type
140
+ when KABDateTimePropertyType
141
+ {:date => ABMultiValueCopyValueAtIndex(@ab_multi_value, i)}
125
142
  when KABStringPropertyType
126
143
  {:value => ABMultiValueCopyValueAtIndex(@ab_multi_value, i)}
127
- when KABDateTimePropertyType
128
- {:date => ABHack.getDateValueAtIndex(i, from: @ab_multi_value)}
129
144
  when KABDictionaryPropertyType
130
145
  ab_record = ABMultiValueCopyValueAtIndex(@ab_multi_value, i)
131
146
  PropertyMap.each_with_object({}) do |(ab_key, attr_key), dict|
@@ -1,28 +1,16 @@
1
1
  module AddressBook
2
2
  class Person
3
3
  attr_reader :error
4
+ attr_reader :address_book
4
5
 
5
- def initialize(attributes={}, existing_ab_person = nil, opts = {})
6
- @address_book = opts[:address_book]
7
- if existing_ab_person.nil?
8
- @ab_person = nil
9
- @attributes = attributes
10
- else
11
- @ab_person = existing_ab_person
12
- @attributes = nil
13
- end
6
+ def initialize(attributes = nil, existing_ab_person = nil, opts = {})
7
+ @address_book = opts.fetch(:address_book) { AddressBook.address_book }
8
+ @attributes = attributes
9
+ @ab_person = existing_ab_person
14
10
  end
15
11
 
16
- def self.all
17
- ab = AddressBook.address_book
18
- ab_people = ABAddressBookCopyArrayOfAllPeople(ab)
19
- return [] if ab_people.nil?
20
-
21
- people = ab_people.map do |ab_person|
22
- new({}, ab_person, :address_book => ab)
23
- end
24
- people.sort! { |a,b| "#{a.first_name} #{a.last_name}" <=> "#{b.first_name} #{b.last_name}" }
25
- people
12
+ def self.all(options = {})
13
+ AddressBook::AddrBook.new.people(options)
26
14
  end
27
15
 
28
16
  def self.create(attributes)
@@ -35,7 +23,7 @@ module AddressBook
35
23
  ABAddressBookAddRecord(address_book, ab_person, error)
36
24
  ABAddressBookSave(address_book, error)
37
25
  @attributes = nil # force refresh
38
- uid
26
+ self
39
27
  end
40
28
 
41
29
  def attributes
@@ -65,7 +53,7 @@ module AddressBook
65
53
  conditions.keys.all? do |attribute|
66
54
  case attribute
67
55
  when :email
68
- emails.attributes.map {|rec| rec[:value]}.any? {|v| v == conditions[attribute]}
56
+ emails.map {|rec| rec[:value]}.any? {|v| v == conditions[attribute]}
69
57
  else
70
58
  send(attribute) == conditions[attribute]
71
59
  end
@@ -215,6 +203,8 @@ module AddressBook
215
203
  def get_multi_valued(field)
216
204
  if mv = ABRecordCopyValue(ab_person, field)
217
205
  MultiValued.new(:ab_multi_value => mv)
206
+ else
207
+ []
218
208
  end
219
209
  end
220
210
 
@@ -223,7 +213,7 @@ module AddressBook
223
213
  end
224
214
 
225
215
  def phone_values
226
- phones.attributes.map {|r| r[:value]}
216
+ phones.map {|r| r[:value]}
227
217
  end
228
218
 
229
219
  def emails
@@ -231,7 +221,7 @@ module AddressBook
231
221
  end
232
222
 
233
223
  def email_values
234
- emails.attributes.map {|r| r[:value]}
224
+ emails.map {|r| r[:value]}
235
225
  end
236
226
 
237
227
  def addresses
@@ -260,8 +250,8 @@ module AddressBook
260
250
 
261
251
  def email; email_values.first; end
262
252
  def phone; phone_values.first; end
263
- def url; urls.attributes.first[:value]; end
264
- def address; addresses.attributes.first; end
253
+ def url; urls.any? && urls.first[:value]; end
254
+ def address; addresses.any? && addresses.first; end
265
255
 
266
256
  def find_or_new
267
257
  if new_record?
@@ -300,16 +290,11 @@ module AddressBook
300
290
  end
301
291
 
302
292
  def modification_date
303
- # workaround for RubyMotion bug: blows up when fetching NSDate properties
304
- # see http://hipbyte.myjetbrains.com/youtrack/issue/RM-81
305
- # still broken in RubyMotion 2.0
306
- ABHack.getDateProperty(KABPersonModificationDateProperty, from: ab_person)
307
- # when RubyMotion bug is fixed, this should just be
308
- # get_field(KABPersonModificationDateProperty)
293
+ get_field(KABPersonModificationDateProperty)
309
294
  end
310
295
 
311
296
  def creation_date
312
- ABHack.getDateProperty(KABPersonCreationDateProperty, from: ab_person)
297
+ get_field(KABPersonCreationDateProperty)
313
298
  end
314
299
 
315
300
  # replace *all* properties of an existing Person with new values
@@ -427,10 +412,9 @@ module AddressBook
427
412
  end
428
413
 
429
414
  Person.multi_value_property_map.each do |ab_property, attr_key|
430
- if value = get_multi_valued(ab_property)
431
- if value.attributes.any?
432
- @attributes[attr_key] = value.attributes
433
- end
415
+ value = get_multi_valued(ab_property)
416
+ if value.any?
417
+ @attributes[attr_key] = value.attributes
434
418
  end
435
419
  end
436
420
 
@@ -443,13 +427,7 @@ module AddressBook
443
427
  end
444
428
  end
445
429
  def get_field(field)
446
- if field == KABPersonBirthdayProperty
447
- # special case: RubyMotion blows up on NSDate properties
448
- # see http://hipbyte.myjetbrains.com/youtrack/issue/RM-81
449
- ABHack.getDateProperty(field, from: ab_person)
450
- else
451
- ABRecordCopyValue(ab_person, field)
452
- end
430
+ ABRecordCopyValue(ab_person, field)
453
431
  end
454
432
  def remove_field(field)
455
433
  ABRecordRemoveValue(ab_person, field, nil)
@@ -475,9 +453,5 @@ module AddressBook
475
453
  # what if there are more than one match? email should be unique but ...
476
454
  existing_records.first
477
455
  end
478
-
479
- def address_book
480
- @address_book ||= AddressBook.address_book
481
- end
482
456
  end
483
457
  end
@@ -3,10 +3,10 @@ module AddressBook
3
3
  class << self
4
4
  attr_accessor :showing
5
5
  end
6
- def self.show(&after)
6
+ def self.show(options={}, &after)
7
7
  raise "Cannot show two Pickers" if showing?
8
8
  @picker = Picker.new(&after)
9
- @picker.show
9
+ @picker.show options
10
10
  @picker
11
11
  end
12
12
 
@@ -18,12 +18,13 @@ module AddressBook
18
18
  @after = after
19
19
  end
20
20
 
21
- def show
21
+ def show(options)
22
22
  self.class.showing = true
23
23
 
24
24
  @people_picker_ctlr = ABPeoplePickerNavigationController.alloc.init
25
25
  @people_picker_ctlr.peoplePickerDelegate = self
26
- UIApplication.sharedApplication.keyWindow.rootViewController.presentViewController(@people_picker_ctlr, animated:true, completion:nil)
26
+ presenter = options.fetch :presenter, UIApplication.sharedApplication.keyWindow.rootViewController
27
+ presenter.presentViewController(@people_picker_ctlr, animated:true, completion:nil)
27
28
  end
28
29
 
29
30
  def hide(ab_person=nil)
@@ -53,8 +54,8 @@ end
53
54
 
54
55
  module AddressBook
55
56
  module_function
56
- def pick(&after)
57
- AddressBook::Picker.show &after
57
+ def pick(options={}, &after)
58
+ AddressBook::Picker.show options, &after
58
59
  end
59
60
  end
60
61
 
@@ -9,9 +9,9 @@ module AddressBook
9
9
  def type
10
10
  ABRecordCopyValue(ab_source, KABSourceTypeProperty)
11
11
  end
12
- end
13
12
 
14
- def local?
15
- type == KABSourceTypeLocal
13
+ def local?
14
+ type == KABSourceTypeLocal
15
+ end
16
16
  end
17
17
  end
@@ -46,6 +46,9 @@ module AddressBook
46
46
  AddressBook::Group.new(:ab_group => ab_group, :address_book => @ab)
47
47
  end
48
48
  end
49
+ def group_count
50
+ groups.count
51
+ end
49
52
  def new_group(attributes)
50
53
  AddressBook::Group.new(:attributes => attributes, :address_book => @ab)
51
54
  end
@@ -56,12 +59,13 @@ module AddressBook
56
59
  end
57
60
 
58
61
  def notify_changes(callback, context)
59
- ABAddressBookRegisterExternalChangeCallback(ab, callback, context)
62
+ App.notification_center.observe KABDatabaseChangedExternallyNotification do |notification|
63
+ callback.call(context)
64
+ end
60
65
  end
61
66
 
62
- # def sources
63
- # # ABAddressBookCopyArrayOfAllSources(ab).map {|s| ABRecordCopyValue(s, KABSourceTypeProperty)}
64
- # ABAddressBookCopyArrayOfAllSources(ab).map {|s| Source.new(s)}
65
- # end
67
+ def inspect
68
+ "#<#{self.class}:#{"0x%0x" % object_id} #{count} people, #{group_count} groups>"
69
+ end
66
70
  end
67
71
  end
@@ -6,9 +6,10 @@
6
6
  module AddressBook
7
7
  class Group
8
8
  attr_reader :attributes, :error
9
+ attr_reader :address_book
9
10
 
10
11
  def initialize(opts)
11
- @address_book = opts[:address_book]
12
+ @address_book = opts.fetch(:address_book) { AddressBook.address_book }
12
13
  if opts[:ab_group]
13
14
  # import existing
14
15
  @ab_group = opts[:ab_group]
@@ -20,10 +21,6 @@ module AddressBook
20
21
  end
21
22
  end
22
23
 
23
- def address_book
24
- @address_book ||= AddressBook.address_book
25
- end
26
-
27
24
  def save
28
25
  address_book.addRecord(ab_group)
29
26
  address_book.save
@@ -64,6 +61,9 @@ module AddressBook
64
61
  def name
65
62
  get_field(KABGroupNameProperty)
66
63
  end
64
+ def name=(newname)
65
+ ABRecordSetValue(ab_group, KABGroupNameProperty, newname)
66
+ end
67
67
 
68
68
  def size
69
69
  members.count
@@ -85,7 +85,15 @@ module AddressBook
85
85
 
86
86
  def <<(person_or_group)
87
87
  raise ArgumentError, "Must save member before adding to group" if person_or_group.new?
88
- ABGroupAddMember(ab_group, person_or_group.ab_record, error)
88
+ ABGroupAddMember(ab_group, person_or_group.ab_record)
89
+ end
90
+ def add(*items)
91
+ items.each { |item| self << item }
92
+ self
93
+ end
94
+ def remove(person_or_group)
95
+ ABGroupRemoveMember(ab_group, person_or_group.ab_record)
96
+ self
89
97
  end
90
98
 
91
99
  def local?
@@ -1,5 +1,7 @@
1
1
  module AddressBook
2
2
  class MultiValued
3
+ include Enumerable
4
+
3
5
  attr_reader :mv_type
4
6
 
5
7
  def initialize(opts)
@@ -23,6 +25,19 @@ module AddressBook
23
25
  def attributes
24
26
  @attributes ||= convert_multi_value_into_dictionary
25
27
  end
28
+ def to_ary
29
+ attributes
30
+ end
31
+ def [](index)
32
+ attributes[index]
33
+ end
34
+ def each
35
+ attributes.each { |i| yield i }
36
+ end
37
+ def to_s
38
+ "#<#{self.class}: #{attributes}>"
39
+ end
40
+ alias :inspect :to_s
26
41
 
27
42
  def convert_multi_value_into_dictionary
28
43
  count.times.map do |i|
@@ -1,9 +1,10 @@
1
1
  module AddressBook
2
2
  class Person
3
3
  attr_reader :error
4
+ attr_reader :address_book
4
5
 
5
6
  def initialize(target, opts = {})
6
- @address_book = opts[:address_book]
7
+ @address_book = opts.fetch(:address_book) { AddressBook.address_book }
7
8
  if target.respond_to?(:fetch)
8
9
  # data for a new Person, to be saved to the Address Book
9
10
  @ab_person = nil
@@ -41,13 +42,17 @@ module AddressBook
41
42
  get_field('com.apple.uuid')
42
43
  end
43
44
 
44
- def method_missing(name, *args)
45
- if property = ReverseSingleValuePropertyMap[name]
45
+ def method_missing(method_name, *args)
46
+ if property = ReverseSingleValuePropertyMap[method_name]
46
47
  get_field(property)
48
+ elsif property = ReverseSingleValuePropertyMap[method_name.gsub(/=$/, '').to_sym]
49
+ set_field(property, args.first)
50
+ @attributes = nil
47
51
  else
48
52
  super
49
53
  end
50
54
  end
55
+
51
56
  # def self.method_missing(name, *args)
52
57
  # if attribute_name = all_finder?(name)
53
58
  # find_all_by(attribute_name, args.first)
@@ -107,6 +112,8 @@ module AddressBook
107
112
  def get_multi_valued(field)
108
113
  if mv = get_field(field)
109
114
  MultiValued.new(:ab_multi_value => mv)
115
+ else
116
+ []
110
117
  end
111
118
  end
112
119
 
@@ -240,7 +247,7 @@ module AddressBook
240
247
  KABFirstNameProperty => :first_name,
241
248
  KABLastNameProperty => :last_name,
242
249
  KABMiddleNameProperty => :middle_name,
243
- KABPrefixProperty => :prefix,
250
+ KABTitleProperty => :prefix,
244
251
  KABSuffixProperty => :suffix,
245
252
  KABNicknameProperty => :nickname,
246
253
  KABJobTitleProperty => :job_title,
@@ -314,7 +321,7 @@ module AddressBook
314
321
 
315
322
  MultiValuePropertyMap.each do |ab_property, attr_key|
316
323
  if value = get_multi_valued(ab_property)
317
- if value.attributes.any?
324
+ if value.any?
318
325
  @attributes[attr_key] = value.attributes
319
326
  end
320
327
  end
@@ -342,9 +349,5 @@ module AddressBook
342
349
  set_field(field, multi_field.ab_multi_value)
343
350
  end
344
351
  end
345
-
346
- def address_book
347
- @address_book ||= AddressBook.address_book
348
- end
349
352
  end
350
353
  end
@@ -5,10 +5,10 @@ module AddressBook
5
5
  if App.osx?
6
6
  ABAddressBook.addressBook
7
7
  else # iOS
8
- if Device.ios_version == '6.0'
9
- ios6_create
10
- else
8
+ if Device.ios_version =~ /5/
11
9
  ios5_create
10
+ else
11
+ ios6_create
12
12
  end
13
13
  end
14
14
  end
@@ -23,8 +23,13 @@ module AddressBook
23
23
 
24
24
  def ios6_create
25
25
  error = nil
26
- @address_book = ABAddressBookCreateWithOptions(nil, error)
27
- request_authorization unless authorized?
26
+ if authorized?
27
+ @address_book = ABAddressBookCreateWithOptions(nil, error)
28
+ else
29
+ request_authorization do |rc|
30
+ NSLog "AddressBook: access was #{rc ? 'approved' : 'denied'}"
31
+ end
32
+ end
28
33
  @address_book
29
34
  end
30
35
 
@@ -24,6 +24,10 @@ describe AddressBook::Group do
24
24
  @group.should.not.be.new
25
25
  end
26
26
 
27
+ it "should describe itself" do
28
+ @group.to_s.should.match /AddressBook::Group:.*:Test Group: 0 members/
29
+ end
30
+
27
31
  it "should not add unsaved person records" do
28
32
  p = @ab.new_person({:first_name => 'Alice', :last_name => 'Artichoke'})
29
33
  lambda {@group << p}.should.raise ArgumentError
@@ -32,13 +36,10 @@ describe AddressBook::Group do
32
36
 
33
37
  describe 'a group with members' do
34
38
  before do
35
- @p1 = @ab.new_person({:first_name => 'Alice', :emails => [{:label => 'home', :value => 'alice@example.com'}]})
36
- @p1.save
37
- @p2 = @ab.new_person({:first_name => 'Bob', :emails => [{:label => 'home', :value => 'bob@example.com'}]})
38
- @p2.save
39
+ @p1 = @ab.create_person({:first_name => 'Alice', :emails => [{:label => 'home', :value => 'alice@example.com'}]})
40
+ @p2 = @ab.create_person({:first_name => 'Bob', :emails => [{:label => 'home', :value => 'bob@example.com'}]})
39
41
  @group = @ab.new_group(:name => 'Test Group')
40
- @group << @p1
41
- @group << @p2
42
+ @group.add(@p1, @p2)
42
43
  @group.save
43
44
  end
44
45
  after do
@@ -58,6 +59,45 @@ describe AddressBook::Group do
58
59
  it "should search by id" do
59
60
  @ab.group(@group.uid).name.should.equal @group.name
60
61
  end
62
+
63
+ it "should describe itself" do
64
+ @group.to_s.should.match /AddressBook::Group:.*:Test Group: 2 members/
65
+ end
66
+
67
+ describe "after removing one member" do
68
+ before do
69
+ @group.remove(@p2)
70
+ @group.save
71
+ end
72
+
73
+ it "should no longer contain the removed member" do
74
+ @group.members.map(&:uid).should.equal [@p1.uid]
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'a deleted group' do
80
+ before do
81
+ @p1 = @ab.create_person({:first_name => 'Alice', :emails => [{:label => 'home', :value => 'alice@example.com'}]})
82
+ @p2 = @ab.create_person({:first_name => 'Bob', :emails => [{:label => 'home', :value => 'bob@example.com'}]})
83
+ @group = @ab.new_group(:name => 'Test Group')
84
+ @group.add(@p1, @p2)
85
+ @group.save
86
+ @group.delete!
87
+ end
88
+
89
+ after do
90
+ @p1.delete!
91
+ @p2.delete!
92
+ end
93
+
94
+ it "should have no uid" do
95
+ @group.uid.should.be.nil
96
+ end
97
+
98
+ it "should describe itself" do
99
+ @group.to_s.should.match /AddressBook::Group:DELETED/
100
+ end
61
101
  end
62
102
 
63
103
  # TODO: nested groups
@@ -1,4 +1,12 @@
1
1
  describe AddressBook::Person do
2
+ before do
3
+ @ab = AddressBook::AddrBook.new
4
+ end
5
+
6
+ it "should be authorized" do
7
+ @ab.authorized?.should.be.true
8
+ end
9
+
2
10
  describe 'ways of creating and finding people' do
3
11
  describe 'new' do
4
12
  before do
@@ -157,7 +165,11 @@ describe AddressBook::Person do
157
165
  { :label => 'home page', :value => "http://www.mysite.com/" },
158
166
  { :label => 'work', :value => 'http://dept.bigco.com/' },
159
167
  { :label => 'school', :value => 'http://state.edu/college' }
160
- ]
168
+ ],
169
+ :social_profiles => [
170
+ { service: 'FaceBook', username: 'testyman' },
171
+ { service: 'twitter', username: 'testwit' }
172
+ ]
161
173
  }
162
174
  end
163
175
 
@@ -242,6 +254,11 @@ describe AddressBook::Person do
242
254
  @ab_person.urls.attributes.should.equal @attributes[:urls]
243
255
  end
244
256
 
257
+ it 'should round-trip social profiles' do
258
+ @ab_person.social_profiles.count.should.equal 2
259
+ @ab_person.attributes[:social_profiles].should.equal @attributes[:social_profiles]
260
+ end
261
+
245
262
  describe 'once saved' do
246
263
  before do
247
264
  @before_count = AddressBook.count
@@ -446,4 +463,35 @@ describe AddressBook::Person do
446
463
  end
447
464
  end
448
465
  end
466
+
467
+ describe "sorting" do
468
+ before do
469
+ @ab.people.each(&:delete!)
470
+
471
+ @p1 = @ab.create_person({:first_name => 'Bob', :last_name => 'Edwards'}).uid
472
+ @p2 = @ab.create_person({:first_name => 'Doris', :last_name => 'Channing'}).uid
473
+ @p3 = @ab.create_person({:first_name => 'Anne', :last_name => 'Brown'}).uid
474
+ @p4 = @ab.create_person({:first_name => 'Eddie', :last_name => 'Anderson'}).uid
475
+ @p5 = @ab.create_person({:first_name => 'Carol', :last_name => 'Dolittle'}).uid
476
+ end
477
+
478
+ it "should sort on last name using OS sort" do
479
+ @ab.people(ordering: KABPersonSortByLastName).map(&:uid).should.equal [@p4, @p3, @p2, @p5, @p1]
480
+ end
481
+ it "should support last-name sort in Person#all" do
482
+ AddressBook::Person.all(ordering: KABPersonSortByLastName).map(&:uid).should.equal [@p4, @p3, @p2, @p5, @p1]
483
+ end
484
+
485
+ it "should sort on first name using OS sort" do
486
+ @ab.people(ordering: KABPersonSortByFirstName).map(&:uid).should.equal [@p3, @p1, @p5, @p2, @p4]
487
+ end
488
+ it "should support first-name sort in Person#all" do
489
+ AddressBook::Person.all(ordering: KABPersonSortByFirstName).map(&:uid).should.equal [@p3, @p1, @p5, @p2, @p4]
490
+ end
491
+
492
+ it "should support a custom sort order" do
493
+ ordered = @ab.people { |p| p.last_name[1] }.map(&:uid)
494
+ ordered.should.equal [@p1, @p2, @p4, @p5, @p3]
495
+ end
496
+ end
449
497
  end
@@ -0,0 +1,32 @@
1
+ # These methods are intended to protect contents of the simulator
2
+ # instance from destruction when the spec suite runs. Specifically,
3
+ # the contents of the iOS Address Book, which is global to all
4
+ # applications.
5
+
6
+ SIMULATOR_ROOT = "#{ENV['HOME']}/../.."
7
+ AB_PATH = SIMULATOR_ROOT + "/Library/AddressBook"
8
+ AB_PATH_BAK = AB_PATH + ".bak"
9
+
10
+ def protect_existing_address_book
11
+ # Can't use ruby methods to operate on these directories because the
12
+ # iOS layer protects them, but shelling out is still allowed so we
13
+ # can alter the world that way.
14
+
15
+ unless AddressBook.authorized?
16
+ warn "BLOCKING FOR AUTHORIZATION"
17
+ AddressBook.request_authorization
18
+ end
19
+
20
+ warn "PROTECTING EXISTING ADDRESS BOOK IN SIMULATOR"
21
+
22
+ `mv \"#{AB_PATH}\" "#{AB_PATH_BAK}"`
23
+ end
24
+
25
+ at_exit do
26
+ warn "RESTORING ORIGINAL ADDRESS BOOK IN SIMULATOR"
27
+
28
+ `rm -rf \"#{AB_PATH}\"`
29
+ `mv \"#{AB_PATH_BAK}\" "#{AB_PATH}"`
30
+ end
31
+
32
+ protect_existing_address_book
@@ -41,16 +41,16 @@ describe AddressBook::Person do
41
41
  end
42
42
 
43
43
  it 'should be able to get each of the single value fields' do
44
- @the_person.first_name.should.equal @alex_data[:first_name ]
45
- @the_person.last_name.should.equal @alex_data[:last_name ]
46
- @the_person.middle_name.should.equal @alex_data[:middle_name ]
47
- @the_person.suffix.should.equal @alex_data[:prefix ]
48
- @the_person.suffix.should.equal @alex_data[:suffix ]
49
- @the_person.nickname.should.equal @alex_data[:nickname ]
50
- @the_person.job_title.should.equal @alex_data[:job_title ]
51
- @the_person.department.should.equal @alex_data[:department ]
44
+ @the_person.first_name.should.equal @alex_data[:first_name]
45
+ @the_person.last_name.should.equal @alex_data[:last_name]
46
+ @the_person.middle_name.should.equal @alex_data[:middle_name]
47
+ @the_person.prefix.should.equal @alex_data[:prefix]
48
+ @the_person.suffix.should.equal @alex_data[:suffix]
49
+ @the_person.nickname.should.equal @alex_data[:nickname]
50
+ @the_person.job_title.should.equal @alex_data[:job_title]
51
+ @the_person.department.should.equal @alex_data[:department]
52
52
  @the_person.organization.should.equal @alex_data[:organization]
53
- @the_person.note.should.equal @alex_data[:note]
53
+ @the_person.note.should.equal @alex_data[:note]
54
54
  @the_person.should.be.person?
55
55
  end
56
56
 
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-addressbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
5
- prerelease:
4
+ version: 1.6.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Alex Rothenberg
@@ -10,12 +9,11 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-06-12 00:00:00.000000000 Z
12
+ date: 2013-10-22 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: bubble-wrap
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
18
  - - ~>
21
19
  - !ruby/object:Gem::Version
@@ -23,7 +21,6 @@ dependencies:
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
25
  - - ~>
29
26
  - !ruby/object:Gem::Version
@@ -31,33 +28,29 @@ dependencies:
31
28
  - !ruby/object:Gem::Dependency
32
29
  name: rake
33
30
  requirement: !ruby/object:Gem::Requirement
34
- none: false
35
31
  requirements:
36
- - - ! '>='
32
+ - - '>='
37
33
  - !ruby/object:Gem::Version
38
34
  version: '0'
39
35
  type: :development
40
36
  prerelease: false
41
37
  version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
38
  requirements:
44
- - - ! '>='
39
+ - - '>='
45
40
  - !ruby/object:Gem::Version
46
41
  version: '0'
47
42
  - !ruby/object:Gem::Dependency
48
43
  name: rspec
49
44
  requirement: !ruby/object:Gem::Requirement
50
- none: false
51
45
  requirements:
52
- - - ! '>='
46
+ - - '>='
53
47
  - !ruby/object:Gem::Version
54
48
  version: '0'
55
49
  type: :development
56
50
  prerelease: false
57
51
  version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
52
  requirements:
60
- - - ! '>='
53
+ - - '>='
61
54
  - !ruby/object:Gem::Version
62
55
  version: '0'
63
56
  description: A RubyMotion wrapper around the iOS & OSX Address Book frameworks
@@ -74,8 +67,6 @@ files:
74
67
  - LICENSE
75
68
  - README.md
76
69
  - Rakefile
77
- - abhack/abhack.h
78
- - abhack/abhack.m
79
70
  - lib/motion-addressbook.rb
80
71
  - lib/motion-addressbook/version.rb
81
72
  - motion-addressbook.gemspec
@@ -98,39 +89,33 @@ files:
98
89
  - spec/ios/helpers/bacon_matchers.rb
99
90
  - spec/ios/helpers/hacks.rb
100
91
  - spec/ios/helpers/person_helpers.rb
92
+ - spec/ios/helpers/spec_helper.rb
101
93
  - spec/osx/address_book/person_spec.rb
102
94
  - spec/osx/helpers/bacon_matchers.rb
103
95
  - spec/osx/helpers/hacks.rb
104
96
  - spec/osx/helpers/person_helpers.rb
105
97
  homepage: ''
106
98
  licenses: []
99
+ metadata: {}
107
100
  post_install_message:
108
101
  rdoc_options: []
109
102
  require_paths:
110
103
  - lib
111
104
  required_ruby_version: !ruby/object:Gem::Requirement
112
- none: false
113
105
  requirements:
114
- - - ! '>='
106
+ - - '>='
115
107
  - !ruby/object:Gem::Version
116
108
  version: '0'
117
- segments:
118
- - 0
119
- hash: -2657752188704794631
120
109
  required_rubygems_version: !ruby/object:Gem::Requirement
121
- none: false
122
110
  requirements:
123
- - - ! '>='
111
+ - - '>='
124
112
  - !ruby/object:Gem::Version
125
113
  version: '0'
126
- segments:
127
- - 0
128
- hash: -2657752188704794631
129
114
  requirements: []
130
115
  rubyforge_project:
131
- rubygems_version: 1.8.24
116
+ rubygems_version: 2.0.5
132
117
  signing_key:
133
- specification_version: 3
118
+ specification_version: 4
134
119
  summary: A RubyMotion wrapper around the iOS & OSX Address Book frameworks
135
120
  test_files:
136
121
  - spec/ios/address_book/group_spec.rb
@@ -140,6 +125,7 @@ test_files:
140
125
  - spec/ios/helpers/bacon_matchers.rb
141
126
  - spec/ios/helpers/hacks.rb
142
127
  - spec/ios/helpers/person_helpers.rb
128
+ - spec/ios/helpers/spec_helper.rb
143
129
  - spec/osx/address_book/person_spec.rb
144
130
  - spec/osx/helpers/bacon_matchers.rb
145
131
  - spec/osx/helpers/hacks.rb
data/abhack/abhack.h DELETED
@@ -1,8 +0,0 @@
1
- #import <AddressBook/AddressBook.h>
2
-
3
- @interface ABHack : NSObject
4
-
5
- + (NSDate *) getDateProperty: (ABPropertyID) property from: (ABRecordRef) ab_person;
6
- + (NSDate *) getDateValueAtIndex: (int) index from: (ABMutableMultiValueRef) ab_multi_value;
7
-
8
- @end
data/abhack/abhack.m DELETED
@@ -1,15 +0,0 @@
1
- #import "abhack.h"
2
-
3
- @implementation ABHack
4
-
5
- + (NSDate *) getDateProperty: (ABPropertyID) property from: (ABRecordRef) ab_person
6
- {
7
- return (NSDate *)ABRecordCopyValue(ab_person, property);
8
- }
9
-
10
- + (NSDate *) getDateValueAtIndex: (int) index from: (ABMultiValueRef) ab_multi_value
11
- {
12
- return (NSDate *)ABMultiValueCopyValueAtIndex(ab_multi_value, index);
13
- }
14
-
15
- @end