bubble-wrap 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +0 -1
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +24 -0
  6. data/HACKING.md +2 -2
  7. data/README.md +363 -21
  8. data/Rakefile +6 -2
  9. data/lib/bubble-wrap.rb +0 -1
  10. data/lib/bubble-wrap/all.rb +4 -0
  11. data/lib/bubble-wrap/camera.rb +7 -0
  12. data/lib/bubble-wrap/core.rb +3 -2
  13. data/lib/bubble-wrap/ext/motion_project_app.rb +2 -2
  14. data/lib/bubble-wrap/http.rb +1 -0
  15. data/lib/bubble-wrap/loader.rb +19 -12
  16. data/lib/bubble-wrap/location.rb +6 -0
  17. data/lib/bubble-wrap/reactor.rb +10 -0
  18. data/lib/bubble-wrap/requirement.rb +11 -3
  19. data/lib/bubble-wrap/rss_parser.rb +2 -0
  20. data/lib/bubble-wrap/ui.rb +4 -0
  21. data/lib/bubble-wrap/version.rb +1 -1
  22. data/motion/core.rb +8 -2
  23. data/motion/core/app.rb +34 -6
  24. data/motion/core/device.rb +10 -1
  25. data/motion/core/device/camera.rb +219 -0
  26. data/motion/core/device/camera_wrapper.rb +45 -0
  27. data/motion/core/ns_url_request.rb +10 -0
  28. data/motion/core/persistence.rb +7 -0
  29. data/motion/core/pollute.rb +1 -2
  30. data/motion/core/string.rb +23 -0
  31. data/motion/http.rb +142 -83
  32. data/motion/location/location.rb +152 -0
  33. data/motion/location/pollute.rb +5 -0
  34. data/motion/reactor.rb +105 -0
  35. data/motion/reactor/default_deferrable.rb +9 -0
  36. data/motion/reactor/deferrable.rb +126 -0
  37. data/motion/reactor/eventable.rb +24 -0
  38. data/motion/reactor/future.rb +22 -0
  39. data/motion/reactor/periodic_timer.rb +27 -0
  40. data/motion/reactor/queue.rb +60 -0
  41. data/motion/reactor/timer.rb +25 -0
  42. data/motion/rss_parser.rb +131 -0
  43. data/motion/shortcut.rb +18 -0
  44. data/motion/{core → ui}/gestures.rb +15 -9
  45. data/motion/ui/pollute.rb +5 -0
  46. data/motion/{core → ui}/ui_control.rb +0 -0
  47. data/motion/{core → ui}/ui_view_controller.rb +0 -0
  48. data/resources/atom.xml +1705 -0
  49. data/spec/lib/bubble-wrap/ext/motion_project_app_spec.rb +7 -11
  50. data/spec/lib/bubble-wrap/requirement_spec.rb +4 -4
  51. data/spec/lib/bubble-wrap_spec.rb +2 -2
  52. data/spec/motion/core/app_spec.rb +118 -14
  53. data/spec/motion/core/device/camera_spec.rb +130 -0
  54. data/spec/motion/core/device/camera_wrapper_spec.rb +45 -0
  55. data/spec/motion/core/device_spec.rb +0 -50
  56. data/spec/motion/core/gestures_spec.rb +5 -0
  57. data/spec/motion/core/persistence_spec.rb +24 -2
  58. data/spec/motion/core/string_spec.rb +55 -0
  59. data/spec/motion/core_spec.rb +72 -1
  60. data/spec/motion/http_spec.rb +100 -65
  61. data/spec/motion/location/location_spec.rb +152 -0
  62. data/spec/motion/reactor/eventable_spec.rb +40 -0
  63. data/spec/motion/reactor_spec.rb +163 -0
  64. data/spec/motion/rss_parser_spec.rb +36 -0
  65. metadata +75 -16
data/Rakefile CHANGED
@@ -4,12 +4,17 @@ require 'motion/project'
4
4
  Bundler.setup
5
5
  Bundler.require
6
6
 
7
+ require 'bubble-wrap/all'
7
8
  require 'bubble-wrap/test'
8
9
 
9
10
  Motion::Project::App.setup do |app|
10
11
  app.name = 'testSuite'
11
12
  app.identifier = 'io.bubblewrap.testSuite'
12
- app.specs_dir = './spec/motion'
13
+ app.specs_dir = './spec/motion/'
14
+ # Hold your breath, we're going API spelunking!
15
+ spec_files = app.spec_files + Dir.glob(File.join(app.specs_dir, '**/*.rb'))
16
+ spec_files.uniq!
17
+ app.instance_variable_set(:@spec_files, spec_files)
13
18
  end
14
19
 
15
20
  namespace :spec do
@@ -21,4 +26,3 @@ namespace :spec do
21
26
 
22
27
  task :all => [:lib, :motion]
23
28
  end
24
-
data/lib/bubble-wrap.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  require "bubble-wrap/version" unless defined?(BubbleWrap::VERSION)
2
- require File.expand_path('../bubble-wrap/loader', __FILE__)
3
2
  require File.expand_path('../bubble-wrap/core', __FILE__)
4
3
  require File.expand_path('../bubble-wrap/http', __FILE__)
@@ -0,0 +1,4 @@
1
+ require File.expand_path('../loader', __FILE__)
2
+ ['core', 'http', 'reactor', 'rss_parser', 'ui', 'location'].each { |sub|
3
+ require File.expand_path("../#{sub}", __FILE__)
4
+ }
@@ -0,0 +1,7 @@
1
+ require 'bubble-wrap/loader'
2
+ BubbleWrap.require('motion/core/device.rb')
3
+ BubbleWrap.require('motion/core/device/**/*.rb') do
4
+ file('motion/core/device/camera_wrapper.rb').depends_on 'motion/core/device/camera.rb'
5
+ file('motion/core/device/camera.rb').depends_on 'motion/core/device.rb'
6
+ file('motion/core/device/screen.rb').depends_on 'motion/core/device.rb'
7
+ end
@@ -1,7 +1,8 @@
1
1
  require 'bubble-wrap/loader'
2
2
  BubbleWrap.require('motion/core.rb')
3
- BubbleWrap.require('motion/core/**/*.rb') do
3
+ BubbleWrap.require('motion/core/**/*.rb') do
4
+ file('motion/core/device/camera.rb').depends_on 'motion/core/device.rb'
4
5
  file('motion/core/device/screen.rb').depends_on 'motion/core/device.rb'
5
6
  file('motion/core/pollute.rb').depends_on 'motion/core/ns_index_path.rb'
6
- file('motion/core/pollute.rb').depends_on 'motion/core/ui_control.rb'
7
7
  end
8
+ require 'bubble-wrap/ui'
@@ -6,9 +6,9 @@ module BubbleWrap
6
6
  base.instance_eval do
7
7
  def setup_with_bubblewrap(&block)
8
8
  bw_config = proc do |app|
9
- app.files = (::BubbleWrap::Requirement.files + (app.files||[])).uniq
9
+ app.files = ::BubbleWrap::Requirement.files(app.files)
10
10
  app.files_dependencies ::BubbleWrap::Requirement.files_dependencies
11
- app.frameworks = (::BubbleWrap::Requirement.frameworks + (app.frameworks||[])).uniq
11
+ app.frameworks = ::BubbleWrap::Requirement.frameworks(app.frameworks)
12
12
  block.call(app) unless block.nil?
13
13
  end
14
14
  configs.each_value &bw_config
@@ -1,2 +1,3 @@
1
1
  require 'bubble-wrap/loader'
2
+ BubbleWrap.require('motion/core/ns_url_request.rb')
2
3
  BubbleWrap.require('motion/http.rb')
@@ -2,22 +2,29 @@ unless defined?(Motion::Project::Config)
2
2
  raise "This file must be required within a RubyMotion project Rakefile."
3
3
  end
4
4
 
5
- require 'bubble-wrap/version'
6
- require 'bubble-wrap/ext'
7
- require 'bubble-wrap/requirement'
5
+ unless defined?(BubbleWrap::LOADER_PRESENT)
8
6
 
9
- module BubbleWrap
7
+ require 'bubble-wrap/version' unless defined?(VERSION)
8
+ require 'bubble-wrap/ext'
9
+ require 'bubble-wrap/requirement'
10
10
 
11
- module_function
11
+ module BubbleWrap
12
12
 
13
- def root
14
- File.expand_path('../../../', __FILE__)
15
- end
13
+ LOADER_PRESENT=true
14
+ module_function
15
+
16
+ def root
17
+ File.expand_path('../../../', __FILE__)
18
+ end
19
+
20
+ def require(file_spec, &block)
21
+ Requirement.scan(caller.first, file_spec, &block)
22
+ end
16
23
 
17
- def require(file_spec, &block)
18
- Requirement.scan(caller.first, file_spec, &block)
19
24
  end
20
25
 
21
- end
26
+ BW = BubbleWrap unless defined?(BW)
22
27
 
23
- BW = BubbleWrap
28
+ BW.require 'motion/shortcut.rb'
29
+
30
+ end
@@ -0,0 +1,6 @@
1
+ require 'bubble-wrap/loader'
2
+ BubbleWrap.require('motion/core/string.rb')
3
+ BubbleWrap.require('motion/location/**/*.rb') do
4
+ file('motion/location/pollute.rb').depends_on 'motion/location/location.rb'
5
+ file('motion/location/location.rb').uses_framework('CoreLocation')
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'bubble-wrap/loader'
2
+
3
+ BW.require 'motion/reactor.rb'
4
+ BW.require 'motion/reactor/**/*.rb' do
5
+ file('motion/reactor.rb').depends_on Dir.glob('motion/reactor/**/*.rb')
6
+ file('motion/reactor/timer.rb').depends_on 'motion/reactor/eventable.rb'
7
+ file('motion/reactor/periodic_timer.rb').depends_on 'motion/reactor/eventable.rb'
8
+ file('motion/reactor/deferrable.rb').depends_on ['motion/reactor/timer.rb', 'motion/reactor/future.rb']
9
+ file('motion/reactor/default_deferrable.rb').depends_on 'motion/reactor/deferrable.rb'
10
+ end
@@ -57,6 +57,7 @@ module BubbleWrap
57
57
  Dir.glob(File.expand_path(file_spec, root)).each do |file|
58
58
  p = new(file,root)
59
59
  self.paths[p.relative] = p
60
+ p.depends_on('motion/shortcut.rb') unless p.relative == 'motion/shortcut.rb'
60
61
  end
61
62
  self.class_eval(&block) if block
62
63
  end
@@ -65,8 +66,14 @@ module BubbleWrap
65
66
  paths.fetch(relative)
66
67
  end
67
68
 
68
- def files
69
- paths.values.map(&:to_s)
69
+ def files(app_files=nil)
70
+ files = paths.values.map(&:to_s)
71
+ files += app_files if app_files
72
+ files.uniq
73
+ end
74
+
75
+ def clear!
76
+ paths.select! { |k,v| v.relative == 'motion/shortcut.rb' }
70
77
  end
71
78
 
72
79
  def files_dependencies
@@ -77,9 +84,10 @@ module BubbleWrap
77
84
  deps
78
85
  end
79
86
 
80
- def frameworks
87
+ def frameworks(app_frameworks=nil)
81
88
  frameworks = ['UIKit', 'Foundation', 'CoreGraphics'] +
82
89
  paths.values.map(&:frameworks)
90
+ frameworks += app_frameworks if app_frameworks
83
91
  frameworks.flatten.compact.sort.uniq
84
92
  end
85
93
 
@@ -0,0 +1,2 @@
1
+ require 'bubble-wrap/loader'
2
+ BubbleWrap.require('motion/rss_parser.rb')
@@ -0,0 +1,4 @@
1
+ require 'bubble-wrap/loader'
2
+ BubbleWrap.require('motion/ui/**/*.rb') do
3
+ file('motion/ui/pollute.rb').depends_on 'motion/ui/ui_control.rb'
4
+ end
@@ -1,3 +1,3 @@
1
1
  module BubbleWrap
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0' unless defined?(BubbleWrap::VERSION)
3
3
  end
data/motion/core.rb CHANGED
@@ -11,7 +11,7 @@ module BubbleWrap
11
11
  UIColor.colorWithRed((r/255.0), green:(g/255.0), blue:(b/255.0), alpha:a)
12
12
  end
13
13
 
14
- def NSLocalizedString(key, value)
14
+ def localized_string(key, value)
15
15
  NSBundle.mainBundle.localizedStringForKey(key, value:value, table:nil)
16
16
  end
17
17
 
@@ -20,5 +20,11 @@ module BubbleWrap
20
20
  NSLog arg.inspect
21
21
  end
22
22
 
23
+ def create_uuid
24
+ uuid = CFUUIDCreate(nil)
25
+ uuid_string = CFUUIDCreateString(nil, uuid)
26
+ CFRelease(uuid)
27
+ uuid_string
28
+ end
29
+
23
30
  end
24
- BW = BubbleWrap
data/motion/core/app.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Provides a module to store global states
1
+ # Provides a module to store global states
2
2
  #
3
3
  module BubbleWrap
4
4
  module App
@@ -26,12 +26,30 @@ module BubbleWrap
26
26
  NSUserDefaults.standardUserDefaults
27
27
  end
28
28
 
29
- def alert(msg,cancelButtonTitle='OK')
30
- alert = UIAlertView.alloc.initWithTitle msg,
31
- message: nil,
32
- delegate: nil,
33
- cancelButtonTitle: cancelButtonTitle,
29
+ # Displays a UIAlertView.
30
+ #
31
+ # title - The title as a String.
32
+ # args - The title of the cancel button as a String, or a Hash of options.
33
+ # (Default: { cancel_button_title: 'OK' })
34
+ # cancel_button_title - The title of the cancel button as a String.
35
+ # message - The main message as a String.
36
+ # block - Yields the alert object if a block is given, and does so before the alert is shown.
37
+ def alert(title, *args, &block)
38
+ options = { cancel_button_title: 'OK' }
39
+ options.merge!(args.pop) if args.last.is_a?(Hash)
40
+
41
+ if args.size > 0 && args.first.is_a?(String)
42
+ options[:cancel_button_title] = args.shift
43
+ end
44
+
45
+ alert = UIAlertView.alloc.initWithTitle title,
46
+ message: options[:message],
47
+ delegate: nil,
48
+ cancelButtonTitle: options[:cancel_button_title],
34
49
  otherButtonTitles: nil
50
+
51
+ yield(alert) if block_given?
52
+
35
53
  alert.show
36
54
  alert
37
55
  end
@@ -47,6 +65,16 @@ module BubbleWrap
47
65
  repeats: false)
48
66
  end
49
67
 
68
+ # Opens an url (string or instance of `NSURL`)
69
+ # in the device's web browser.
70
+ # Usage Example:
71
+ # App.open_url("http://matt.aimonetti.net")
72
+ def open_url(url)
73
+ unless url.is_a?(NSURL)
74
+ url = NSURL.URLWithString(url)
75
+ end
76
+ UIApplication.sharedApplication.openURL(url)
77
+ end
50
78
 
51
79
  @states = {}
52
80
 
@@ -14,15 +14,24 @@ module BubbleWrap
14
14
  idiom == UIUserInterfaceIdiomPad
15
15
  end
16
16
 
17
+ # Use this to make a DSL-style call for picking images
18
+ # @example Device.camera.front
19
+ # @return [Device::Camera::CameraWrapper]
20
+ def camera
21
+ BubbleWrap::Device::CameraWrapper
22
+ end
23
+
17
24
  # Verifies that the device running has a front facing camera.
18
25
  # @return [TrueClass, FalseClass] true will be returned if the device has a front facing camera, false otherwise.
19
- def front_camera?(picker=UIImagePickerController)
26
+ def front_camera?
27
+ p "This method (front_camera?) is DEPRECATED. Transition to using Device.camera.front?"
20
28
  picker.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceFront)
21
29
  end
22
30
 
23
31
  # Verifies that the device running has a rear facing camera.
24
32
  # @return [TrueClass, FalseClass] true will be returned if the device has a rear facing camera, false otherwise.
25
33
  def rear_camera?(picker=UIImagePickerController)
34
+ p "This method (rear_camera?) is DEPRECATED. Transition to using Device.camera.rear?"
26
35
  picker.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceRear)
27
36
  end
28
37
 
@@ -0,0 +1,219 @@
1
+ # Provides a nice DSL for interacting with the standard
2
+ # UIImagePickerController
3
+ #
4
+ module BubbleWrap
5
+ module Device
6
+ class Camera
7
+ module Error
8
+ SOURCE_TYPE_NOT_AVAILABLE=0
9
+ INVALID_MEDIA_TYPE=1
10
+ MEDIA_TYPE_NOT_AVAILABLE=2
11
+ INVALID_CAMERA_LOCATION=3
12
+ CANCELED=1000
13
+ end
14
+
15
+ MEDIA_TYPE_HASH = {movie: KUTTypeMovie, image: KUTTypeImage}
16
+
17
+ # The camera location; if :none, then we can't use source_type: :camera
18
+ # in #picture
19
+ # [:front, :rear, :none]
20
+ attr_accessor :location
21
+
22
+ def self.front
23
+ return nil if not UIImagePickerController.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceFront)
24
+ Camera.new(:front).retain
25
+ end
26
+
27
+ def self.rear
28
+ return nil if not UIImagePickerController.isCameraDeviceAvailable(UIImagePickerControllerCameraDeviceRear)
29
+ Camera.new(:rear).retain
30
+ end
31
+
32
+ # For uploading photos from the library.
33
+ def self.any
34
+ Camera.new.retain
35
+ end
36
+
37
+ def initialize(location = :none)
38
+ self.location = location
39
+ end
40
+
41
+ def location=(location)
42
+ if not [:front, :rear, :none].member? location
43
+ raise Error::INVALID_CAMERA_LOCATION, "#{location} is not a valid camera location"
44
+ end
45
+ @location = location
46
+ end
47
+
48
+ def flash?
49
+ return false if self.location == :none
50
+ UIImagePickerController.isFlashAvailableForCameraDevice(camera_device)
51
+ end
52
+
53
+ # @param [Hash] options to open the UIImagePickerController with
54
+ # the form {
55
+ # source_type: :photo_library, :camera, or :saved_photos_album; default :photo_library
56
+ # media_types: [] containing :image and/or :movie; default [:image]
57
+ # allows_editing: true/false; default false
58
+ # animated: true/false; default true
59
+ # }
60
+ #
61
+ # @param [UIViewController] view controller from which to present the image picker;
62
+ # if nil, uses the keyWindow's rootViewController.
63
+ #
64
+ # @block for callback. takes one argument.
65
+ # - On error or cancelled, is called with a hash {error: BW::Camera::Error::<Type>}
66
+ # - On success, is called with a hash with a possible set of keys
67
+ # [:media_type, :original_image, :edited_image, :crop_rect, :media_url,
68
+ # :reference_url, :media_metadata]
69
+ #
70
+ # Example
71
+ # BW::Camera.picture(source_type: :photo_library, media_types: [:image]) do |result|
72
+ # image_view = UIImageView.alloc.initWithImage(result[:original_image])
73
+ # end
74
+ def picture(options = {}, presenting_controller = nil, &block)
75
+ @callback = block
76
+
77
+ @options = options
78
+ @options[:allows_editing] = false if not @options.has_key? :allows_editing
79
+ @options[:animated] = true if not @options.has_key? :animated
80
+ @options[:media_types] = [:image] if not @options.has_key? :media_types
81
+
82
+ # If we're using Camera.any, by default use photo library
83
+ if !@options.has_key?(:source_type) and self.location == :none
84
+ @options[:source_type] = :photo_library
85
+ # If we're using a real Camera, by default use the camera.
86
+ elsif !@options.has_key?(:source_type)
87
+ @options[:source_type] = :camera
88
+ end
89
+
90
+ source_type = const_int_get("UIImagePickerControllerSourceType", @options[:source_type])
91
+ if not Camera.source_type_available?(source_type)
92
+ error(Error::SOURCE_TYPE_NOT_AVAILABLE) and return
93
+ end
94
+
95
+ media_types = @options[:media_types].collect { |mt| symbol_to_media_type(mt) }
96
+ if media_types.member? nil
97
+ error(Error::INVALID_MEDIA_TYPE) and return
98
+ end
99
+
100
+ media_types.each { |media_type|
101
+ if not Camera.media_type_available?(media_type, for_source_type: source_type)
102
+ error(Error::MEDIA_TYPE_NOT_AVAILABLE) and return
103
+ end
104
+ }
105
+
106
+ self.picker.delegate = self
107
+ self.picker.sourceType = source_type
108
+ self.picker.mediaTypes = media_types
109
+ self.picker.allowsEditing = @options[:allows_editing]
110
+
111
+ if source_type == :camera && ![:front, :rear].member?(self.location)
112
+ raise Error::INVALID_CAMERA_LOCATION, "Can't use camera location #{self.location} with source type :camera"
113
+ end
114
+
115
+ if source_type == :camera
116
+ self.picker.cameraDevice = camera_device
117
+ end
118
+
119
+ presenting_controller ||= UIApplication.sharedApplication.keyWindow.rootViewController
120
+ presenting_controller.presentViewController(self.picker, animated:@options[:animated], completion: lambda {})
121
+ end
122
+
123
+ ##########
124
+ # UIImagePickerControllerDelegate Methods
125
+ def imagePickerControllerDidCancel(picker)
126
+ error(Error::CANCELED)
127
+ dismiss
128
+ end
129
+
130
+ # Takes the default didFinishPickingMediaWithInfo hash,
131
+ # transforms the keys to be nicer symbols of :this_form
132
+ # instead of UIImagePickerControllerThisForm, and then sends it
133
+ # to the callback
134
+ def imagePickerController(picker, didFinishPickingMediaWithInfo: info)
135
+ delete_keys = []
136
+ callback_info = {}
137
+
138
+ info.keys.each { |k|
139
+ nice_key = k.gsub("UIImagePickerController", "").underscore.to_sym
140
+ val = info[k]
141
+ callback_info[nice_key] = val
142
+ info.delete k
143
+ }
144
+
145
+ if media_type = callback_info[:media_type]
146
+ callback_info[:media_type] = media_type_to_symbol(media_type)
147
+ end
148
+
149
+ @callback.call(callback_info)
150
+ dismiss
151
+ end
152
+
153
+ ##########
154
+ # Short Helper Methods
155
+ def picker
156
+ @picker_klass ||= UIImagePickerController
157
+ @picker ||= @picker_klass.alloc.init
158
+ end
159
+
160
+ def dismiss
161
+ self.picker.dismissViewControllerAnimated(@options[:animated], completion: lambda {})
162
+ end
163
+
164
+ # @param [UIImagePickerControllerSourceType] source_type to check
165
+ def self.source_type_available?(source_type)
166
+ UIImagePickerController.isSourceTypeAvailable(source_type)
167
+ end
168
+
169
+ # @param [String] (either KUTTypeMovie or KUTTypeImage)
170
+ # @param [UIImagePickerControllerSourceType]
171
+ def self.media_type_available?(media_type, for_source_type: source_type)
172
+ UIImagePickerController.availableMediaTypesForSourceType(source_type).member? media_type
173
+ end
174
+
175
+ private
176
+ def camera_device
177
+ const_int_get("UIImagePickerControllerCameraDevice", self.location)
178
+ end
179
+
180
+ # ex media_type_to_symbol(KUTTypeMovie) => :movie
181
+ def media_type_to_symbol(media_type)
182
+ MEDIA_TYPE_HASH.invert[media_type]
183
+ end
184
+
185
+ # ex symbol_to_media_type(:movie) => :KUTTypeMovie
186
+ def symbol_to_media_type(symbol)
187
+ MEDIA_TYPE_HASH[symbol]
188
+ end
189
+
190
+ def error(type)
191
+ @callback.call({ error: type })
192
+ end
193
+
194
+ # @param [String] base of the constant
195
+ # @param [Integer, String, Symbol] the
196
+ # @return [Integer] the constant for this base
197
+ # Examples
198
+ # const_int_get("UIReturnKey", :done) => UIReturnKeyDone == 9
199
+ # const_int_get("UIReturnKey", "done") => UIReturnKeyDone == 9
200
+ # const_int_get("UIReturnKey", 9) => 9
201
+ def const_int_get(base, value)
202
+ return value if value.is_a? Numeric
203
+ value = value.to_s.camelize
204
+ Kernel.const_get("#{base}#{value}")
205
+ end
206
+
207
+ # Looks like RubyMotion adds UIKit constants
208
+ # at compile time. If you don't use these
209
+ # directly in your code, they don't get added
210
+ # to Kernel and const_int_get crashes.
211
+ def load_constants_hack
212
+ [UIImagePickerControllerSourceTypePhotoLibrary, UIImagePickerControllerSourceTypeCamera,
213
+ UIImagePickerControllerSourceTypeSavedPhotosAlbum
214
+ ]
215
+ end
216
+ end
217
+ end
218
+ end
219
+ ::Camera = BubbleWrap::Device::Camera