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.
Files changed (72) hide show
  1. checksums.yaml +6 -14
  2. data/.travis.yml +2 -1
  3. data/CHANGELOG.md +26 -2
  4. data/GETTING_STARTED.md +1 -1
  5. data/Gemfile.lock +1 -1
  6. data/HACKING.md +6 -4
  7. data/README.md +83 -3
  8. data/Rakefile +9 -7
  9. data/lib/bubble-wrap/all.rb +2 -2
  10. data/lib/bubble-wrap/mail.rb +9 -0
  11. data/lib/bubble-wrap/sms.rb +9 -0
  12. data/lib/bubble-wrap/ui.rb +6 -2
  13. data/lib/bubble-wrap/version.rb +1 -1
  14. data/motion/core.rb +1 -1
  15. data/motion/core/app.rb +7 -2
  16. data/motion/core/device/ios/camera.rb +3 -2
  17. data/motion/core/device/ios/screen.rb +19 -0
  18. data/motion/core/ios/app.rb +13 -1
  19. data/motion/core/ios/device.rb +5 -0
  20. data/motion/core/json.rb +1 -3
  21. data/motion/core/kvo.rb +11 -13
  22. data/motion/core/persistence.rb +8 -1
  23. data/motion/core/string.rb +3 -3
  24. data/motion/core/time.rb +5 -0
  25. data/motion/http.rb +1 -1
  26. data/motion/http/query.rb +39 -19
  27. data/motion/http/response.rb +4 -4
  28. data/motion/mail/mail.rb +59 -0
  29. data/motion/mail/result.rb +29 -0
  30. data/motion/reactor/eventable.rb +3 -2
  31. data/motion/reactor/periodic_timer.rb +12 -8
  32. data/motion/reactor/timer.rb +11 -7
  33. data/motion/sms/result.rb +24 -0
  34. data/motion/sms/sms.rb +47 -0
  35. data/motion/ui/pollute.rb +4 -1
  36. data/motion/ui/ui_alert_view.rb +15 -8
  37. data/motion/ui/ui_control_wrapper.rb +16 -0
  38. data/motion/ui/ui_view_controller_wrapper.rb +13 -0
  39. data/motion/ui/ui_view_wrapper.rb +55 -0
  40. data/resources/Localizable.strings +1 -0
  41. data/samples/gesture/Gemfile +2 -2
  42. data/samples/location/Gemfile +1 -1
  43. data/samples/osx/Gemfile +2 -2
  44. data/spec/motion/core/app_spec.rb +6 -0
  45. data/spec/motion/core/device/ios/camera_spec.rb +3 -3
  46. data/spec/motion/core/device/ios/screen_spec.rb +45 -0
  47. data/spec/motion/core/ios/app_spec.rb +29 -0
  48. data/spec/motion/core/persistence_spec.rb +25 -0
  49. data/spec/motion/core/string_spec.rb +2 -2
  50. data/spec/motion/core/time_spec.rb +14 -4
  51. data/spec/motion/core_spec.rb +9 -8
  52. data/spec/motion/http/query_spec.rb +92 -15
  53. data/spec/motion/http/response_spec.rb +4 -3
  54. data/spec/motion/location/location_spec.rb +1 -1
  55. data/spec/motion/mail/mail_spec.rb +125 -0
  56. data/spec/motion/mail/result_spec.rb +53 -0
  57. data/spec/motion/reactor/eventable_spec.rb +85 -0
  58. data/spec/motion/reactor_spec.rb +0 -20
  59. data/spec/motion/sms/result_spec.rb +38 -0
  60. data/spec/motion/sms/sms_spec.rb +71 -0
  61. data/spec/motion/ui/pollute_spec.rb +13 -0
  62. data/spec/motion/ui/ui_bar_button_item_spec.rb +8 -8
  63. data/spec/motion/ui/ui_control_wrapper_spec.rb +35 -0
  64. data/spec/motion/ui/ui_view_controller_wrapper_spec.rb +34 -0
  65. data/spec/motion/ui/ui_view_wrapper_spec.rb +62 -0
  66. data/travis.sh +7 -0
  67. metadata +52 -22
  68. data/motion/ui/gestures.rb +0 -57
  69. data/motion/ui/ui_control.rb +0 -14
  70. data/motion/ui/ui_view_controller.rb +0 -11
  71. data/spec/motion/ui/gestures_spec.rb +0 -62
  72. data/spec/motion/ui/ui_control_spec.rb +0 -42
@@ -1,8 +1,8 @@
1
1
  describe BubbleWrap::String do
2
2
 
3
- describe ::String do
3
+ describe ::NSString do
4
4
  it 'should include BubbleWrap::String' do
5
- ::String.ancestors.member?(BubbleWrap::String).should == true
5
+ ::NSString.ancestors.member?(BubbleWrap::String).should == true
6
6
  end
7
7
  end
8
8
 
@@ -17,39 +17,49 @@ describe "Time" do
17
17
  describe "parsing an iso8601 formatted time to a Time object" do
18
18
  before do
19
19
  @time = Time.iso8601("2012-05-31T19:41:33Z")
20
+ @time_with_timezone = Time.iso8601_with_timezone("1987-08-10T06:00:00+02:00")
20
21
  end
21
22
 
22
23
  it "should be a time" do
23
24
  @time.instance_of?(Time).should == true
25
+ @time_with_timezone.instance_of?(Time).should == true
24
26
  end
25
27
 
26
- # # Crashes Buggy RubyMotion 1.18
27
- # it "should be converted to the local timezone automatically" do
28
- # @time.zone.should == Time.now.zone
29
- # end
28
+ # Crashes Buggy RubyMotion 1.18
29
+ it "should be converted to the local timezone automatically" do
30
+ local_zone = Time.now.zone
31
+ @time.zone.should == local_zone
32
+ @time_with_timezone.zone == local_zone
33
+ end
30
34
 
31
35
  it "should have a valid year" do
32
36
  @time.utc.year.should == 2012
37
+ @time_with_timezone.utc.year.should == 1987
33
38
  end
34
39
 
35
40
  it "should have a valid month" do
36
41
  @time.utc.month.should == 5
42
+ @time_with_timezone.utc.month.should == 8
37
43
  end
38
44
 
39
45
  it "should have a valid day" do
40
46
  @time.utc.day.should == 31
47
+ @time_with_timezone.utc.day.should == 10
41
48
  end
42
49
 
43
50
  it "should have a valid hour" do
44
51
  @time.utc.hour.should == 19
52
+ @time_with_timezone.utc.hour.should == 4
45
53
  end
46
54
 
47
55
  it "should have a valid minute" do
48
56
  @time.utc.min.should == 41
57
+ @time_with_timezone.utc.min.should == 0
49
58
  end
50
59
 
51
60
  it "should have a valid second" do
52
61
  @time.utc.sec.should == 33
62
+ @time_with_timezone.utc.sec.should == 0
53
63
  end
54
64
  end
55
65
 
@@ -54,15 +54,16 @@ describe 'BubbleWrap' do
54
54
  describe "Localized string" do
55
55
 
56
56
  it "loads the string from NSBundle" do
57
+ key = 'real_key'
58
+ value = 'Real Key'
59
+
60
+ BubbleWrap::localized_string(key, value).should == value
61
+ end
62
+
63
+ it "returns the key if localization not found and no value is given" do
57
64
  key = 'fake_key'
58
- value = 'fake_value'
59
-
60
- bundle = NSBundle.mainBundle
61
- def bundle.arguments; @arguments; end
62
- def bundle.localizedStringForKey(key, value:value, table:table); @arguments = [key, value, table]; end
63
-
64
- BubbleWrap::localized_string(key, value)
65
- bundle.arguments.should.equal [key, value, nil]
65
+
66
+ BubbleWrap::localized_string(key).should == key
66
67
  end
67
68
 
68
69
  end
@@ -1,5 +1,31 @@
1
+ # -*- coding: utf-8 -*-
1
2
  describe BubbleWrap::HTTP::Query do
2
3
 
4
+ describe "json parameter encoding" do
5
+ before do
6
+ @json_payload = {"foo" => "bar"}
7
+ @json_options = {
8
+ payload: @json_payload,
9
+ format: :json
10
+ }
11
+ @json_query = BubbleWrap::HTTP::Query.new( "http://localhost:3000" , :post, @json_options )
12
+ end
13
+
14
+ it "should generate json body" do
15
+ BW::JSON.parse(@json_query.request.HTTPBody).should == @json_payload
16
+ end
17
+ end
18
+
19
+ describe "false value" do
20
+ before do
21
+ @query = BubbleWrap::HTTP::Query.new("http://www.google.com", :get, {payload: {following: false}})
22
+ end
23
+
24
+ it "should have right url" do
25
+ @query.request.URL.absoluteString.should == "http://www.google.com?following=false"
26
+ end
27
+ end
28
+
3
29
  before do
4
30
  @localhost_url = 'http://localhost'
5
31
  @fake_url = 'http://fake.url'
@@ -137,14 +163,14 @@ describe BubbleWrap::HTTP::Query do
137
163
  }.should.not.raise NoMethodError
138
164
  end
139
165
 
140
- it "should set the payload in URL only for GET and HEAD requests" do
166
+ it "should set the payload in URL only for GET/HEAD/OPTIONS requests" do
141
167
  [:post, :put, :delete, :patch].each do |method|
142
168
  query = BubbleWrap::HTTP::Query.new( @localhost_url , method, { payload: @payload } )
143
169
  query.instance_variable_get(:@url).description.should.equal @localhost_url
144
170
  end
145
171
 
146
172
  payload = {name: 'marin'}
147
- [:get, :head].each do |method|
173
+ [:get, :head, :options].each do |method|
148
174
  query = BubbleWrap::HTTP::Query.new( @localhost_url , method, { payload: payload } )
149
175
  query.instance_variable_get(:@url).description.should.equal "#{@localhost_url}?name=marin"
150
176
  end
@@ -179,11 +205,10 @@ describe BubbleWrap::HTTP::Query do
179
205
  }.should.raise InvalidFileError
180
206
  end
181
207
 
182
- it "sets the HTTPBody DATA to @request for all methods except GET and HEAD" do
208
+ it "sets the HTTPBody DATA to @request for all methods except GET/HEAD/OPTIONS" do
183
209
  payload = { name: 'apple', model: 'macbook'}
184
210
  files = { twitter: sample_data, site: "mneorr.com".dataUsingEncoding(NSUTF8StringEncoding) }
185
211
 
186
- puts "\n"
187
212
  [:post, :put, :delete, :patch].each do |method|
188
213
  puts " - #{method}\n"
189
214
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: payload, files: files } )
@@ -192,7 +217,7 @@ describe BubbleWrap::HTTP::Query do
192
217
  real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\napple\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nmacbook\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"twitter\"; filename=\"twitter\"\r\nContent-Type: application/octet-stream\r\n\r\ntwitter:@mneorr\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"site\"; filename=\"site\"\r\nContent-Type: application/octet-stream\r\n\r\nmneorr.com\r\n--#{uuid}--\r\n"
193
218
  end
194
219
 
195
- [:get, :head].each do |method|
220
+ [:get, :head, :options].each do |method|
196
221
  puts " - #{method}\n"
197
222
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: payload } )
198
223
  real_payload = NSString.alloc.initWithData(query.request.HTTPBody, encoding:NSUTF8StringEncoding)
@@ -202,12 +227,11 @@ describe BubbleWrap::HTTP::Query do
202
227
 
203
228
  it "sets the payload without conversion to-from NSString if the payload was NSData" do
204
229
  data = sample_data
205
- lambda { query = create_query(data, nil) }.should.not.raise NoMethodError
230
+ lambda { create_query(data, nil) }.should.not.raise NoMethodError
206
231
  end
207
232
 
208
233
  it "sets the payload as a string if JSON" do
209
234
  json = "{\"foo\":42,\"bar\":\"BubbleWrap\"}"
210
- puts "\n"
211
235
  [:put, :post, :delete, :patch].each do |method|
212
236
  puts " - #{method}\n"
213
237
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: json } )
@@ -224,6 +248,19 @@ describe BubbleWrap::HTTP::Query do
224
248
  real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[name]\"\r\n\r\napple\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[model]\"\r\n\r\nmacbook\r\n--#{uuid}--\r\n"
225
249
  end
226
250
 
251
+ [["NSUTF8StringEncoding", NSUTF8StringEncoding],
252
+ ["NSJapaneseEUCStringEncoding", NSJapaneseEUCStringEncoding],
253
+ ["NSShiftJISStringEncoding", NSShiftJISStringEncoding],
254
+ ["NSISO2022JPStringEncoding", NSISO2022JPStringEncoding]].each do |enc_name, encoding|
255
+ it "sets the japanese characters payload encoded in #{enc_name}" do
256
+ payload = { computer: { name: '名前', model: 'モデル'} }
257
+ query = BubbleWrap::HTTP::Query.new( @fake_url, :post, { payload: payload, encoding: encoding })
258
+ uuid = query.instance_variable_get(:@boundary)
259
+ real_payload = NSString.alloc.initWithData(query.request.HTTPBody, encoding:encoding)
260
+ real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[name]\"\r\n\r\n#{payload[:computer][:name]}\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[model]\"\r\n\r\n#{payload[:computer][:model]}\r\n--#{uuid}--\r\n"
261
+ end
262
+ end
263
+
227
264
  end
228
265
 
229
266
  it "should set default timeout to 30s or the one from hash" do
@@ -479,6 +516,12 @@ describe BubbleWrap::HTTP::Query do
479
516
  @query.response.error_message.should.equal @fake_error.localizedDescription
480
517
  end
481
518
 
519
+ it "should set the error object to response object" do
520
+ @query.response.error.should.equal nil
521
+ @query.connection(nil, didFailWithError:@fake_error)
522
+ @query.response.error.code.should.equal @fake_error.code
523
+ end
524
+
482
525
  it "should check if there's a callback block and pass the response in" do
483
526
  expected_response = BubbleWrap::HTTP::Response.new
484
527
  real_response = nil
@@ -577,8 +620,9 @@ describe BubbleWrap::HTTP::Query do
577
620
  end
578
621
  end
579
622
 
580
- it "sets the error message on response" do
623
+ it "sets the error message/code on response" do
581
624
  @real_response.error_message.should.equal "Too many redirections"
625
+ @real_response.error.code.should.equal NSURLErrorHTTPTooManyRedirects
582
626
  end
583
627
 
584
628
  it "sets the request.done_loading" do
@@ -608,10 +652,18 @@ describe BubbleWrap::HTTP::Query do
608
652
  @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
609
653
  end
610
654
 
611
- it "should cancel the authentication if the failure count was not 0" do
612
- @challenge.previousFailureCount = 1
613
- @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
614
- @challenge.sender.was_cancelled.should.equal true
655
+ describe "given the failure count was not 0" do
656
+ before { @challenge.previousFailureCount = 1 }
657
+
658
+ it "should cancel the authentication" do
659
+ @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
660
+ @challenge.sender.was_cancelled.should.equal true
661
+ end
662
+
663
+ it "should set the response fields" do
664
+ @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
665
+ @query.response.status_code.should.equal @challenge.failureResponse.statusCode
666
+ end
615
667
  end
616
668
 
617
669
  it "should pass in Credentials and the challenge itself to the sender" do
@@ -633,6 +685,23 @@ describe BubbleWrap::HTTP::Query do
633
685
 
634
686
  end
635
687
 
688
+ describe 'cancel' do
689
+ before do
690
+ @doa_query = BubbleWrap::HTTP::Query.new(@localhost_url, :get)
691
+ @doa_query.cancel
692
+ end
693
+
694
+ it "should cancel the connection" do
695
+ @doa_query.connection.was_cancelled.should.equal true
696
+ end
697
+
698
+ if App.ios?
699
+ it "should turn off the network indicator" do
700
+ UIApplication.sharedApplication.isNetworkActivityIndicatorVisible.should.equal false
701
+ end
702
+ end
703
+ end
704
+
636
705
  describe "empty payload" do
637
706
 
638
707
  before do
@@ -695,11 +764,15 @@ describe BubbleWrap::HTTP::Query do
695
764
  end
696
765
 
697
766
  class FakeChallenge
698
- attr_accessor :previousFailureCount
767
+ attr_accessor :previousFailureCount, :failureResponse
699
768
 
700
769
  def sender
701
770
  @fake_sender ||= FakeSender.new
702
771
  end
772
+
773
+ def failureResponse
774
+ @failureResponse ||= FakeURLResponse.new(401, { bla: "123" }, 123)
775
+ end
703
776
  end
704
777
 
705
778
  class BubbleWrap::HTTP::Query
@@ -707,7 +780,7 @@ describe BubbleWrap::HTTP::Query do
707
780
  end
708
781
 
709
782
  class FakeURLConnection < NSURLConnection
710
- attr_reader :delegate, :request, :was_started
783
+ attr_reader :delegate, :request, :was_started, :was_cancelled
711
784
  def initialize(request, delegate)
712
785
  @request = request
713
786
  @delegate = delegate
@@ -715,8 +788,12 @@ describe BubbleWrap::HTTP::Query do
715
788
  end
716
789
  def start
717
790
  @was_started = true
791
+ @was_cancelled = false
718
792
  super
719
793
  end
794
+ def cancel
795
+ @was_cancelled = true
796
+ end
720
797
  end
721
798
 
722
799
  class FakeURLResponse < NSHTTPURLResponse
@@ -728,4 +805,4 @@ describe BubbleWrap::HTTP::Query do
728
805
  end
729
806
  end
730
807
 
731
- end
808
+ end
@@ -9,12 +9,12 @@ describe BubbleWrap::HTTP::Response do
9
9
  @response.instance_variable_get(:@url).should == 'http://localhost'
10
10
  end
11
11
 
12
- it "says OK status code 20x" do
12
+ it "says OK status code 2xx" do
13
13
  @response.ok?.should.equal true
14
- (200..209).each do |code|
14
+ (200..211).each do |code|
15
15
  BubbleWrap::HTTP::Response.new(status_code: code).ok?.should.be.true
16
16
  end
17
- [100..101, 300..307, 400..417, 500..505].inject([]){|codes, rg| codes += rg.to_a}.each do |code|
17
+ [100..101, 300..307, 400..417, 500..505].inject([]){|codes, rg| codes + rg.to_a}.each do |code|
18
18
  BubbleWrap::HTTP::Response.new(status_code: code).ok?.should.be.false
19
19
  end
20
20
  end
@@ -39,6 +39,7 @@ describe BubbleWrap::HTTP::Response do
39
39
  @response.should.respond_to :url
40
40
  @response.should.respond_to :status_code=
41
41
  @response.should.respond_to :error_message=
42
+ @response.should.respond_to :error=
42
43
  end
43
44
 
44
45
  end
@@ -162,7 +162,7 @@ describe BubbleWrap::Location do
162
162
  end
163
163
 
164
164
  it "should use significant update functions with get_significant" do
165
- BW::Location.get_significant do |result|
165
+ BW::Location.get_significant do
166
166
  end
167
167
 
168
168
  BW::Location.stop
@@ -0,0 +1,125 @@
1
+ # Mocking the presentViewController
2
+ class MailViewController < 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 MFMailComposeViewController
11
+ # So we can access the values that are set.
12
+ # This of course breaks MFMailComposeViewController from actually working,
13
+ # but it's testable.
14
+ class MFMailComposeViewController
15
+ attr_accessor :toRecipients, :ccRecipients, :bccRecipients, :subject, :message, :html
16
+
17
+ def setToRecipients(r)
18
+ self.toRecipients = r
19
+ end
20
+
21
+ def setCcRecipients(r)
22
+ self.ccRecipients = r
23
+ end
24
+
25
+ def setBccRecipients(r)
26
+ self.bccRecipients = r
27
+ end
28
+
29
+ def setSubject(r)
30
+ self.subject = r
31
+ end
32
+
33
+ def setMessageBody(message, isHTML: html)
34
+ self.message = message
35
+ self.html = html
36
+ end
37
+ end
38
+
39
+ describe BW::Mail do
40
+ describe ".compose" do
41
+ before do
42
+ @view_controller = MailViewController.new
43
+ @standard_mail_options = {
44
+ delegate: @view_controller,
45
+ to: [ "tom@example.com" ],
46
+ cc: [ "itchy@example.com", "scratchy@example.com" ],
47
+ bcc: [ "jerry@example.com" ],
48
+ html: false,
49
+ subject: "My Subject",
50
+ message: "This is my message. It isn't very long.",
51
+ animated: false
52
+ }
53
+ end
54
+
55
+ it "should open the mail controller in a modal" do
56
+ @view_controller.expectation = lambda { |mail_controller, animated|
57
+ mail_controller.should.be.kind_of(MFMailComposeViewController)
58
+ }
59
+
60
+ BubbleWrap::Mail.compose @standard_mail_options
61
+ end
62
+
63
+ it "should create a mail controller with the right to: address set" do
64
+ @view_controller.expectation = lambda { |mail_controller, animated|
65
+ mail_controller.toRecipients.should.be.kind_of(Array)
66
+ mail_controller.toRecipients.should == @standard_mail_options[:to]
67
+ }
68
+
69
+ BubbleWrap::Mail.compose @standard_mail_options
70
+ end
71
+
72
+ it "should create a mail controller with the right cc: address set" do
73
+ @view_controller.expectation = lambda { |mail_controller, animated|
74
+ mail_controller.ccRecipients.should.be.kind_of(Array)
75
+ mail_controller.ccRecipients.should == @standard_mail_options[:cc]
76
+ }
77
+
78
+ BubbleWrap::Mail.compose @standard_mail_options
79
+ end
80
+
81
+ it "should create a mail controller with the right bcc: address set" do
82
+ @view_controller.expectation = lambda { |mail_controller, animated|
83
+ mail_controller.bccRecipients.should.be.kind_of(Array)
84
+ mail_controller.bccRecipients.should == @standard_mail_options[:bcc]
85
+ }
86
+
87
+ BubbleWrap::Mail.compose @standard_mail_options
88
+ end
89
+
90
+ it "should create a mail controller with the right subject: set" do
91
+ @view_controller.expectation = lambda { |mail_controller, animated|
92
+ mail_controller.subject.should.be.kind_of(String)
93
+ mail_controller.subject.should == @standard_mail_options[:subject]
94
+ }
95
+
96
+ BubbleWrap::Mail.compose @standard_mail_options
97
+ end
98
+
99
+ it "should create a mail controller with the right message: set" do
100
+ @view_controller.expectation = lambda { |mail_controller, animated|
101
+ mail_controller.message.should.be.kind_of(String)
102
+ mail_controller.message.should == @standard_mail_options[:message]
103
+ }
104
+
105
+ BubbleWrap::Mail.compose @standard_mail_options
106
+ end
107
+
108
+ it "should create a mail controller with the right html: set" do
109
+ @view_controller.expectation = lambda { |mail_controller, animated|
110
+ mail_controller.html.should == @standard_mail_options[:html]
111
+ }
112
+
113
+ BubbleWrap::Mail.compose @standard_mail_options
114
+ end
115
+
116
+ it "should create a mail controller with the right animation" do
117
+ @view_controller.expectation = lambda { |mail_controller, animated|
118
+ animated.should.be.false
119
+ }
120
+
121
+ BubbleWrap::Mail.compose @standard_mail_options
122
+ end
123
+
124
+ end
125
+ end