bubble-wrap 1.0.0 → 1.1.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 (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