bubble-wrap 1.8.0 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +14 -9
- data/CHANGELOG.md +21 -2
- data/Gemfile.lock +8 -5
- data/README.md +54 -3
- data/Rakefile +7 -1
- data/lib/bubble-wrap/camera.rb +1 -1
- data/lib/bubble-wrap/core.rb +1 -1
- data/lib/bubble-wrap/font.rb +1 -1
- data/lib/bubble-wrap/loader.rb +4 -4
- data/lib/bubble-wrap/media.rb +1 -1
- data/lib/bubble-wrap/motion.rb +7 -1
- data/lib/bubble-wrap/version.rb +2 -2
- data/motion/core/app.rb +4 -0
- data/motion/core/device/ios/camera_wrapper.rb +1 -1
- data/motion/core/device/ios/screen.rb +2 -2
- data/motion/core/device/osx/screen.rb +1 -1
- data/motion/core/device/screen.rb +1 -1
- data/motion/core/ios/device.rb +1 -1
- data/motion/core/ios/ns_index_path.rb +11 -0
- data/motion/core/json.rb +2 -2
- data/motion/core/kvo.rb +118 -55
- data/motion/core/ns_notification_center.rb +2 -2
- data/motion/core/ns_url_request.rb +2 -2
- data/motion/core/osx/device.rb +1 -1
- data/motion/core/string.rb +7 -7
- data/motion/font/font.rb +1 -1
- data/motion/ios/8/location_constants.rb +21 -0
- data/motion/location/location.rb +38 -18
- data/motion/mail/result.rb +1 -1
- data/motion/media/media.rb +1 -1
- data/motion/motion/accelerometer.rb +55 -0
- data/motion/motion/device_motion.rb +139 -0
- data/motion/motion/gyroscope.rb +55 -0
- data/motion/motion/magnetometer.rb +55 -0
- data/motion/motion/motion.rb +0 -288
- data/motion/reactor.rb +3 -3
- data/motion/reactor/deferrable.rb +32 -32
- data/motion/reactor/periodic_timer.rb +1 -1
- data/motion/reactor/queue.rb +6 -6
- data/motion/reactor/thread_aware_deferrable.rb +1 -1
- data/motion/reactor/timer.rb +1 -1
- data/motion/rss_parser.rb +6 -3
- data/motion/shortcut.rb +1 -1
- data/motion/sms/result.rb +1 -1
- data/motion/test_suite_delegate.rb +1 -1
- data/motion/ui/ui_activity_view_controller_wrapper.rb +6 -1
- data/motion/ui/ui_alert_view.rb +21 -1
- data/motion/util/deprecated.rb +1 -1
- data/samples/alert/Gemfile.lock +1 -1
- data/spec/lib/bubble-wrap/requirement_spec.rb +2 -2
- data/spec/lib/bubble-wrap_spec.rb +1 -1
- data/spec/lib/motion_stub.rb +1 -1
- data/spec/motion/core/app_spec.rb +6 -0
- data/spec/motion/core/device/osx/screen_spec.rb +1 -1
- data/spec/motion/core/ios/ns_index_path_spec.rb +20 -0
- data/spec/motion/core/kvo_spec.rb +171 -58
- data/spec/motion/core/ns_notification_center_spec.rb +3 -3
- data/spec/motion/core/string_spec.rb +16 -16
- data/spec/motion/core_spec.rb +3 -3
- data/spec/motion/font/font_spec.rb +1 -1
- data/spec/motion/location/location_spec.rb +61 -9
- data/spec/motion/mail/result_spec.rb +7 -7
- data/spec/motion/media/player_spec.rb +1 -1
- data/spec/motion/reactor/thread_aware_deferrable_spec.rb +3 -3
- data/spec/motion/sms/result_spec.rb +6 -6
- data/spec/motion/ui/ui_alert_view_spec.rb +59 -1
- data/spec/motion/util/deprecated_spec.rb +1 -1
- metadata +17 -4
- data/motion/ios/7/uiactivity_view_controller_constants.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77584cd0711e17af5282a0e9f40306916177b6d5
|
4
|
+
data.tar.gz: a12694fd9f1a6e370a9d91f3ed15f3ce74af6469
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0fa5d162a946c67f83a77b56b84426f42c62770a10a027523cb2ab0e5c0958e9f657ebfb5e5fda060174aaacdc2faaf22e9f6f5b984b8db73a6bf96866495e2
|
7
|
+
data.tar.gz: 18fbc4e01a2091678107341a57d1067d2ec3341dadec26c180baf863cdfb1d034ff69046e04ecd6c5242937ae5ee410b9cf80270d55a30bd8af996be921881ea
|
data/.travis.yml
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
language: objective-c
|
2
2
|
before_install:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
- (ruby --version)
|
4
|
+
- sudo chown -R travis ~/Library/RubyMotion
|
5
|
+
- sudo mkdir -p ~/Library/RubyMotion/build
|
6
|
+
- sudo chown -R travis ~/Library/RubyMotion/build
|
7
|
+
- sudo motion update
|
8
|
+
gemfile:
|
9
|
+
- Gemfile
|
7
10
|
script:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
- bundle install --jobs=3 --retry=3
|
12
|
+
- bundle exec rake clean
|
13
|
+
- bundle exec rake spec
|
14
|
+
- bundle exec rake clean
|
15
|
+
- bundle exec rake spec target=7.1
|
16
|
+
- bundle exec rake clean
|
17
|
+
- bundle exec rake spec osx=true
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,29 @@
|
|
1
1
|
## Unreleased
|
2
2
|
|
3
|
-
[Commit history](https://github.com/rubymotion/BubbleWrap/compare/v1.
|
3
|
+
[Commit history](https://github.com/rubymotion/BubbleWrap/compare/v1.9.0...master)
|
4
|
+
|
5
|
+
## 1.9.0
|
6
|
+
|
7
|
+
[Commit history](https://github.com/rubymotion/BubbleWrap/compare/v1.8.0...v1.9.0)
|
8
|
+
|
9
|
+
* Add support for `keyboardType` on first input field of `BW::UIAlertView` ([#406](https://github.com/rubymotion/BubbleWrap/pull/406))
|
10
|
+
* Implement #+ and #- for NSIndexPath to incr/decr row ([#420](https://github.com/rubymotion/BubbleWrap/pull/420))
|
11
|
+
* Extract CoreMotion classes to make it easier to use and more maintainable ([#454](https://github.com/rubymotion/BubbleWrap/pull/454))
|
12
|
+
* Motion extract classes ([#454](https://github.com/rubymotion/BubbleWrap/pull/454))
|
13
|
+
* Added RSS fields: creator, category, encoded ([#461](https://github.com/rubymotion/BubbleWrap/pull/461))
|
14
|
+
* KVO `observe!` and ability to pass multiple key paths to `observe` ([#460](https://github.com/rubymotion/BubbleWrap/pull/460))
|
15
|
+
* `App.short_version` ([#466](https://github.com/rubymotion/BubbleWrap/pull/466))
|
16
|
+
* Bump the required version of iOS to >= 7 ([#424](https://github.com/rubymotion/BubbleWrap/pull/424))
|
17
|
+
* Bump the required version of iOS to >= 7 ([#424](https://github.com/rubymotion/BubbleWrap/pull/424))
|
18
|
+
* Fixes to CoreLocation ([#422](https://github.com/rubymotion/BubbleWrap/pull/422)) & ([#432](https://github.com/rubymotion/BubbleWrap/pull/432))
|
19
|
+
* Adds default text option to BW::UIAlertView ([#467](https://github.com/rubymotion/BubbleWrap/pull/467))
|
20
|
+
* Bump the minimum required RubyMotion version to `3.12`.
|
21
|
+
|
22
|
+
## ... nothing to see here... move along.
|
4
23
|
|
5
24
|
## 1.4.0
|
6
25
|
|
7
|
-
[Commit history](https://github.com/rubymotion/BubbleWrap/compare/v1.3.0...
|
26
|
+
[Commit history](https://github.com/rubymotion/BubbleWrap/compare/v1.3.0...v1.4.0)
|
8
27
|
|
9
28
|
* Added `BW::Mail` for sending emails ([#247](https://github.com/rubymotion/BubbleWrap/pull/247))
|
10
29
|
* Added `BW::SMS` for sending SMS/iMessages ([#287](https://github.com/rubymotion/BubbleWrap/pull/287))
|
data/Gemfile.lock
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bubble-wrap (1.
|
4
|
+
bubble-wrap (1.9.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
bacon (1.2.0)
|
10
10
|
metaclass (0.0.4)
|
11
|
-
mocha (0.
|
11
|
+
mocha (0.14.0)
|
12
12
|
metaclass (~> 0.0.1)
|
13
|
-
mocha-on-bacon (0.2.
|
14
|
-
mocha (>= 0.
|
15
|
-
rake (10.
|
13
|
+
mocha-on-bacon (0.2.2)
|
14
|
+
mocha (>= 0.13.0)
|
15
|
+
rake (10.4.2)
|
16
16
|
webstub (1.1.2)
|
17
17
|
|
18
18
|
PLATFORMS
|
@@ -25,3 +25,6 @@ DEPENDENCIES
|
|
25
25
|
mocha-on-bacon (~> 0.2)
|
26
26
|
rake (~> 10.0)
|
27
27
|
webstub (~> 1.1)
|
28
|
+
|
29
|
+
BUNDLED WITH
|
30
|
+
1.10.4
|
data/README.md
CHANGED
@@ -7,6 +7,7 @@ A collection of (tested) helpers and wrappers used to wrap Cocoa Touch and AppKi
|
|
7
7
|
|
8
8
|
[![Code Climate](https://codeclimate.com/github/rubymotion/BubbleWrap.svg)](https://codeclimate.com/github/rubymotion/BubbleWrap)
|
9
9
|
[![Build Status](https://travis-ci.org/rubymotion/BubbleWrap.svg?branch=master)](https://travis-ci.org/rubymotion/BubbleWrap)
|
10
|
+
[![Gem Version](https://badge.fury.io/rb/bubble-wrap.png)](http://badge.fury.io/rb/bubble-wrap)
|
10
11
|
[![Dependency Status](https://gemnasium.com/rubymotion/BubbleWrap.png)](https://gemnasium.com/rubymotion/BubbleWrap)
|
11
12
|
|
12
13
|
## Installation
|
@@ -26,7 +27,7 @@ require 'bubble-wrap'
|
|
26
27
|
If you using Bundler:
|
27
28
|
|
28
29
|
```ruby
|
29
|
-
gem "bubble-wrap", "~> 1.
|
30
|
+
gem "bubble-wrap", "~> 1.9.0"
|
30
31
|
```
|
31
32
|
|
32
33
|
BubbleWrap is split into multiple modules so that you can easily choose which parts are included at compile-time.
|
@@ -79,6 +80,12 @@ If you wish to only include the `SMS` wrapper:
|
|
79
80
|
require 'bubble-wrap/sms'
|
80
81
|
```
|
81
82
|
|
83
|
+
If you wish to only include the `Motion` (CoreMotion) wrapper:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
require 'bubble-wrap/motion'
|
87
|
+
```
|
88
|
+
|
82
89
|
If you wish to only include the `NetworkIndicator` wrapper:
|
83
90
|
|
84
91
|
```ruby
|
@@ -298,6 +305,11 @@ BW::JSON.parse "{\"foo\":1,\"bar\":[1,2,3],\"baz\":\"awesome\"}"
|
|
298
305
|
Helper methods added to give `NSIndexPath` a bit more of a Ruby
|
299
306
|
interface.
|
300
307
|
|
308
|
+
```ruby
|
309
|
+
index_path = table_view.indexPathForCell(cell)
|
310
|
+
index_path + 1 # NSIndexPath for next cell in the same section
|
311
|
+
=> #<NSIndexPath:0x120db8e0>
|
312
|
+
```
|
301
313
|
|
302
314
|
### NSNotificationCenter
|
303
315
|
|
@@ -376,6 +388,32 @@ class ExampleViewController < UIViewController
|
|
376
388
|
end
|
377
389
|
```
|
378
390
|
|
391
|
+
You can remove observers using `unobserve` method.
|
392
|
+
|
393
|
+
**Since: > version 1.9.0**
|
394
|
+
|
395
|
+
Optionally, multiple key paths can be passed to the `observer` method:
|
396
|
+
|
397
|
+
``` ruby
|
398
|
+
class ExampleViewController < UIViewController
|
399
|
+
include BW::KVO
|
400
|
+
|
401
|
+
def viewDidLoad
|
402
|
+
@label = UILabel.alloc.initWithFrame [[20,20],[280,44]]
|
403
|
+
@label.text = ""
|
404
|
+
view.addSubview @label
|
405
|
+
|
406
|
+
observe(@label, [:text, :textColor]) do |old_value, new_value, key_path|
|
407
|
+
puts "Hello from viewDidLoad for #{key_path}!"
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
```
|
412
|
+
|
413
|
+
Also you can use `observe!` method to register observer that will immediately
|
414
|
+
return initial value. Note that in this case only new value will be passed to
|
415
|
+
the block.
|
416
|
+
|
379
417
|
|
380
418
|
### String
|
381
419
|
|
@@ -416,6 +454,10 @@ BW::Location.get(purpose: 'We need to use your GPS because...') do |result|
|
|
416
454
|
p "To Lat #{result[:to].latitude}, Long #{result[:to].longitude}"
|
417
455
|
end
|
418
456
|
```
|
457
|
+
*Note: `result[:from]` will return `nil` the first time location services are started.*
|
458
|
+
|
459
|
+
The `:previous` key in the `BW::Location.get()` result hash will always return an array of zero or more additional `CLLocation` objects aside from the locations returned from the `:to` and `:from` hash keys. While in most scenarios this array will be empty, per [Apple's Documentation](https://developer.apple.com/library/IOs/documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/index.html#//apple_ref/occ/intfm/CLLocationManagerDelegate/locationManager:didUpdateLocations:) if there are deferred updates or multiple locations that arrived before they could be delivered, multiple locations will be returned in an order of oldest to newest.
|
460
|
+
|
419
461
|
|
420
462
|
```ruby
|
421
463
|
BW::Location.get_compass do |result|
|
@@ -1210,9 +1252,18 @@ Ow!
|
|
1210
1252
|
=> nil
|
1211
1253
|
```
|
1212
1254
|
|
1213
|
-
#
|
1255
|
+
# Contributing
|
1214
1256
|
|
1215
1257
|
Do you have a suggestion for a specific wrapper? Feel free to open an
|
1216
1258
|
issue/ticket and tell us about what you are after. If you have a
|
1217
1259
|
wrapper/helper you are using and are thinking that others might enjoy,
|
1218
|
-
please send a pull request
|
1260
|
+
please send a pull request with tests. If you need help writing the tests,
|
1261
|
+
send the pull request anyways and we'll try to help you out with that.
|
1262
|
+
|
1263
|
+
1. Create an issue in GitHub to make sure your PR will be accepted
|
1264
|
+
2. Fork the BubbleWrap repository
|
1265
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
1266
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
1267
|
+
5. Write tests for your changes and ensure they pass locally (`bundle exec rake spec && bundle exec rake spec osx=true`)
|
1268
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
1269
|
+
7. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -32,9 +32,15 @@ Motion::Project::App.setup do |app|
|
|
32
32
|
app.spec_files -= Dir.glob("./spec/motion/#{package}/**/*.rb")
|
33
33
|
end
|
34
34
|
else
|
35
|
+
app.deployment_target = '7.1'
|
36
|
+
app.info_plist['NSLocationAlwaysUsageDescription'] = 'Description'
|
37
|
+
app.info_plist['NSLocationWhenInUseUsageDescription'] = 'Description'
|
38
|
+
|
35
39
|
app.spec_files -= Dir.glob("./spec/motion/**/osx/**.rb")
|
36
40
|
end
|
37
|
-
|
41
|
+
|
42
|
+
app.version = '1.2.3'
|
43
|
+
app.short_version = '3.2.1'
|
38
44
|
end
|
39
45
|
|
40
46
|
namespace :spec do
|
data/lib/bubble-wrap/camera.rb
CHANGED
data/lib/bubble-wrap/core.rb
CHANGED
data/lib/bubble-wrap/font.rb
CHANGED
data/lib/bubble-wrap/loader.rb
CHANGED
@@ -48,13 +48,13 @@ unless defined?(BubbleWrap::LOADER_PRESENT)
|
|
48
48
|
|
49
49
|
def after_config(config)
|
50
50
|
BubbleWrap.require_ios do
|
51
|
-
|
52
|
-
if config.send(:deployment_target).to_f >=
|
53
|
-
::BubbleWrap.require(
|
51
|
+
ios8_files = 'motion/ios/8/location_constants.rb'
|
52
|
+
if config.send(:deployment_target).to_f >= 8.0
|
53
|
+
::BubbleWrap.require(ios8_files)
|
54
54
|
before_config(config)
|
55
55
|
else
|
56
56
|
config.files = config.files.reject {|s|
|
57
|
-
s.include?(
|
57
|
+
s.include?(ios8_files)
|
58
58
|
}
|
59
59
|
end
|
60
60
|
end
|
data/lib/bubble-wrap/media.rb
CHANGED
data/lib/bubble-wrap/motion.rb
CHANGED
@@ -5,6 +5,12 @@ BubbleWrap.require_ios('motion') do
|
|
5
5
|
BubbleWrap.require('motion/core/string.rb')
|
6
6
|
BubbleWrap.require('motion/motion/**/*.rb') do
|
7
7
|
file('motion/motion/motion.rb').depends_on 'motion/util/constants.rb'
|
8
|
+
|
9
|
+
file('motion/motion/accelerometer.rb').depends_on('motion/motion/motion.rb')
|
10
|
+
file('motion/motion/device_motion.rb').depends_on('motion/motion/motion.rb')
|
11
|
+
file('motion/motion/gyroscope.rb').depends_on('motion/motion/motion.rb')
|
12
|
+
file('motion/motion/magnetometer.rb').depends_on('motion/motion/motion.rb')
|
13
|
+
|
8
14
|
file('motion/motion/motion.rb').uses_framework('CoreMotion')
|
9
15
|
end
|
10
|
-
end
|
16
|
+
end
|
data/lib/bubble-wrap/version.rb
CHANGED
data/motion/core/app.rb
CHANGED
@@ -78,7 +78,7 @@ module BubbleWrap
|
|
78
78
|
# compensating for screen rotation (which
|
79
79
|
# can do your head in).
|
80
80
|
def width_for_orientation(o=orientation)
|
81
|
-
return height if (o == :landscape_left) || (o == :landscape_right)
|
81
|
+
return height if (o == :landscape_left) || (o == :landscape_right)
|
82
82
|
width
|
83
83
|
end
|
84
84
|
|
@@ -86,7 +86,7 @@ module BubbleWrap
|
|
86
86
|
# compensating for screen rotation (which
|
87
87
|
# can do your head in).
|
88
88
|
def height_for_orientation(o=orientation)
|
89
|
-
return width if (o == :landscape_left) || (o == :landscape_right)
|
89
|
+
return width if (o == :landscape_left) || (o == :landscape_right)
|
90
90
|
height
|
91
91
|
end
|
92
92
|
end
|
data/motion/core/ios/device.rb
CHANGED
@@ -13,7 +13,7 @@ module BubbleWrap
|
|
13
13
|
def ipad?(idiom=UIDevice.currentDevice.userInterfaceIdiom)
|
14
14
|
idiom == UIUserInterfaceIdiomPad
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# Verifies that the device having a long screen (4 inch iPhone/iPod)
|
18
18
|
# @return [TrueClass, FalseClass] true will be returned if the device is an iPhone/iPod with 4 inche screen, false otherwise.
|
19
19
|
def long_screen?(idiom=UIDevice.currentDevice.userInterfaceIdiom, screen_height=UIScreen.mainScreen.bounds.size.height)
|
data/motion/core/json.rb
CHANGED
data/motion/core/kvo.rb
CHANGED
@@ -18,93 +18,156 @@
|
|
18
18
|
# @see https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i
|
19
19
|
module BubbleWrap
|
20
20
|
module KVO
|
21
|
-
|
22
|
-
|
21
|
+
class Registry
|
22
|
+
COLLECTION_OPERATIONS = [ NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, NSKeyValueChangeReplacement ]
|
23
|
+
OPTION_MAP = {
|
24
|
+
new: NSKeyValueChangeNewKey,
|
25
|
+
old: NSKeyValueChangeOldKey
|
26
|
+
}
|
27
|
+
|
28
|
+
attr_reader :callbacks, :keys
|
29
|
+
|
30
|
+
def initialize(value_keys = [:old, :new])
|
31
|
+
@keys = value_keys.inject([]) do |acc, key|
|
32
|
+
value_change_key = OPTION_MAP[key]
|
33
|
+
|
34
|
+
if value_change_key.nil?
|
35
|
+
raise RuntimeError, "Unknown value change key #{key}. Possible keys: #{OPTION_MAP.keys}"
|
36
|
+
end
|
37
|
+
|
38
|
+
acc << value_change_key
|
39
|
+
end
|
23
40
|
|
24
|
-
|
25
|
-
|
26
|
-
|
41
|
+
@callbacks = Hash.new do |hash, key|
|
42
|
+
hash[key] = Hash.new do |subhash, subkey|
|
43
|
+
subhash[subkey] = Array.new
|
44
|
+
end
|
45
|
+
end
|
27
46
|
end
|
28
47
|
|
29
|
-
key_path
|
30
|
-
|
48
|
+
def add(target, key_path, &block)
|
49
|
+
return if target.nil? || key_path.nil? || block.nil?
|
31
50
|
|
32
|
-
|
33
|
-
add_observer_block(target, key_path, &block)
|
34
|
-
end
|
51
|
+
block.weak! if BubbleWrap.use_weak_callbacks?
|
35
52
|
|
36
|
-
|
37
|
-
unless [1,2].include?(arguments.length)
|
38
|
-
raise ArgumentError, "wrong number of arguments (#{arguments.length} for 1 or 2)"
|
53
|
+
callbacks[target][key_path.to_s] << block
|
39
54
|
end
|
40
55
|
|
41
|
-
|
42
|
-
|
56
|
+
def remove(target, key_path)
|
57
|
+
return if target.nil? || key_path.nil?
|
43
58
|
|
44
|
-
|
59
|
+
key_path = key_path.to_s
|
45
60
|
|
46
|
-
|
47
|
-
remove_observer_block(target, key_path)
|
48
|
-
end
|
61
|
+
callbacks[target].delete(key_path)
|
49
62
|
|
50
|
-
|
51
|
-
|
63
|
+
# If there no key_paths left for target, remove the target key
|
64
|
+
if callbacks[target].empty?
|
65
|
+
callbacks.delete(target)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def registered?(target, key_path)
|
70
|
+
callbacks[target].has_key? key_path.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def remove_all
|
74
|
+
callbacks.clear
|
75
|
+
end
|
52
76
|
|
53
|
-
|
54
|
-
|
55
|
-
|
77
|
+
def each_key_path
|
78
|
+
callbacks.each do |target, key_paths|
|
79
|
+
key_paths.each_key do |key_path|
|
80
|
+
yield target, key_path
|
81
|
+
end
|
56
82
|
end
|
57
83
|
end
|
58
|
-
remove_all_observer_blocks
|
59
|
-
end
|
60
84
|
|
61
|
-
|
85
|
+
private
|
62
86
|
|
63
|
-
|
64
|
-
|
65
|
-
|
87
|
+
def observeValueForKeyPath(key_path, ofObject: target, change: change, context: context)
|
88
|
+
key_paths = callbacks[target] || {}
|
89
|
+
blocks = key_paths[key_path] || []
|
90
|
+
|
91
|
+
args = change.values_at(*keys)
|
92
|
+
args << key_path
|
93
|
+
|
94
|
+
blocks.each do |block|
|
95
|
+
block.call(*args)
|
96
|
+
end
|
97
|
+
end
|
66
98
|
end
|
67
99
|
|
68
|
-
|
69
|
-
|
100
|
+
DEFAULT_OPTIONS = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
|
101
|
+
IMMIDEATE_OPTIONS = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
|
70
102
|
|
71
|
-
|
103
|
+
def observe(target = self, key_paths, &block)
|
104
|
+
key_paths = [key_paths].flatten
|
72
105
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
106
|
+
key_paths.each do |key_path|
|
107
|
+
if not observers_registry.registered?(target, key_path)
|
108
|
+
target.addObserver(observers_registry, forKeyPath:key_path, options:DEFAULT_OPTIONS, context:nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Add block even if observer is registed, so multiplie blocks can be invoked.
|
112
|
+
observers_registry.add(target, key_path, &block)
|
113
|
+
end
|
77
114
|
end
|
78
115
|
|
79
|
-
def
|
80
|
-
|
116
|
+
def observe!(target = self, key_paths, &block)
|
117
|
+
key_paths = [key_paths].flatten
|
81
118
|
|
82
|
-
key_paths
|
83
|
-
|
84
|
-
|
85
|
-
|
119
|
+
key_paths.each do |key_path|
|
120
|
+
registered = immediate_observers_registry.registered?(target, key_path)
|
121
|
+
|
122
|
+
immediate_observers_registry.add(target, key_path, &block)
|
123
|
+
|
124
|
+
# We need to first register the block, and then call addObserver, because
|
125
|
+
# observeValueForKeyPath will fire immedeately.
|
126
|
+
if not registered
|
127
|
+
target.addObserver(immediate_observers_registry, forKeyPath:key_path, options: IMMIDEATE_OPTIONS, context:nil)
|
128
|
+
end
|
86
129
|
end
|
87
130
|
end
|
88
131
|
|
89
|
-
def
|
90
|
-
|
132
|
+
def unobserve(target = self, key_paths)
|
133
|
+
remove_from_registry_if_exists(target, key_paths, observers_registry)
|
134
|
+
end
|
135
|
+
|
136
|
+
def unobserve!(target = self, key_paths)
|
137
|
+
remove_from_registry_if_exists(target, key_paths, immediate_observers_registry)
|
91
138
|
end
|
92
139
|
|
93
|
-
|
140
|
+
def unobserve_all
|
141
|
+
observers_registry.each_key_path do |target, key_path|
|
142
|
+
target.removeObserver(observers_registry, forKeyPath:key_path)
|
143
|
+
end
|
94
144
|
|
95
|
-
|
96
|
-
|
97
|
-
blocks = key_paths[key_path] || []
|
98
|
-
blocks.each do |block|
|
99
|
-
args = [change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey]]
|
100
|
-
args << change[NSKeyValueChangeIndexesKey] if collection?(change)
|
101
|
-
block.call(*args)
|
145
|
+
immediate_observers_registry.each_key_path do |target, key_path|
|
146
|
+
target.removeObserver(immediate_observers_registry, forKeyPath:key_path)
|
102
147
|
end
|
148
|
+
|
149
|
+
observers_registry.remove_all
|
150
|
+
immediate_observers_registry.remove_all
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
def observers_registry
|
155
|
+
@observers_registry ||= Registry.new
|
103
156
|
end
|
104
157
|
|
105
|
-
def
|
106
|
-
|
158
|
+
def immediate_observers_registry
|
159
|
+
@immediate_observers_registry ||= Registry.new([:new])
|
107
160
|
end
|
108
161
|
|
162
|
+
def remove_from_registry_if_exists(target, key_paths, registry)
|
163
|
+
key_paths = [key_paths].flatten
|
164
|
+
|
165
|
+
key_paths.each do |key_path|
|
166
|
+
if registry.registered?(target, key_path)
|
167
|
+
target.removeObserver(registry, forKeyPath:key_path)
|
168
|
+
registry.remove(target, key_path)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
109
172
|
end
|
110
173
|
end
|