bubble-wrap 1.3.0 → 1.4.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 +6 -14
- data/.travis.yml +2 -1
- data/CHANGELOG.md +26 -2
- data/GETTING_STARTED.md +1 -1
- data/Gemfile.lock +1 -1
- data/HACKING.md +6 -4
- data/README.md +83 -3
- data/Rakefile +9 -7
- data/lib/bubble-wrap/all.rb +2 -2
- data/lib/bubble-wrap/mail.rb +9 -0
- data/lib/bubble-wrap/sms.rb +9 -0
- data/lib/bubble-wrap/ui.rb +6 -2
- data/lib/bubble-wrap/version.rb +1 -1
- data/motion/core.rb +1 -1
- data/motion/core/app.rb +7 -2
- data/motion/core/device/ios/camera.rb +3 -2
- data/motion/core/device/ios/screen.rb +19 -0
- data/motion/core/ios/app.rb +13 -1
- data/motion/core/ios/device.rb +5 -0
- data/motion/core/json.rb +1 -3
- data/motion/core/kvo.rb +11 -13
- data/motion/core/persistence.rb +8 -1
- data/motion/core/string.rb +3 -3
- data/motion/core/time.rb +5 -0
- data/motion/http.rb +1 -1
- data/motion/http/query.rb +39 -19
- data/motion/http/response.rb +4 -4
- data/motion/mail/mail.rb +59 -0
- data/motion/mail/result.rb +29 -0
- data/motion/reactor/eventable.rb +3 -2
- data/motion/reactor/periodic_timer.rb +12 -8
- data/motion/reactor/timer.rb +11 -7
- data/motion/sms/result.rb +24 -0
- data/motion/sms/sms.rb +47 -0
- data/motion/ui/pollute.rb +4 -1
- data/motion/ui/ui_alert_view.rb +15 -8
- data/motion/ui/ui_control_wrapper.rb +16 -0
- data/motion/ui/ui_view_controller_wrapper.rb +13 -0
- data/motion/ui/ui_view_wrapper.rb +55 -0
- data/resources/Localizable.strings +1 -0
- data/samples/gesture/Gemfile +2 -2
- data/samples/location/Gemfile +1 -1
- data/samples/osx/Gemfile +2 -2
- data/spec/motion/core/app_spec.rb +6 -0
- data/spec/motion/core/device/ios/camera_spec.rb +3 -3
- data/spec/motion/core/device/ios/screen_spec.rb +45 -0
- data/spec/motion/core/ios/app_spec.rb +29 -0
- data/spec/motion/core/persistence_spec.rb +25 -0
- data/spec/motion/core/string_spec.rb +2 -2
- data/spec/motion/core/time_spec.rb +14 -4
- data/spec/motion/core_spec.rb +9 -8
- data/spec/motion/http/query_spec.rb +92 -15
- data/spec/motion/http/response_spec.rb +4 -3
- data/spec/motion/location/location_spec.rb +1 -1
- data/spec/motion/mail/mail_spec.rb +125 -0
- data/spec/motion/mail/result_spec.rb +53 -0
- data/spec/motion/reactor/eventable_spec.rb +85 -0
- data/spec/motion/reactor_spec.rb +0 -20
- data/spec/motion/sms/result_spec.rb +38 -0
- data/spec/motion/sms/sms_spec.rb +71 -0
- data/spec/motion/ui/pollute_spec.rb +13 -0
- data/spec/motion/ui/ui_bar_button_item_spec.rb +8 -8
- data/spec/motion/ui/ui_control_wrapper_spec.rb +35 -0
- data/spec/motion/ui/ui_view_controller_wrapper_spec.rb +34 -0
- data/spec/motion/ui/ui_view_wrapper_spec.rb +62 -0
- data/travis.sh +7 -0
- metadata +52 -22
- data/motion/ui/gestures.rb +0 -57
- data/motion/ui/ui_control.rb +0 -14
- data/motion/ui/ui_view_controller.rb +0 -11
- data/spec/motion/ui/gestures_spec.rb +0 -62
- data/spec/motion/ui/ui_control_spec.rb +0 -42
@@ -0,0 +1,53 @@
|
|
1
|
+
describe BW::Mail::Result do
|
2
|
+
|
3
|
+
before do
|
4
|
+
@subject = BW::Mail::Result.new(MFMailComposeResultCancelled, nil)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should set sent? when sent" do
|
8
|
+
@subject.result = MFMailComposeResultSent
|
9
|
+
@subject.should.be.sent
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not set sent? when not sent" do
|
13
|
+
@subject.result = MFMailComposeResultCancelled
|
14
|
+
@subject.should.not.be.sent
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set canceled? when canceled" do
|
18
|
+
@subject.result = MFMailComposeResultCancelled
|
19
|
+
@subject.should.be.canceled
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not set canceled? when not canceled" do
|
23
|
+
@subject.result = MFMailComposeResultSent
|
24
|
+
@subject.should.not.be.canceled
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should set saved? when saved" do
|
28
|
+
@subject.result = MFMailComposeResultSaved
|
29
|
+
@subject.should.be.saved
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not set saved? when not saved" do
|
33
|
+
@subject.result = MFMailComposeResultFailed
|
34
|
+
@subject.should.not.be.saved
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should set failed? when failed" do
|
38
|
+
@subject.result = MFMailComposeResultFailed
|
39
|
+
@subject.should.be.failed
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not set failed? when not failed" do
|
43
|
+
@subject.result = MFMailComposeResultSent
|
44
|
+
@subject.should.not.be.failed
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should set failed? when error" do
|
48
|
+
@subject.result = MFMailComposeResultCancelled
|
49
|
+
@subject.error = :errored
|
50
|
+
@subject.should.be.failed
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -30,6 +30,21 @@ describe BubbleWrap::Reactor::Eventable do
|
|
30
30
|
@subject.off(:foo, &proof)
|
31
31
|
events[:foo].member?(proof).should == false
|
32
32
|
end
|
33
|
+
|
34
|
+
it 'calls other event procs when a proc unregisters itself' do
|
35
|
+
@proxy.proof = 0
|
36
|
+
proof1 = proc do |r|
|
37
|
+
@proxy.proof += r
|
38
|
+
@subject.off(:foo, &proof1)
|
39
|
+
end
|
40
|
+
proof2 = proc do |r|
|
41
|
+
@proxy.proof += r
|
42
|
+
end
|
43
|
+
@subject.on(:foo, &proof1)
|
44
|
+
@subject.on(:foo, &proof2)
|
45
|
+
@subject.trigger(:foo, 2)
|
46
|
+
@proxy.proof.should == 4
|
47
|
+
end
|
33
48
|
end
|
34
49
|
|
35
50
|
describe '.trigger' do
|
@@ -42,6 +57,15 @@ describe BubbleWrap::Reactor::Eventable do
|
|
42
57
|
@proxy.proof.should == true
|
43
58
|
end
|
44
59
|
|
60
|
+
it 'calls event procs for correct event' do
|
61
|
+
@proxy.proof = false
|
62
|
+
@subject.on(:foo) do |r|
|
63
|
+
@proxy.proof = r
|
64
|
+
end
|
65
|
+
@subject.trigger(:bar, true)
|
66
|
+
@proxy.proof.should == false
|
67
|
+
end
|
68
|
+
|
45
69
|
it 'calls all the event procs' do
|
46
70
|
@proxy.proof = 0
|
47
71
|
@subject.on(:foo) { |r| @proxy.proof += r }
|
@@ -50,6 +74,67 @@ describe BubbleWrap::Reactor::Eventable do
|
|
50
74
|
@subject.trigger(:foo, 2)
|
51
75
|
@proxy.proof.should == 6
|
52
76
|
end
|
77
|
+
|
78
|
+
class TestUIViewControllerWithEventable
|
79
|
+
include BubbleWrap::Reactor::Eventable
|
80
|
+
def test_on
|
81
|
+
on(:foo) do
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def dealloc
|
85
|
+
$test_dealloc = true
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'memory implications' do
|
91
|
+
|
92
|
+
it 'does not cause a retain-cycle prior to loading __events__' do
|
93
|
+
autorelease_pool do
|
94
|
+
$test_dealloc = false
|
95
|
+
TestUIViewControllerWithEventable.alloc.init
|
96
|
+
end
|
97
|
+
wait 0 do
|
98
|
+
$test_dealloc.should == true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'does not cause a retain-cycle after calling trigger' do
|
103
|
+
autorelease_pool do
|
104
|
+
autorelease_pool do
|
105
|
+
$test_dealloc = false
|
106
|
+
obj = TestUIViewControllerWithEventable.alloc.init
|
107
|
+
obj.trigger(:something)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
wait 0 do
|
111
|
+
$test_dealloc.should == true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'does not cause a retain-cycle after loading __events__' do
|
116
|
+
autorelease_pool do
|
117
|
+
$test_dealloc = false
|
118
|
+
obj = TestUIViewControllerWithEventable.alloc.init
|
119
|
+
obj.send(:__events__)
|
120
|
+
end
|
121
|
+
wait 0 do
|
122
|
+
$test_dealloc.should == true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'does not cause a retain-cycle after adding an event' do
|
127
|
+
autorelease_pool do
|
128
|
+
$test_dealloc = false
|
129
|
+
obj = TestUIViewControllerWithEventable.alloc.init
|
130
|
+
obj.test_on
|
131
|
+
end
|
132
|
+
wait 0 do
|
133
|
+
$test_dealloc.should == true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
53
138
|
end
|
54
139
|
|
55
140
|
end
|
data/spec/motion/reactor_spec.rb
CHANGED
@@ -65,17 +65,6 @@ describe BubbleWrap::Reactor do
|
|
65
65
|
@proxy.proof.should >= 2
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
69
|
-
it 'runs callbacks repeatedly in common runloop modes' do
|
70
|
-
@proxy.proof = 0
|
71
|
-
@timer = @subject.add_periodic_timer 0.5, :common_modes => true do
|
72
|
-
@proxy.proof = @proxy.proof + 1
|
73
|
-
@subject.cancel_timer(@timer) if @proxy.proof > 2
|
74
|
-
end
|
75
|
-
wait 1.1 do
|
76
|
-
@proxy.proof.should >= 2
|
77
|
-
end
|
78
|
-
end
|
79
68
|
end
|
80
69
|
|
81
70
|
describe '.cancel_timer' do
|
@@ -96,15 +85,6 @@ describe BubbleWrap::Reactor do
|
|
96
85
|
@subject.cancel_timer(timer)
|
97
86
|
@proxy.proof.should == true
|
98
87
|
end
|
99
|
-
|
100
|
-
it 'cancels common modes periodic timers' do
|
101
|
-
@proxy.proof = true
|
102
|
-
timer = @subject.add_periodic_timer 10.0, :common_modes => true do
|
103
|
-
@proxy.proof = false
|
104
|
-
end
|
105
|
-
@subject.cancel_timer(timer)
|
106
|
-
@proxy.proof.should == true
|
107
|
-
end
|
108
88
|
end
|
109
89
|
|
110
90
|
describe '.defer' do
|
@@ -0,0 +1,38 @@
|
|
1
|
+
describe BW::SMS::Result do
|
2
|
+
|
3
|
+
before do
|
4
|
+
@subject = BW::SMS::Result.new(MessageComposeResultCancelled)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should set sent? when sent" do
|
8
|
+
@subject.result = MessageComposeResultSent
|
9
|
+
@subject.should.be.sent
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not set sent? when not sent" do
|
13
|
+
@subject.result = MessageComposeResultFailed
|
14
|
+
@subject.should.not.be.sent
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set canceled? when canceled" do
|
18
|
+
@subject.result = MessageComposeResultCancelled
|
19
|
+
@subject.should.be.canceled
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not set canceled? when not canceled" do
|
23
|
+
@subject.result = MessageComposeResultFailed
|
24
|
+
@subject.should.not.be.canceled
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "should set failed? when failed" do
|
29
|
+
@subject.result = MessageComposeResultFailed
|
30
|
+
@subject.should.be.failed
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not set failed? when not failed" do
|
34
|
+
@subject.result = MessageComposeResultSent
|
35
|
+
@subject.should.not.be.failed
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Mocking the presentViewController
|
2
|
+
class MessageViewController < UIViewController
|
3
|
+
attr_accessor :expectation
|
4
|
+
|
5
|
+
def presentModalViewController(modal, animated: animated)
|
6
|
+
expectation.call modal, animated
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Monkey-patching MFMessageComposeViewController
|
11
|
+
# So we can access the values that are set.
|
12
|
+
# This of course breaks MFMessageComposeViewController from actually working,
|
13
|
+
# but it's testable.
|
14
|
+
class MFMessageComposeViewController
|
15
|
+
attr_accessor :recipients, :body
|
16
|
+
|
17
|
+
# for iOS7 compatibility
|
18
|
+
# on similators, MFMessageComposeViewController.alloc.init returns nil
|
19
|
+
def init
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe BW::SMS do
|
25
|
+
describe ".compose" do
|
26
|
+
before do
|
27
|
+
@view_controller = MessageViewController.new
|
28
|
+
@standard_message_options = {
|
29
|
+
delegate: @view_controller,
|
30
|
+
to: [ "1(234)567-8910" ],
|
31
|
+
message: "This is my message. It isn't very long.",
|
32
|
+
animated: false
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should open the message controller in a modal" do
|
37
|
+
@view_controller.expectation = lambda { |message_controller, animated|
|
38
|
+
message_controller.should.be.kind_of(MFMessageComposeViewController)
|
39
|
+
}
|
40
|
+
|
41
|
+
BW::SMS.compose @standard_message_options
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should create a message controller with the right recipient address set" do
|
45
|
+
@view_controller.expectation = lambda { |message_controller, animated|
|
46
|
+
message_controller.recipients.should.be.kind_of(Array)
|
47
|
+
message_controller.recipients.should == @standard_message_options[:to]
|
48
|
+
}
|
49
|
+
|
50
|
+
BubbleWrap::SMS.compose @standard_message_options
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
it "should create a message controller with the right message: set" do
|
55
|
+
@view_controller.expectation = lambda { |message_controller, animated|
|
56
|
+
message_controller.body.should.be.kind_of(String)
|
57
|
+
message_controller.body.should == @standard_message_options[:message]
|
58
|
+
}
|
59
|
+
|
60
|
+
BubbleWrap::SMS.compose @standard_message_options
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should create a mail controller with the right animation" do
|
64
|
+
@view_controller.expectation = lambda { |message_controller, animated|
|
65
|
+
animated.should.be.false
|
66
|
+
}
|
67
|
+
BubbleWrap::SMS.compose @standard_message_options
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe "UIKit pollution" do
|
2
|
+
it "pollutes UIControl" do
|
3
|
+
UIControl.ancestors.should.include BW::UIControlWrapper
|
4
|
+
end
|
5
|
+
|
6
|
+
it "pollutes UIView" do
|
7
|
+
UIView.ancestors.should.include BW::UIViewWrapper
|
8
|
+
end
|
9
|
+
|
10
|
+
it "pollutes UIViewController" do
|
11
|
+
UIViewController.ancestors.should.include BW::UIViewControllerWrapper
|
12
|
+
end
|
13
|
+
end
|
@@ -9,8 +9,8 @@ describe BW::UIBarButtonItem do
|
|
9
9
|
|
10
10
|
describe "given an invalid object" do
|
11
11
|
it "raises an exception" do
|
12
|
-
exception = should.raise(ArgumentError) { BW::UIBarButtonItem.styled(:plain,
|
13
|
-
exception.message.should.equal("invalid object -
|
12
|
+
exception = should.raise(ArgumentError) { BW::UIBarButtonItem.styled(:plain, 2) }
|
13
|
+
exception.message.should.equal("invalid object - 2")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -87,7 +87,7 @@ describe BW::UIBarButtonItem do
|
|
87
87
|
before do
|
88
88
|
@object = UIImage.alloc.init
|
89
89
|
@target = -> { true }
|
90
|
-
@subject = BW::UIBarButtonItem.styled(:
|
90
|
+
@subject = BW::UIBarButtonItem.styled(:done, @object, &@target)
|
91
91
|
end
|
92
92
|
|
93
93
|
it "has the correct class" do
|
@@ -99,7 +99,7 @@ describe BW::UIBarButtonItem do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
it "has the correct style" do
|
102
|
-
@subject.style.should.equal(
|
102
|
+
@subject.style.should.equal(UIBarButtonItemStyleDone)
|
103
103
|
end
|
104
104
|
|
105
105
|
it "has the correct image" do
|
@@ -349,7 +349,7 @@ describe BW::UIBarButtonItem do
|
|
349
349
|
|
350
350
|
describe "given options for a styled item with an image" do
|
351
351
|
before do
|
352
|
-
@options = { :styled => :
|
352
|
+
@options = { :styled => :done, :image => UIImage.alloc.init }
|
353
353
|
@target = -> { true }
|
354
354
|
@subject = BW::UIBarButtonItem.new(@options, &@target)
|
355
355
|
end
|
@@ -363,7 +363,7 @@ describe BW::UIBarButtonItem do
|
|
363
363
|
end
|
364
364
|
|
365
365
|
it "has the correct style" do
|
366
|
-
@subject.style.should.equal(
|
366
|
+
@subject.style.should.equal(UIBarButtonItemStyleDone)
|
367
367
|
end
|
368
368
|
|
369
369
|
it "has the correct image" do
|
@@ -384,7 +384,7 @@ describe BW::UIBarButtonItem do
|
|
384
384
|
describe "given options for a styled item with two images" do
|
385
385
|
before do
|
386
386
|
@options = {
|
387
|
-
:styled => :
|
387
|
+
:styled => :done,
|
388
388
|
:image => UIImage.alloc.init,
|
389
389
|
:landscape => UIImage.alloc.init
|
390
390
|
}
|
@@ -401,7 +401,7 @@ describe BW::UIBarButtonItem do
|
|
401
401
|
end
|
402
402
|
|
403
403
|
it "has the correct style" do
|
404
|
-
@subject.style.should.equal(
|
404
|
+
@subject.style.should.equal(UIBarButtonItemStyleDone)
|
405
405
|
end
|
406
406
|
|
407
407
|
it "has the correct image" do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
describe BW::UIControlWrapper do
|
2
|
+
describe "#when" do
|
3
|
+
before do
|
4
|
+
@subject = UIControl.alloc.init
|
5
|
+
@touched = []
|
6
|
+
|
7
|
+
@subject.when(UIControlEventTouchUpInside) do
|
8
|
+
@touched << 'for the very first time'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "supports the 'when' event handler" do
|
13
|
+
@subject.sendActionsForControlEvents(UIControlEventTouchUpInside)
|
14
|
+
@touched.should.equal ['for the very first time']
|
15
|
+
end
|
16
|
+
|
17
|
+
it "replaces the target for a given control event by default" do
|
18
|
+
@subject.when(UIControlEventTouchUpInside) do
|
19
|
+
@touched << 'touched'
|
20
|
+
end
|
21
|
+
|
22
|
+
@subject.sendActionsForControlEvents(UIControlEventTouchUpInside)
|
23
|
+
@touched.should.equal ['touched']
|
24
|
+
end
|
25
|
+
|
26
|
+
it "allows multiple targets for a given control event if specified" do
|
27
|
+
@subject.when(UIControlEventTouchUpInside, append: true) do
|
28
|
+
@touched << 'touched'
|
29
|
+
end
|
30
|
+
|
31
|
+
@subject.sendActionsForControlEvents(UIControlEventTouchUpInside)
|
32
|
+
@touched.should.equal ['for the very first time', 'touched']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
describe BW::UIViewControllerWrapper do
|
2
|
+
describe "#content_frame" do
|
3
|
+
describe "given a UIViewController" do
|
4
|
+
before do
|
5
|
+
@subject = UIViewController.alloc.init
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has the correct content frame" do
|
9
|
+
height = App.frame.size.height
|
10
|
+
expected = CGRectMake(0, 0, App.frame.size.width, height)
|
11
|
+
|
12
|
+
@subject.content_frame.should.equal(expected)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
###############################################################################################
|
17
|
+
|
18
|
+
describe "given a UIViewController inside a UINavigationController" do
|
19
|
+
before do
|
20
|
+
@subject = UIViewController.alloc.init
|
21
|
+
|
22
|
+
UINavigationController.alloc.initWithRootViewController(@subject)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has the correct content frame" do
|
26
|
+
height = App.frame.size.height
|
27
|
+
height -= @subject.navigationController.navigationBar.frame.size.height
|
28
|
+
expected = CGRectMake(0, 0, App.frame.size.width, height)
|
29
|
+
|
30
|
+
@subject.content_frame.should.equal(expected)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|