bubble-wrap 1.2.0 → 1.3.0.osx

Sign up to get free protection for your applications and to get access to all the features.
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