bubble-wrap 1.8.0 → 1.9.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -9
  3. data/CHANGELOG.md +21 -2
  4. data/Gemfile.lock +8 -5
  5. data/README.md +54 -3
  6. data/Rakefile +7 -1
  7. data/lib/bubble-wrap/camera.rb +1 -1
  8. data/lib/bubble-wrap/core.rb +1 -1
  9. data/lib/bubble-wrap/font.rb +1 -1
  10. data/lib/bubble-wrap/loader.rb +4 -4
  11. data/lib/bubble-wrap/media.rb +1 -1
  12. data/lib/bubble-wrap/motion.rb +7 -1
  13. data/lib/bubble-wrap/version.rb +2 -2
  14. data/motion/core/app.rb +4 -0
  15. data/motion/core/device/ios/camera_wrapper.rb +1 -1
  16. data/motion/core/device/ios/screen.rb +2 -2
  17. data/motion/core/device/osx/screen.rb +1 -1
  18. data/motion/core/device/screen.rb +1 -1
  19. data/motion/core/ios/device.rb +1 -1
  20. data/motion/core/ios/ns_index_path.rb +11 -0
  21. data/motion/core/json.rb +2 -2
  22. data/motion/core/kvo.rb +118 -55
  23. data/motion/core/ns_notification_center.rb +2 -2
  24. data/motion/core/ns_url_request.rb +2 -2
  25. data/motion/core/osx/device.rb +1 -1
  26. data/motion/core/string.rb +7 -7
  27. data/motion/font/font.rb +1 -1
  28. data/motion/ios/8/location_constants.rb +21 -0
  29. data/motion/location/location.rb +38 -18
  30. data/motion/mail/result.rb +1 -1
  31. data/motion/media/media.rb +1 -1
  32. data/motion/motion/accelerometer.rb +55 -0
  33. data/motion/motion/device_motion.rb +139 -0
  34. data/motion/motion/gyroscope.rb +55 -0
  35. data/motion/motion/magnetometer.rb +55 -0
  36. data/motion/motion/motion.rb +0 -288
  37. data/motion/reactor.rb +3 -3
  38. data/motion/reactor/deferrable.rb +32 -32
  39. data/motion/reactor/periodic_timer.rb +1 -1
  40. data/motion/reactor/queue.rb +6 -6
  41. data/motion/reactor/thread_aware_deferrable.rb +1 -1
  42. data/motion/reactor/timer.rb +1 -1
  43. data/motion/rss_parser.rb +6 -3
  44. data/motion/shortcut.rb +1 -1
  45. data/motion/sms/result.rb +1 -1
  46. data/motion/test_suite_delegate.rb +1 -1
  47. data/motion/ui/ui_activity_view_controller_wrapper.rb +6 -1
  48. data/motion/ui/ui_alert_view.rb +21 -1
  49. data/motion/util/deprecated.rb +1 -1
  50. data/samples/alert/Gemfile.lock +1 -1
  51. data/spec/lib/bubble-wrap/requirement_spec.rb +2 -2
  52. data/spec/lib/bubble-wrap_spec.rb +1 -1
  53. data/spec/lib/motion_stub.rb +1 -1
  54. data/spec/motion/core/app_spec.rb +6 -0
  55. data/spec/motion/core/device/osx/screen_spec.rb +1 -1
  56. data/spec/motion/core/ios/ns_index_path_spec.rb +20 -0
  57. data/spec/motion/core/kvo_spec.rb +171 -58
  58. data/spec/motion/core/ns_notification_center_spec.rb +3 -3
  59. data/spec/motion/core/string_spec.rb +16 -16
  60. data/spec/motion/core_spec.rb +3 -3
  61. data/spec/motion/font/font_spec.rb +1 -1
  62. data/spec/motion/location/location_spec.rb +61 -9
  63. data/spec/motion/mail/result_spec.rb +7 -7
  64. data/spec/motion/media/player_spec.rb +1 -1
  65. data/spec/motion/reactor/thread_aware_deferrable_spec.rb +3 -3
  66. data/spec/motion/sms/result_spec.rb +6 -6
  67. data/spec/motion/ui/ui_alert_view_spec.rb +59 -1
  68. data/spec/motion/util/deprecated_spec.rb +1 -1
  69. metadata +17 -4
  70. data/motion/ios/7/uiactivity_view_controller_constants.rb +0 -10
@@ -16,7 +16,7 @@ module BubbleWrap
16
16
  if options[:common_modes]
17
17
  NSLog "[DEPRECATED - Option :common_modes] a Run Loop Mode is no longer needed."
18
18
  end
19
-
19
+
20
20
  self.interval = interval
21
21
 
22
22
  leeway = interval
@@ -2,8 +2,8 @@ module BubbleWrap
2
2
  module Reactor
3
3
  # A GCD scheduled, linear queue.
4
4
  #
5
- # This class provides a simple “Queue” like abstraction on top of the
6
- # GCD scheduler.
5
+ # This class provides a simple “Queue” like abstraction on top of the
6
+ # GCD scheduler.
7
7
  #
8
8
  # Useful as an API sugar for stateful protocols
9
9
  #
@@ -29,17 +29,17 @@ module BubbleWrap
29
29
  @items.size
30
30
  end
31
31
 
32
- # Push items onto the work queue. The items will not appear in the queue
32
+ # Push items onto the work queue. The items will not appear in the queue
33
33
  # immediately, but will be scheduled for addition.
34
34
  def push(*items)
35
- ::BubbleWrap::Reactor.schedule do
35
+ ::BubbleWrap::Reactor.schedule do
36
36
  @items.push(*items)
37
37
  @popq.shift.call @items.shift until @items.empty? || @popq.empty?
38
38
  end
39
39
  end
40
40
 
41
- # Pop items off the queue, running the block on the work queue. The pop
42
- # will not happen immediately, but at some point in the future, either
41
+ # Pop items off the queue, running the block on the work queue. The pop
42
+ # will not happen immediately, but at some point in the future, either
43
43
  # in the next tick, if the queue has data, or when the queue is populated.
44
44
  def pop(*args, &blk)
45
45
  cb = proc do
@@ -3,7 +3,7 @@ module BubbleWrap
3
3
  class ThreadAwareDeferrable < DefaultDeferrable
4
4
  include ::BubbleWrap::Reactor::Deferrable
5
5
 
6
-
6
+
7
7
  # need to store the the queue in callback / errback
8
8
  def callback(&blk)
9
9
  return unless blk
@@ -14,7 +14,7 @@ module BubbleWrap
14
14
  ensure
15
15
  src.cancel!
16
16
  end
17
- end
17
+ end
18
18
  end
19
19
 
20
20
  # Cancel the timer
data/motion/rss_parser.rb CHANGED
@@ -28,10 +28,10 @@ module BubbleWrap
28
28
  # RSSItem is a simple class that holds all of RSS items.
29
29
  # Extend this class to display/process the item differently.
30
30
  class RSSItem
31
- attr_accessor :title, :description, :link, :guid, :pubDate, :enclosure
31
+ attr_accessor :title, :description, :link, :guid, :pubDate, :creator, :category, :encoded, :enclosure
32
32
 
33
33
  def initialize
34
- @title, @description, @link, @pubDate, @guid = '', '', '', '', ''
34
+ @title, @description, @link, @pubDate, @guid, @creator, @category, @encoded = '', '', '', '', ''
35
35
  end
36
36
 
37
37
  def to_hash
@@ -41,6 +41,9 @@ module BubbleWrap
41
41
  :link => link,
42
42
  :pubDate => pubDate,
43
43
  :guid => guid,
44
+ :enclosure => enclosure,
45
+ :category => category,
46
+ :encoded => encoded,
44
47
  :enclosure => enclosure
45
48
  }
46
49
  end
@@ -56,7 +59,6 @@ module BubbleWrap
56
59
  @source = url
57
60
  @source_type = :url
58
61
  end
59
- self.state = :initializes
60
62
  self
61
63
  end
62
64
 
@@ -85,6 +87,7 @@ module BubbleWrap
85
87
 
86
88
  @parser.shouldProcessNamespaces = true
87
89
  @parser.delegate ||= self
90
+ self.state = :initializes
88
91
  @parser.parse
89
92
  end
90
93
 
data/motion/shortcut.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Make sure that
1
+ # Make sure that
2
2
  # Both BubbleWrap and BW are defined. This file is depended on by everything
3
3
  # else in BubbleWrap, so don't stuff anything in here unless you know why
4
4
  # you're doing it.
data/motion/sms/result.rb CHANGED
@@ -18,7 +18,7 @@ module BubbleWrap
18
18
  def failed?
19
19
  self.result == MessageComposeResultFailed
20
20
  end
21
-
21
+
22
22
  end
23
23
  end
24
24
  end
@@ -65,4 +65,4 @@ class TestSuiteOSXDelegate
65
65
  item.submenu = menu
66
66
  item
67
67
  end
68
- end
68
+ end
@@ -41,6 +41,11 @@ module BW
41
41
  UIActivityTypePrint,
42
42
  UIActivityTypeCopyToPasteboard,
43
43
  UIActivityTypeAssignToContact,
44
- UIActivityTypeSaveToCameraRoll
44
+ UIActivityTypeSaveToCameraRoll,
45
+ UIActivityTypeAddToReadingList,
46
+ UIActivityTypePostToFlickr,
47
+ UIActivityTypePostToVimeo,
48
+ UIActivityTypePostToTencentWeibo,
49
+ UIActivityTypeAirDrop
45
50
  )
46
51
  end
@@ -10,6 +10,22 @@ module BW
10
10
  :did_dismiss
11
11
  ]
12
12
 
13
+ KEYBOARD_TYPES = {
14
+ default: UIKeyboardTypeDefault,
15
+ ascii: UIKeyboardTypeASCIICapable,
16
+ numbers_punctuation: UIKeyboardTypeNumbersAndPunctuation,
17
+ url: UIKeyboardTypeURL,
18
+ number_pad: UIKeyboardTypeNumberPad,
19
+ phone_pad: UIKeyboardTypePhonePad,
20
+ name_phone_pad: UIKeyboardTypeNamePhonePad,
21
+ email_address: UIKeyboardTypeEmailAddress,
22
+ email: UIKeyboardTypeEmailAddress, # Duplicate to help developers
23
+ decimal_pad: UIKeyboardTypeDecimalPad,
24
+ twitter: UIKeyboardTypeTwitter,
25
+ web_search: UIKeyboardTypeWebSearch,
26
+ alphabet: UIKeyboardTypeASCIICapable
27
+ }
28
+
13
29
  class << self
14
30
  attr_reader :callbacks
15
31
 
@@ -50,7 +66,11 @@ module BW
50
66
  cancel_button_index: 0}.merge!(options)
51
67
  options[:style] = :plain_text_input
52
68
  new(options, &block).tap do |view|
53
- view.textFieldAtIndex(0).placeholder = options[:placeholder] if options[:placeholder]
69
+ view.textFieldAtIndex(0).tap do |tf|
70
+ tf.text = options[:text] if options[:text]
71
+ tf.placeholder = options[:placeholder] if options[:placeholder]
72
+ tf.keyboardType = (KEYBOARD_TYPES[options[:keyboard_type]] || options[:keyboard_type]) if options[:keyboard_type]
73
+ end
54
74
  end
55
75
  end
56
76
 
@@ -39,4 +39,4 @@ module BubbleWrap
39
39
  base.extend(self)
40
40
  end
41
41
  end
42
- end
42
+ end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../../
3
3
  specs:
4
- bubble-wrap (1.7.1)
4
+ bubble-wrap (1.8.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -10,11 +10,11 @@ describe BubbleWrap::Requirement do
10
10
  describe '.scan' do
11
11
  before do
12
12
  @subject.clear!
13
- @root_path = File.expand_path('../../../../', __FILE__)
13
+ @root_path = File.expand_path('../../../../', __FILE__)
14
14
  end
15
15
 
16
16
  it 'asking for a not-yet-found file raises an exception' do
17
- should.raise(Exception) do
17
+ should.raise(Exception) do
18
18
  @subject.find('foo')
19
19
  end
20
20
  end
@@ -19,7 +19,7 @@ describe BubbleWrap do
19
19
  BW::Requirement.clear!
20
20
  BW.require '../motion/core.rb'
21
21
  BW::Requirement.files.member?(File.expand_path('../../../motion/core.rb', __FILE__)).should == true
22
- end
22
+ end
23
23
 
24
24
  it 'finds files with absolute paths' do
25
25
  BW::Requirement.clear!
@@ -5,7 +5,7 @@ module Motion
5
5
  def self.setup
6
6
  end
7
7
  end
8
-
8
+
9
9
  class Config
10
10
  def files_dependencies
11
11
  end
@@ -60,6 +60,12 @@ describe BubbleWrap::App do
60
60
  end
61
61
  end
62
62
 
63
+ describe '.short_version' do
64
+ it 'returns the application short version' do
65
+ App.short_version.should == '3.2.1'
66
+ end
67
+ end
68
+
63
69
  describe '.run_after' do
64
70
  class DelayedRunAfterTest; attr_accessor :test_value end
65
71
 
@@ -23,4 +23,4 @@ describe BubbleWrap::Device::Screen do
23
23
  end
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -0,0 +1,20 @@
1
+ describe "NSIndexPathWrap" do
2
+
3
+ before do
4
+ @index = NSIndexPath.indexPathForRow(0, inSection:3)
5
+ end
6
+
7
+ it "should support #+ and #-" do
8
+ @index = @index + 1
9
+ @index.row.should == 1
10
+ @index = @index + 1
11
+ @index.row.should == 2
12
+ @index = @index + 12
13
+ @index.row.should == 14
14
+ @index = @index - 3
15
+ @index.row.should == 11
16
+ @index = @index - 0
17
+ @index.row.should == 11
18
+ end
19
+
20
+ end
@@ -11,29 +11,27 @@ describe BubbleWrap::KVO do
11
11
  @items = [ "Apple", "Banana", "Chickpeas" ]
12
12
  @age = 1
13
13
 
14
- if App.osx?
15
- @label = NSTextField.alloc.initWithFrame [[0,0],[320, 30]]
16
- @label.stringValue = "Foo"
17
- else
18
- @label = UILabel.alloc.initWithFrame [[0,0],[320, 30]]
19
- @label.text = "Foo"
20
- end
14
+ @label = text_class.alloc.initWithFrame [[0,0],[320, 30]]
15
+
16
+ set_text "Foo"
21
17
  end
22
18
 
23
19
  # Test helper
24
20
 
25
21
  def get_text
26
- App.osx? ? @label.stringValue : @label.text
22
+ @label.send(text_method_name)
27
23
  end
28
24
 
29
25
  def set_text(text)
30
- method = App.osx? ? :stringValue : :text
31
- @label.send("#{method}=", text)
26
+ @label.send("#{text_method_name}=", text)
32
27
  end
33
28
 
34
29
  def observe_label(&block)
35
- method = App.osx? ? :stringValue : :text
36
- observe(@label, method, &block)
30
+ observe(@label, text_method_name, &block)
31
+ end
32
+
33
+ def observe_label!(&block)
34
+ observe!(@label, text_method_name, &block)
37
35
  end
38
36
 
39
37
  def observe_collection(&block)
@@ -41,8 +39,23 @@ describe BubbleWrap::KVO do
41
39
  end
42
40
 
43
41
  def unobserve_label
44
- method = App.osx? ? :stringValue : :text
45
- unobserve(@label, method)
42
+ unobserve(@label, text_method_name)
43
+ end
44
+
45
+ def unobserve_label!
46
+ unobserve!(@label, text_method_name)
47
+ end
48
+
49
+ def text_method_name
50
+ App.osx? ? :stringValue : :text
51
+ end
52
+
53
+ def text_class
54
+ App.osx? ? NSTextField : UILabel
55
+ end
56
+
57
+ def update_collection
58
+ self.items += [ "Rice" ]
46
59
  end
47
60
 
48
61
  # def unobserve_all
@@ -52,9 +65,9 @@ describe BubbleWrap::KVO do
52
65
 
53
66
  end
54
67
 
55
- describe "Callbacks" do
68
+ describe "Registry" do
56
69
  before do
57
- @example = KvoExample.new
70
+ @example = BW::KVO::Registry.new
58
71
  end
59
72
 
60
73
  after do
@@ -66,21 +79,21 @@ describe BubbleWrap::KVO do
66
79
  it "should add an observer block" do
67
80
  target = Object.new
68
81
  block = lambda { |old_value, new_value| }
69
- @example.send(:add_observer_block, target, "key_path", &block)
70
- @example.send(:registered?, target, "key_path").should == true
82
+ @example.add(target, "key_path", &block)
83
+ @example.registered?(target, "key_path").should == true
71
84
  end
72
85
 
73
86
  it "should not add an observer block if the key path is not present" do
74
87
  target = Object.new
75
88
  block = lambda { |old_value, new_value| }
76
- @example.send(:add_observer_block, target, nil, &block)
77
- @example.send(:registered?, target, nil).should == false
89
+ @example.add(target, nil, &block)
90
+ @example.registered?(target, nil).should == false
78
91
  end
79
92
 
80
93
  it "should not add an observer block if the block is not present" do
81
94
  target = Object.new
82
- @example.send(:add_observer_block, target, "key_path")
83
- @example.send(:registered?, target, "key_path").should == false
95
+ @example.add(target, "key_path")
96
+ @example.registered?(target, "key_path").should == false
84
97
  end
85
98
 
86
99
  # remove
@@ -88,35 +101,35 @@ describe BubbleWrap::KVO do
88
101
  it "should remove an observer block" do
89
102
  target = Object.new
90
103
  block = lambda { |old_value, new_value| }
91
- @example.send(:add_observer_block, target, "key_path", &block)
92
- @example.send(:remove_observer_block, target, "key_path")
93
- @example.send(:registered?, target, "key_path").should == false
104
+ @example.add(target, "key_path", &block)
105
+ @example.remove(target, "key_path")
106
+ @example.registered?(target, "key_path").should == false
94
107
  end
95
108
 
96
109
  it "should not remove an observer block if the target is not present" do
97
110
  target = Object.new
98
111
  block = lambda { |old_value, new_value| }
99
- @example.send(:add_observer_block, target, "key_path", &block)
100
- @example.send(:remove_observer_block, nil, "key_path")
101
- @example.send(:registered?, target, "key_path").should == true
112
+ @example.add(target, "key_path", &block)
113
+ @example.remove(nil, "key_path")
114
+ @example.registered?(target, "key_path").should == true
102
115
  end
103
116
 
104
117
  it "should not remove an observer block if the key path is not present" do
105
118
  target = Object.new
106
119
  block = lambda { |old_value, new_value| }
107
- @example.send(:add_observer_block, target, "key_path", &block)
108
- @example.send(:remove_observer_block, target, nil)
109
- @example.send(:registered?, target, "key_path").should == true
120
+ @example.add(target, "key_path", &block)
121
+ @example.remove(target, nil)
122
+ @example.registered?(target, "key_path").should == true
110
123
  end
111
124
 
112
125
  it "should remove only one observer block" do
113
126
  target = Object.new
114
127
  block = lambda { |old_value, new_value| }
115
- @example.send(:add_observer_block, target, "key_path1", &block)
116
- @example.send(:add_observer_block, target, "key_path2", &block)
117
- @example.send(:remove_observer_block, target, "key_path1")
118
- @example.send(:registered?, target, "key_path1").should == false
119
- @example.send(:registered?, target, "key_path2").should == true
128
+ @example.add(target, "key_path1", &block)
129
+ @example.add(target, "key_path2", &block)
130
+ @example.remove(target, "key_path1")
131
+ @example.registered?(target, "key_path1").should == false
132
+ @example.registered?(target, "key_path2").should == true
120
133
  end
121
134
 
122
135
  # remove all
@@ -124,28 +137,28 @@ describe BubbleWrap::KVO do
124
137
  it "should remove all observer blocks" do
125
138
  target = Object.new
126
139
  block = lambda { |old_value, new_value| }
127
- @example.send(:add_observer_block, target, "key_path1", &block)
128
- @example.send(:add_observer_block, target, "key_path2", &block)
129
- @example.send(:remove_all_observer_blocks)
130
- @example.send(:registered?, target, "key_path1").should == false
131
- @example.send(:registered?, target, "key_path2").should == false
140
+ @example.add(target, "key_path1", &block)
141
+ @example.add(target, "key_path2", &block)
142
+ @example.remove_all
143
+ @example.registered?(target, "key_path1").should == false
144
+ @example.registered?(target, "key_path2").should == false
132
145
  end
133
146
 
134
147
  it "should remove target from targets if no observers remain" do
135
148
  target = Object.new
136
149
  block = lambda { |old_value, new_value| }
137
- @example.send(:add_observer_block, target, "key_path", &block)
138
- @example.send(:remove_observer_block, target, "key_path")
139
- @example.instance_variable_get(:@targets).length.should == 0
150
+ @example.add(target, "key_path", &block)
151
+ @example.remove(target, "key_path")
152
+ @example.callbacks.length.should == 0
140
153
  end
141
154
 
142
155
  it "should not remove target from targets if observers remain" do
143
156
  target = Object.new
144
157
  block = lambda { |old_value, new_value| }
145
- @example.send(:add_observer_block, target, "key_path1", &block)
146
- @example.send(:add_observer_block, target, "key_path2", &block)
147
- @example.send(:remove_observer_block, target, "key_path1")
148
- @example.instance_variable_get(:@targets).length.should > 0
158
+ @example.add(target, "key_path1", &block)
159
+ @example.add(target, "key_path2", &block)
160
+ @example.remove(target, "key_path1")
161
+ @example.callbacks.length.should > 0
149
162
  end
150
163
 
151
164
  end
@@ -174,6 +187,18 @@ describe BubbleWrap::KVO do
174
187
  observed.should == true
175
188
  end
176
189
 
190
+ it "should immediately observe a key path" do
191
+ @example.set_text "Foo"
192
+
193
+ observed = false
194
+ @example.observe_label! do |new_value|
195
+ observed = true
196
+ new_value.should == "Foo"
197
+ end
198
+
199
+ observed.should == true
200
+ end
201
+
177
202
  it "should observe a key path with more than one block" do
178
203
  observed_one = false
179
204
  observed_two = false
@@ -207,6 +232,17 @@ describe BubbleWrap::KVO do
207
232
  observed.should == false
208
233
  end
209
234
 
235
+ it "should unobserve immediate observer" do
236
+ observed_times = 0
237
+ @example.observe_label do |old_value, new_value|
238
+ observed_times += 1
239
+ end
240
+ @example.unobserve_label!
241
+
242
+ @example.set_text "Bar"
243
+ observed_times.should == 1
244
+ end
245
+
210
246
  # without target
211
247
 
212
248
  it "should observe a key path without a target" do
@@ -232,19 +268,96 @@ describe BubbleWrap::KVO do
232
268
  observed.should == false
233
269
  end
234
270
 
235
- end
271
+ # with multiple keypaths
272
+
273
+ it "should observe multiple key paths" do
274
+ observed = []
275
+ @example.observe [:age, :items] do |old_value, new_value|
276
+ observed << [old_value, new_value]
277
+ end
278
+
279
+ @example.age = 2
280
+ @example.age = 3
281
+ @example.update_collection
282
+
283
+ observed.should.be == [
284
+ [1, 2],
285
+ [2, 3],
286
+ [
287
+ ["Apple", "Banana", "Chickpeas"],
288
+ ["Apple", "Banana", "Chickpeas", "Rice"]
289
+ ]
290
+ ]
291
+ end
292
+
293
+ it "should observe multiple key paths with key_path argument" do
294
+ observed_changes = []
295
+ @example.observe [:age, :items] do |old_value, new_value, key_path|
296
+ observed_changes << { key_path => [old_value, new_value] }
297
+ end
236
298
 
237
- =begin
238
- it "should be able to observe a collection" do
239
- observed = false
240
- @example.observe_collection do |old_value, new_value, indexes|
241
- puts "#{collection} #{old_value} #{new_value} #{indexes}"
242
- observed = true
299
+ @example.age = 2
300
+ @example.age = 3
301
+ @example.update_collection
302
+
303
+ observed_changes.should.be == [
304
+ {"age" => [1, 2]},
305
+ {"age" => [2, 3]},
306
+ {
307
+ "items" => [
308
+ ["Apple", "Banana", "Chickpeas"],
309
+ ["Apple", "Banana", "Chickpeas", "Rice"]
310
+ ]
311
+ }
312
+ ]
243
313
  end
244
314
 
245
- @example.items << "Dragonfruit"
246
- observed.should == true
315
+ it "should immediately observe multiple key paths" do
316
+ observed_changes = []
317
+ @example.observe! [:age, :items] do |new_value|
318
+ observed_changes << new_value
319
+ end
320
+
321
+ @example.age = 2
322
+ @example.age = 3
323
+ @example.update_collection
324
+
325
+ observed_changes.should.be == [1, ["Apple", "Banana", "Chickpeas"], 2, 3, ["Apple", "Banana", "Chickpeas", "Rice"]]
326
+ end
327
+
328
+ it "should immediately observe multiple key paths with key_path argument" do
329
+ observed_changes = []
330
+ @example.observe! [:age, :items] do |new_value, key_path|
331
+ observed_changes << { key_path => new_value }
332
+ end
333
+
334
+ @example.age = 2
335
+ @example.age = 3
336
+ @example.update_collection
337
+
338
+ observed_changes.should.be == [
339
+ {"age" => 1},
340
+ {"items" => ["Apple", "Banana", "Chickpeas"]},
341
+ {"age" => 2},
342
+ {"age" => 3},
343
+ {"items" => ["Apple", "Banana", "Chickpeas", "Rice"]}
344
+ ]
345
+ end
346
+
347
+ it "should unobserve multiple key paths" do
348
+ observed = 0
349
+
350
+ @example.observe [:age, :items] do
351
+ observed += 1
352
+ end
353
+
354
+ @example.unobserve [:age]
355
+
356
+ @example.age = 2
357
+ @example.update_collection
358
+
359
+ observed.should.be == 1
360
+ end
247
361
  end
248
- =end
249
362
 
250
363
  end