bubble-wrap 1.2.0 → 1.3.0.osx

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 (79) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +4 -2
  3. data/Gemfile.lock +1 -1
  4. data/README.md +217 -7
  5. data/Rakefile +23 -2
  6. data/lib/bubble-wrap/camera.rb +10 -6
  7. data/lib/bubble-wrap/core.rb +14 -1
  8. data/lib/bubble-wrap/ext/motion_project_app.rb +8 -0
  9. data/lib/bubble-wrap/font.rb +3 -1
  10. data/lib/bubble-wrap/http.rb +2 -0
  11. data/lib/bubble-wrap/loader.rb +17 -2
  12. data/lib/bubble-wrap/location.rb +9 -6
  13. data/lib/bubble-wrap/media.rb +10 -6
  14. data/lib/bubble-wrap/test.rb +6 -1
  15. data/lib/bubble-wrap/ui.rb +5 -2
  16. data/lib/bubble-wrap/version.rb +2 -7
  17. data/motion/core.rb +6 -1
  18. data/motion/core/app.rb +3 -64
  19. data/motion/core/device.rb +0 -55
  20. data/motion/core/device/{camera.rb → ios/camera.rb} +0 -0
  21. data/motion/core/device/{camera_wrapper.rb → ios/camera_wrapper.rb} +0 -0
  22. data/motion/core/device/ios/screen.rb +75 -0
  23. data/motion/core/device/osx/screen.rb +18 -0
  24. data/motion/core/device/screen.rb +1 -69
  25. data/motion/core/ios/app.rb +71 -0
  26. data/motion/core/ios/device.rb +59 -0
  27. data/motion/core/osx/app.rb +15 -0
  28. data/motion/core/osx/device.rb +6 -0
  29. data/motion/core/string.rb +3 -2
  30. data/motion/http.rb +0 -364
  31. data/motion/http/query.rb +367 -0
  32. data/motion/http/response.rb +32 -0
  33. data/motion/test_suite_delegate.rb +58 -0
  34. data/motion/ui/ui_alert_view.rb +169 -0
  35. data/motion/ui/ui_bar_button_item.rb +55 -53
  36. data/motion/util/constants.rb +34 -32
  37. data/samples/alert/.gitignore +16 -0
  38. data/samples/alert/Gemfile +3 -0
  39. data/samples/alert/Rakefile +10 -0
  40. data/samples/alert/app/app_delegate.rb +8 -0
  41. data/samples/alert/app/controllers/alert_view_controller.rb +74 -0
  42. data/samples/alert/resources/Default-568h@2x.png +0 -0
  43. data/samples/alert/spec/main_spec.rb +9 -0
  44. data/samples/media/.gitignore +16 -0
  45. data/samples/media/Rakefile +11 -0
  46. data/samples/media/app/app_delegate.rb +8 -0
  47. data/samples/media/app/controllers/play_controller.rb +46 -0
  48. data/samples/media/resources/Default-568h@2x.png +0 -0
  49. data/samples/media/resources/test.mp3 +0 -0
  50. data/samples/media/spec/main_spec.rb +9 -0
  51. data/samples/osx/Gemfile +3 -0
  52. data/samples/osx/Gemfile.lock +10 -0
  53. data/samples/osx/Rakefile +11 -0
  54. data/samples/osx/app/app_delegate.rb +69 -0
  55. data/samples/osx/app/menu.rb +108 -0
  56. data/samples/osx/resources/Credits.rtf +29 -0
  57. data/samples/osx/spec/main_spec.rb +9 -0
  58. data/spec/motion/core/app_spec.rb +5 -164
  59. data/spec/motion/core/device/{camera_spec.rb → ios/camera_spec.rb} +0 -0
  60. data/spec/motion/core/device/{camera_wrapper_spec.rb → ios/camera_wrapper_spec.rb} +0 -0
  61. data/spec/motion/core/device/ios/device_spec.rb +74 -0
  62. data/spec/motion/core/device/{screen_spec.rb → ios/screen_spec.rb} +2 -1
  63. data/spec/motion/core/device/osx/screen_spec.rb +26 -0
  64. data/spec/motion/core/device_spec.rb +0 -71
  65. data/spec/motion/core/ios/app_spec.rb +180 -0
  66. data/spec/motion/core/kvo_spec.rb +23 -7
  67. data/spec/motion/core/ns_index_path_spec.rb +10 -2
  68. data/spec/motion/core/osx/app_spec.rb +15 -0
  69. data/spec/motion/core/string_spec.rb +11 -5
  70. data/spec/motion/core_spec.rb +13 -2
  71. data/spec/motion/http/query_spec.rb +731 -0
  72. data/spec/motion/http/response_spec.rb +44 -0
  73. data/spec/motion/http_spec.rb +0 -722
  74. data/spec/motion/{core → ui}/gestures_spec.rb +0 -0
  75. data/spec/motion/ui/ui_alert_view_spec.rb +1188 -0
  76. data/spec/motion/{core → ui}/ui_bar_button_item_spec.rb +80 -24
  77. data/spec/motion/{core → ui}/ui_control_spec.rb +0 -0
  78. data/spec/motion/util/constants_spec.rb +4 -4
  79. metadata +86 -26
@@ -0,0 +1,59 @@
1
+ module BubbleWrap
2
+ module Device
3
+ module_function
4
+
5
+ # Verifies that the device running the app is an iPhone.
6
+ # @return [TrueClass, FalseClass] true will be returned if the device is an iPhone, false otherwise.
7
+ def iphone?(idiom=UIDevice.currentDevice.userInterfaceIdiom)
8
+ idiom == UIUserInterfaceIdiomPhone
9
+ end
10
+
11
+ # Verifies that the device running the app is an iPad.
12
+ # @return [TrueClass, FalseClass] true will be returned if the device is an iPad, false otherwise.
13
+ def ipad?(idiom=UIDevice.currentDevice.userInterfaceIdiom)
14
+ idiom == UIUserInterfaceIdiomPad
15
+ end
16
+
17
+ # Verifies that the device having a long screen (4 inch iPhone/iPod)
18
+ # @return [TrueClass, FalseClass] true will be returned if the device is an iPhone/iPod with 4 inche screen, false otherwise.
19
+ def long_screen?(idiom=UIDevice.currentDevice.userInterfaceIdiom, screen_height=UIScreen.mainScreen.bounds.size.height)
20
+ iphone?(idiom) && screen_height == 568.0
21
+ end
22
+
23
+ # Use this to make a DSL-style call for picking images
24
+ # @example Device.camera.front
25
+ # @return [Device::Camera::CameraWrapper]
26
+ def camera
27
+ BubbleWrap::Device::CameraWrapper
28
+ end
29
+
30
+ # Verifies that the device running has a front facing camera.
31
+ # @return [TrueClass, FalseClass] true will be returned if the device has a front facing camera, false otherwise.
32
+ def front_camera?(picker=UIImagePickerController)
33
+ p "This method (front_camera?) is DEPRECATED. Transition to using Device.camera.front?"
34
+ picker.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceFront)
35
+ end
36
+
37
+ # Verifies that the device running has a rear facing camera.
38
+ # @return [TrueClass, FalseClass] true will be returned if the device has a rear facing camera, false otherwise.
39
+ def rear_camera?(picker=UIImagePickerController)
40
+ p "This method (rear_camera?) is DEPRECATED. Transition to using Device.camera.rear?"
41
+ picker.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceRear)
42
+ end
43
+
44
+ def simulator?
45
+ @simulator_state ||= !(UIDevice.currentDevice.model =~ /simulator/i).nil?
46
+ end
47
+
48
+ # Returns the IOS SDK version currently running (i.e. "5.1" or "6.0" etc)
49
+ # @return [String] the IOS SDK version currently running
50
+ def ios_version
51
+ UIDevice.currentDevice.systemVersion
52
+ end
53
+
54
+ # Delegates to BubbleWrap::Screen.orientation
55
+ def orientation
56
+ screen.orientation
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ module BubbleWrap
2
+ module App
3
+ module_function
4
+
5
+ # Application Delegate
6
+ def delegate
7
+ shared.delegate
8
+ end
9
+
10
+ # the Application object.
11
+ def shared
12
+ NSApplication.sharedApplication
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module BubbleWrap
2
+ module Device
3
+ module_function
4
+
5
+ end
6
+ end
@@ -48,7 +48,8 @@ module BubbleWrap
48
48
  def to_color
49
49
  # First check if it is a color keyword
50
50
  keyword_selector = "#{self.camelize(:lower)}Color"
51
- return UIColor.send(keyword_selector) if UIColor.respond_to? keyword_selector
51
+ color_klass = App.osx? ? NSColor : UIColor
52
+ return color_klass.send(keyword_selector) if color_klass.respond_to? keyword_selector
52
53
 
53
54
  # Next attempt to convert from hex
54
55
  hex_color = self.gsub("#", "")
@@ -61,7 +62,7 @@ module BubbleWrap
61
62
  raise ArgumentError
62
63
  end
63
64
  if colors.size == 3
64
- UIColor.colorWithRed((colors[0]/255.0), green:(colors[1]/255.0), blue:(colors[2]/255.0), alpha:1)
65
+ BubbleWrap.rgb_color(colors[0], colors[1], colors[2])
65
66
  else
66
67
  raise ArgumentError
67
68
  end
@@ -27,370 +27,6 @@ module BubbleWrap
27
27
  end
28
28
 
29
29
  end
30
-
31
- # Response class wrapping the results of a Query's response
32
- class Response
33
- attr_reader :body
34
- attr_reader :headers
35
- attr_accessor :status_code, :status_description, :error_message
36
- attr_reader :url
37
- attr_reader :original_url
38
-
39
- def initialize(values={})
40
- self.update(values)
41
- end
42
-
43
- def update(values)
44
- values.each do |k,v|
45
- self.instance_variable_set("@#{k}", v)
46
- end
47
- update_status_description
48
- end
49
-
50
- def ok?
51
- status_code.to_s =~ /20\d/ ? true : false
52
- end
53
-
54
- def to_s
55
- "#<#{self.class}:#{self.object_id} - url: #{self.url}, body: #{self.body}, headers: #{self.headers}, status code: #{self.status_code}, error message: #{self.error_message} >"
56
- end
57
- alias description to_s
58
-
59
- def update_status_description
60
- @status_description = status_code.nil? ? nil : NSHTTPURLResponse.localizedStringForStatusCode(status_code)
61
- end
62
- end
63
-
64
- # Class wrapping NSConnection and often used indirectly by the BubbleWrap::HTTP module methods.
65
- class Query
66
- attr_accessor :request
67
- attr_accessor :connection
68
- attr_accessor :credentials # username & password has a hash
69
- attr_accessor :proxy_credential # credential supplied to proxy servers
70
- attr_accessor :post_data
71
- attr_reader :method
72
-
73
- attr_reader :response
74
- attr_reader :status_code
75
- attr_reader :response_headers
76
- attr_reader :response_size
77
- attr_reader :options
78
- CLRF = "\r\n"
79
- # ==== Parameters
80
- # url<String>:: url of the resource to download
81
- # http_method<Symbol>:: Value representing the HTTP method to use
82
- # options<Hash>:: optional options used for the query
83
- #
84
- # ==== Options
85
- # :payload<String> - data to pass to a POST, PUT, DELETE query.
86
- # :delegator - Proc, class or object to call when the file is downloaded.
87
- # a proc will receive a Response object while the passed object
88
- # will receive the handle_query_response method
89
- # :headers<Hash> - headers send with the request
90
- # :cookies<Boolean> - Set whether cookies should be sent with request or not (Default: true)
91
- # Anything else will be available via the options attribute reader.
92
- #
93
- def initialize(url_string, http_method = :get, options={})
94
- @method = http_method.upcase.to_s
95
- @delegator = options.delete(:action) || self
96
- @payload = options.delete(:payload)
97
- @files = options.delete(:files)
98
- @boundary = options.delete(:boundary) || BW.create_uuid
99
- @credentials = options.delete(:credentials) || {}
100
- @credentials = {:username => '', :password => ''}.merge(@credentials)
101
- @timeout = options.delete(:timeout) || 30.0
102
- @headers = escape_line_feeds(options.delete :headers)
103
- @format = options.delete(:format)
104
- @cache_policy = options.delete(:cache_policy) || NSURLRequestUseProtocolCachePolicy
105
- @credential_persistence = options.delete(:credential_persistence) || NSURLCredentialPersistenceForSession
106
- @cookies = options.key?(:cookies) ? options.delete(:cookies) : true
107
- @options = options
108
- @response = HTTP::Response.new
109
- @follow_urls = options[:follow_urls] || true
110
-
111
- @url = create_url(url_string)
112
- @body = create_request_body
113
- @request = create_request
114
- @original_url = @url.copy
115
-
116
- @connection = create_connection(request, self)
117
- @connection.start
118
-
119
- UIApplication.sharedApplication.networkActivityIndicatorVisible = true if defined?(UIApplication)
120
- end
121
-
122
- def to_s
123
- "#<#{self.class}:#{self.object_id} - Method: #{@method}, url: #{@url.description}, body: #{@body.description}, Payload: #{@payload}, Headers: #{@headers} Credentials: #{@credentials}, Timeout: #{@timeout}, \
124
- Cache policy: #{@cache_policy}, response: #{@response.inspect} >"
125
- end
126
- alias description to_s
127
-
128
- def connection(connection, didReceiveResponse:response)
129
- @status_code = response.statusCode
130
- @response_headers = response.allHeaderFields
131
- @response_size = response.expectedContentLength.to_f
132
- end
133
-
134
- # This delegate method get called every time a chunk of data is being received
135
- def connection(connection, didReceiveData:received_data)
136
- @received_data ||= NSMutableData.new
137
- @received_data.appendData(received_data)
138
-
139
- if download_progress = options[:download_progress]
140
- download_progress.call(@received_data.length.to_f, response_size)
141
- end
142
- end
143
-
144
- def connection(connection, willSendRequest:request, redirectResponse:redirect_response)
145
- # abort early if the user has explicitly disabled redirects
146
- if @options[:no_redirect] and redirect_response then
147
- return nil
148
- end
149
- @redirect_count ||= 0
150
- @redirect_count += 1
151
- log "##{@redirect_count} HTTP redirect_count: #{request.inspect} - #{self.description}"
152
-
153
- if @redirect_count >= 30
154
- @response.error_message = "Too many redirections"
155
- @request.done_loading!
156
- call_delegator_with_response
157
- nil
158
- else
159
- @url = request.URL if @follow_urls
160
- request
161
- end
162
- end
163
-
164
- def connection(connection, didFailWithError: error)
165
- log "HTTP Connection to #{@url.absoluteString} failed #{error.localizedDescription}"
166
- UIApplication.sharedApplication.networkActivityIndicatorVisible = false if defined?(UIApplication)
167
- @request.done_loading!
168
- @response.error_message = error.localizedDescription
169
- call_delegator_with_response
170
- end
171
-
172
- def connection(connection, didSendBodyData:sending, totalBytesWritten:written, totalBytesExpectedToWrite:expected)
173
- if upload_progress = options[:upload_progress]
174
- upload_progress.call(sending, written, expected)
175
- end
176
- end
177
-
178
- def connectionDidFinishLoading(connection)
179
- UIApplication.sharedApplication.networkActivityIndicatorVisible = false if defined?(UIApplication)
180
- @request.done_loading!
181
- response_body = NSData.dataWithData(@received_data) if @received_data
182
- @response.update(status_code: status_code, body: response_body, headers: response_headers, url: @url, original_url: @original_url)
183
-
184
- call_delegator_with_response
185
- end
186
-
187
- def connection(connection, didReceiveAuthenticationChallenge:challenge)
188
- if (challenge.previousFailureCount == 0)
189
- if credentials[:username].to_s.empty? && credentials[:password].to_s.empty?
190
- challenge.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)
191
- log 'Continue without credentials to get 401 status in response'
192
- else
193
- new_credential = NSURLCredential.credentialWithUser(credentials[:username], password:credentials[:password], persistence:@credential_persistence)
194
- challenge.sender.useCredential(new_credential, forAuthenticationChallenge:challenge)
195
- log "auth challenged, answered with credentials: #{credentials.inspect}"
196
- end
197
- else
198
- challenge.sender.cancelAuthenticationChallenge(challenge)
199
- log 'Auth Failed :('
200
- end
201
- end
202
-
203
-
204
- private
205
-
206
- def create_request
207
- log "BubbleWrap::HTTP building a NSRequest for #{@url.description}"
208
-
209
- request = NSMutableURLRequest.requestWithURL(@url,
210
- cachePolicy:@cache_policy,
211
- timeoutInterval:@timeout)
212
- request.setHTTPMethod(@method)
213
- set_content_type
214
- request.setAllHTTPHeaderFields(@headers)
215
- request.setHTTPBody(@body)
216
- request.setHTTPShouldHandleCookies(@cookies)
217
- patch_nsurl_request(request)
218
-
219
- request
220
- end
221
-
222
- def set_content_type
223
- return if headers_provided?
224
- return if (@method == "GET" || @method == "HEAD")
225
- @headers ||= {}
226
- @headers["Content-Type"] = case @format
227
- when :json
228
- "application/json"
229
- when :xml
230
- "application/xml"
231
- when :text
232
- "text/plain"
233
- else
234
- if @format == :form_data || @payload_or_files_were_appended
235
- "multipart/form-data; boundary=#{@boundary}"
236
- else
237
- "application/x-www-form-urlencoded"
238
- end
239
- end
240
- end
241
-
242
- def headers_provided?
243
- @headers && @headers.keys.find {|k| k.downcase == 'content-type'}
244
- end
245
-
246
- def create_request_body
247
- return nil if (@method == "GET" || @method == "HEAD")
248
- return nil unless (@payload || @files)
249
-
250
- body = NSMutableData.data
251
-
252
- append_payload(body) if @payload
253
- append_files(body) if @files
254
- append_body_boundary(body) if @payload_or_files_were_appended
255
-
256
- log "Built HTTP body: \n #{body.to_str}"
257
- body
258
- end
259
-
260
- def append_payload(body)
261
- if @payload.is_a?(NSData)
262
- body.appendData(@payload)
263
- elsif @payload.is_a?(String)
264
- body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding)
265
- else
266
- append_form_params(body)
267
- end
268
- body
269
- end
270
-
271
- def append_form_params(body)
272
- list = process_payload_hash(@payload)
273
- list.each do |key, value|
274
- s = "--#{@boundary}\r\n"
275
- s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
276
- s += value.to_s
277
- s += "\r\n"
278
- body.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
279
- end
280
- @payload_or_files_were_appended = true
281
- body
282
- end
283
-
284
- def parse_file(key, value)
285
- if value.is_a?(Hash)
286
- raise InvalidFileError if value[:data].nil?
287
- {data: value[:data], filename: value[:filename] || key}
288
- else
289
- {data: value, filename: key}
290
- end
291
- end
292
-
293
- def append_files(body)
294
- @files.each do |key, value|
295
- file = parse_file(key, value)
296
- s = "--#{@boundary}\r\n"
297
- s += "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{file[:filename]}\"\r\n"
298
- s += "Content-Type: application/octet-stream\r\n\r\n"
299
- file_data = NSMutableData.new
300
- file_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
301
- file_data.appendData(file[:data])
302
- file_data.appendData("\r\n".dataUsingEncoding NSUTF8StringEncoding)
303
- body.appendData(file_data)
304
- end
305
- @payload_or_files_were_appended = true
306
- body
307
- end
308
-
309
- def append_body_boundary(body)
310
- body.appendData("--#{@boundary}--\r\n".dataUsingEncoding NSUTF8StringEncoding)
311
- end
312
-
313
- def create_url(url_string)
314
- url_string = url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding
315
- if (@method == "GET" || @method == "HEAD") && @payload
316
- convert_payload_to_url if @payload.is_a?(Hash)
317
- url_string += "?#{@payload}"
318
- end
319
- url = NSURL.URLWithString(url_string)
320
-
321
- validate_url(url)
322
- url
323
- end
324
-
325
- def validate_url(url)
326
- if !NSURLConnection.canHandleRequest(NSURLRequest.requestWithURL(url))
327
- raise InvalidURLError, "Invalid URL provided (Make sure you include a valid URL scheme, e.g. http:// or similar)."
328
- end
329
- end
330
-
331
- def escape(string)
332
- if string
333
- CFURLCreateStringByAddingPercentEscapes nil, string.to_s, nil, "!*'();:@&=+$,/?%#[]", KCFStringEncodingUTF8
334
- end
335
- end
336
-
337
- def convert_payload_to_url
338
- params_array = process_payload_hash(@payload)
339
- params_array.map! { |key, value| "#{escape key}=#{escape value}" }
340
- @payload = params_array.join("&")
341
- end
342
-
343
- def process_payload_hash(payload, prefix=nil)
344
- list = []
345
- payload.each do |k,v|
346
- if v.is_a?(Hash)
347
- new_prefix = prefix ? "#{prefix}[#{k.to_s}]" : k.to_s
348
- param = process_payload_hash(v, new_prefix)
349
- list += param
350
- elsif v.is_a?(Array)
351
- v.each do |val|
352
- param = prefix ? "#{prefix}[#{k.to_s}][]" : "#{k.to_s}[]"
353
- list << [param, val]
354
- end
355
- else
356
- param = prefix ? "#{prefix}[#{k.to_s}]" : k.to_s
357
- list << [param, v]
358
- end
359
- end
360
- list
361
- end
362
-
363
- def log(message)
364
- NSLog message if BubbleWrap.debug?
365
- end
366
-
367
- def escape_line_feeds(hash)
368
- return nil if hash.nil?
369
- escaped_hash = {}
370
-
371
- hash.each{|k,v| escaped_hash[k] = v.gsub("\n", CLRF) if v }
372
- escaped_hash
373
- end
374
-
375
- def patch_nsurl_request(request)
376
- request.instance_variable_set("@done_loading", false)
377
-
378
- def request.done_loading?; @done_loading; end
379
- def request.done_loading!; @done_loading = true; end
380
- end
381
-
382
- def call_delegator_with_response
383
- if @delegator.respond_to?(:call)
384
- @delegator.call( @response, self )
385
- end
386
- end
387
-
388
- # This is a temporary method used for mocking.
389
- def create_connection(request, delegate)
390
- NSURLConnection.connectionWithRequest(request, delegate:delegate)
391
- end
392
-
393
- end
394
30
  end
395
31
  end
396
32