rmx 0.6.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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +40 -0
  6. data/Rakefile +18 -0
  7. data/app/app_delegate.rb +5 -0
  8. data/lib/motion/RMXActionSheet.rb +14 -0
  9. data/lib/motion/RMXAutoLayoutLabel.rb +19 -0
  10. data/lib/motion/RMXAutoLayoutScrollView.rb +53 -0
  11. data/lib/motion/RMXCommonMethods.rb +27 -0
  12. data/lib/motion/RMXEventsFromProxy.rb +103 -0
  13. data/lib/motion/RMXExecutionBlock.rb +51 -0
  14. data/lib/motion/RMXKeyboardHelpers.rb +54 -0
  15. data/lib/motion/RMXLongTask.rb +133 -0
  16. data/lib/motion/RMXNavigationController.rb +133 -0
  17. data/lib/motion/RMXObjectExtensions.rb +10 -0
  18. data/lib/motion/RMXSegmentedController.rb +71 -0
  19. data/lib/motion/RMXSetAttributes.rb +34 -0
  20. data/lib/motion/RMXStrongToWeakHash.rb +46 -0
  21. data/lib/motion/RMXSynchronizedStrongToWeakHash.rb +40 -0
  22. data/lib/motion/RMXTableHandler.rb +212 -0
  23. data/lib/motion/RMXTableViewCell.rb +85 -0
  24. data/lib/motion/RMXTableViewCellInnerContentView.rb +16 -0
  25. data/lib/motion/RMXTableViewController.rb +65 -0
  26. data/lib/motion/RMXUnsafeUnretainedHolder.rb +30 -0
  27. data/lib/motion/RMXView.rb +84 -0
  28. data/lib/motion/RMXViewController.rb +65 -0
  29. data/lib/motion/RMXViewControllerPresentation.rb +127 -0
  30. data/lib/motion/RMXWeakHolder.rb +36 -0
  31. data/lib/motion/RMXWeakToStrongHash.rb +39 -0
  32. data/lib/motion/accessors.rb +29 -0
  33. data/lib/motion/base.rb +12 -0
  34. data/lib/motion/env.rb +9 -0
  35. data/lib/motion/events.rb +61 -0
  36. data/lib/motion/layout.rb +357 -0
  37. data/lib/motion/ui.rb +55 -0
  38. data/lib/motion/util.rb +155 -0
  39. data/lib/rmx/version.rb +3 -0
  40. data/lib/rmx.rb +50 -0
  41. data/resources/Default-568h@2x.png +0 -0
  42. data/rmx.gemspec +19 -0
  43. data/spec/main_spec.rb +240 -0
  44. metadata +86 -0
@@ -0,0 +1,357 @@
1
+ class RMX
2
+ class Layout
3
+
4
+ ATTRIBUTE_LOOKUP = {
5
+ "left" => NSLayoutAttributeLeft,
6
+ "right" => NSLayoutAttributeRight,
7
+ "top" => NSLayoutAttributeTop,
8
+ "bottom" => NSLayoutAttributeBottom,
9
+ "leading" => NSLayoutAttributeLeading,
10
+ "trailing" => NSLayoutAttributeTrailing,
11
+ "width" => NSLayoutAttributeWidth,
12
+ "height" => NSLayoutAttributeHeight,
13
+ "centerX" => NSLayoutAttributeCenterX,
14
+ "centerY" => NSLayoutAttributeCenterY,
15
+ "baseline" => NSLayoutAttributeBaseline,
16
+ nil => NSLayoutAttributeNotAnAttribute
17
+ }
18
+
19
+ ATTRIBUTE_LOOKUP_INVERSE = ATTRIBUTE_LOOKUP.invert
20
+
21
+ RELATED_BY_LOOKUP = {
22
+ "<=" => NSLayoutRelationLessThanOrEqual,
23
+ "==" => NSLayoutRelationEqual,
24
+ ">=" => NSLayoutRelationGreaterThanOrEqual
25
+ }
26
+
27
+ RELATED_BY_LOOKUP_INVERSE = RELATED_BY_LOOKUP.invert
28
+
29
+ PRIORITY_LOOKUP = {
30
+ "max" => UILayoutPriorityRequired, # = 1000
31
+ "required" => UILayoutPriorityRequired, # = 1000
32
+ "high" => UILayoutPriorityDefaultHigh, # = 750
33
+ "med" => 500,
34
+ "low" => UILayoutPriorityDefaultLow, # = 250
35
+ "fit" => UILayoutPriorityFittingSizeLevel # = 50
36
+ }
37
+
38
+ PRIORITY_LOOKUP_INVERSE = PRIORITY_LOOKUP.invert
39
+
40
+ AXIS_LOOKUP = {
41
+ "h" => UILayoutConstraintAxisHorizontal,
42
+ "v" => UILayoutConstraintAxisVertical
43
+ }
44
+
45
+ # keeps track of views that are not #hidden? as constraints are built, so the
46
+ # special `last_visible` view name can be used in equations.
47
+ # exposed for advanced layout needs.
48
+ attr_accessor :visible_items
49
+
50
+ # Example:
51
+ # RMX::Layout.new do |layout|
52
+ # ...
53
+ # end
54
+ def initialize(&block)
55
+ @block_owner = block.owner if block
56
+ @visible_items = []
57
+ @constraints = {}
58
+ unless block.nil?
59
+ block.call(self)
60
+ block = nil
61
+ end
62
+ end
63
+
64
+ # reopens the RMX::Layout instance for additional processing, ex:
65
+ # @layout.reopen do |layout|
66
+ # ...
67
+ # end
68
+ # note: you would need to store your instance somewhere on creation to be able to reopen it later, ex:
69
+ # @layout = RMX::Layout.new do |layout|
70
+ # ...
71
+ # end
72
+ def reopen
73
+ if block_given?
74
+ yield self
75
+ end
76
+ self
77
+ end
78
+
79
+ def clear!
80
+ @view.removeConstraints(@view.constraints)
81
+ end
82
+
83
+ def remove(constraint)
84
+ constraints = [ constraint ].flatten.compact
85
+ @view.removeConstraints(constraints)
86
+ @constraints.keys.each do |key|
87
+ @constraints.delete(key) if constraints.include?(@constraints.fetch(key))
88
+ end
89
+ true
90
+ end
91
+
92
+ def view(view)
93
+ @view = view
94
+ end
95
+
96
+ def view=(v)
97
+ view(v)
98
+ end
99
+
100
+ def subviews(subviews)
101
+ @subviews = subviews
102
+ @subviews.values.each do |subview|
103
+ subview.translatesAutoresizingMaskIntoConstraints = false
104
+ @view.addSubview(subview)
105
+ end
106
+ @subviews
107
+ end
108
+
109
+ def subviews=(views)
110
+ subviews(views)
111
+ end
112
+
113
+ # takes a string one or more equations separated by newlines and
114
+ # processes each. returns an array of constraints
115
+ def eqs(str)
116
+ str.split("\n").map(&:strip).select { |x| !x.empty? }.map do |line|
117
+ eq(line)
118
+ end.compact
119
+ end
120
+
121
+ # Constraints are of the form "view1.attr1 <relation> view2.attr2 * multiplier + constant @ priority"
122
+ # processes one equation string
123
+ def eq(str, remove=false)
124
+ parts = str.split("#", 2).first.split(" ").select { |x| !x.empty? }
125
+ return if parts.empty?
126
+
127
+ item = nil
128
+ item_attribute = nil
129
+ related_by = nil
130
+ to_item = nil
131
+ to_item_attribute = nil
132
+ multiplier = 1.0
133
+ constant = 0.0
134
+
135
+ debug = parts.delete("?")
136
+
137
+ # first part should always be view1.attr1
138
+ part = parts.shift
139
+ item, item_attribute = part.split(".", 2)
140
+
141
+ # second part should always be relation
142
+ related_by = parts.shift
143
+
144
+ # now things get more complicated
145
+
146
+ # look for priority
147
+ if idx = parts.index("@")
148
+ priority = parts[idx + 1]
149
+ parts.delete_at(idx)
150
+ parts.delete_at(idx)
151
+ end
152
+
153
+ # look for negative or positive constant
154
+ if idx = parts.index("-")
155
+ constant = "-#{parts[idx + 1]}"
156
+ parts.delete_at(idx)
157
+ parts.delete_at(idx)
158
+ elsif idx = parts.index("+")
159
+ constant = parts[idx + 1]
160
+ parts.delete_at(idx)
161
+ parts.delete_at(idx)
162
+ end
163
+
164
+ # look for multiplier
165
+ if idx = parts.index("*")
166
+ multiplier = parts[idx + 1]
167
+ parts.delete_at(idx)
168
+ parts.delete_at(idx)
169
+ end
170
+
171
+ # now we need to_item, to_item_attribute
172
+
173
+ if part = parts.shift
174
+ # if part includes a . it could be either view2.attr2 or a float like 10.5
175
+ l, r = part.split(".", 2)
176
+ if !r || (r && r =~ /\d/)
177
+ # assume a solo constant was on the right side
178
+ constant = part
179
+ else
180
+ # assume view2.attr2
181
+ to_item, to_item_attribute = l, r
182
+ end
183
+ end
184
+
185
+ # if we dont have to_item and the item_attribute is something that requires a to_item, then
186
+ # assume superview
187
+ if !to_item
188
+ unless item_attribute == "height" || item_attribute == "width"
189
+ to_item = "view"
190
+ to_item_attribute = item_attribute
191
+ end
192
+ end
193
+
194
+ # normalize
195
+
196
+ if item == "last_visible"
197
+ item = @visible_items.first || "view"
198
+ end
199
+
200
+ res_item = view_for_item(item)
201
+ res_constant = Float(PRIORITY_LOOKUP[constant] || constant)
202
+
203
+ if res_item
204
+ case item_attribute
205
+ when "resistH"
206
+ return res_item.setContentCompressionResistancePriority(res_constant, forAxis:UILayoutConstraintAxisHorizontal)
207
+ when "resistV"
208
+ return res_item.setContentCompressionResistancePriority(res_constant, forAxis:UILayoutConstraintAxisVertical)
209
+ when "hugH"
210
+ return res_item.setContentHuggingPriority(res_constant, forAxis:UILayoutConstraintAxisHorizontal)
211
+ when "hugV"
212
+ return res_item.setContentHuggingPriority(res_constant, forAxis:UILayoutConstraintAxisVertical)
213
+ end
214
+ end
215
+
216
+ if to_item == "last_visible"
217
+ to_item = @visible_items.detect { |x| x != item } || "view"
218
+ end
219
+
220
+ res_item_attribute = ATTRIBUTE_LOOKUP[item_attribute]
221
+ res_related_by = RELATED_BY_LOOKUP[related_by]
222
+ res_to_item = to_item ? view_for_item(to_item) : nil
223
+ res_to_item_attribute = ATTRIBUTE_LOOKUP[to_item_attribute]
224
+ res_multiplier = Float(multiplier)
225
+ res_priority = priority ? Integer(PRIORITY_LOOKUP[priority] || priority) : nil
226
+
227
+ errors = []
228
+ errors.push("Invalid view1: #{item}") unless res_item
229
+ errors.push("Invalid attr1: #{item_attribute}") unless res_item_attribute
230
+ errors.push("Invalid relatedBy: #{related_by}") unless res_related_by
231
+ errors.push("Invalid view2: #{to_item}") if to_item && !res_to_item
232
+ errors.push("Invalid attr2: #{to_item_attribute}") unless res_to_item_attribute
233
+
234
+ internal_ident = "#{item}.#{item_attribute} #{related_by} #{to_item}.#{to_item_attribute} * #{multiplier} @ #{priority}"
235
+
236
+ if errors.size > 0 || debug
237
+ p "======================== constraint debug ========================"
238
+ p "given:"
239
+ p " #{str}"
240
+ p "interpreted:"
241
+ p " item: #{item}"
242
+ p " item_attribute: #{item_attribute}"
243
+ p " related_by: #{related_by}"
244
+ p " to_item: #{to_item}"
245
+ p " to_item_attribute: #{to_item_attribute}"
246
+ p " multiplier: #{multiplier}"
247
+ p " constant: #{constant}"
248
+ p " priority: #{priority || "required"}"
249
+ p " internal_ident: #{internal_ident}"
250
+ end
251
+
252
+ if errors.size > 0
253
+ raise(errors.join(", "))
254
+ end
255
+
256
+ unless res_item.hidden?
257
+ @visible_items.unshift(item)
258
+ end
259
+
260
+ if remove
261
+ if constraint = @constraints[internal_ident]
262
+ if debug
263
+ p "status:"
264
+ p " existing (for removal)"
265
+ end
266
+ @view.removeConstraint(constraint)
267
+ else
268
+ raise "RMX::Layout could not find constraint to remove for internal_ident: `#{internal_ident}` (note: this is an internal representation of the constraint, not the exact string given). Make sure the constraint was created first."
269
+ end
270
+ elsif constraint = @constraints[internal_ident]
271
+ if debug
272
+ p "status:"
273
+ p " existing (for modification)"
274
+ end
275
+ constraint.constant = res_constant
276
+ else
277
+ constraint = NSLayoutConstraint.constraintWithItem(res_item,
278
+ attribute:res_item_attribute,
279
+ relatedBy:res_related_by,
280
+ toItem:res_to_item,
281
+ attribute:res_to_item_attribute,
282
+ multiplier:res_multiplier,
283
+ constant:res_constant)
284
+ if debug
285
+ p "status:"
286
+ p " created"
287
+ end
288
+ @constraints[internal_ident] = constraint
289
+ if res_priority
290
+ constraint.priority = res_priority
291
+ end
292
+ @view.addConstraint(constraint)
293
+ end
294
+
295
+ if debug
296
+ p "implemented:"
297
+ p " #{constraint.description}"
298
+ end
299
+
300
+ constraint
301
+ end
302
+
303
+ # removes the constraint matching equation string. constant is not considered.
304
+ # if no matching constraint is found, it will raise an exception.
305
+ def xeq(str)
306
+ eq(str, true)
307
+ end
308
+
309
+ def describe_constraint(constraint)
310
+ self.class.describe_constraint(@subviews, constraint)
311
+ end
312
+
313
+ def describe_view
314
+ self.class.describe_view(@subviews, @view)
315
+ end
316
+
317
+ # transforms an NSLayoutConstraint into a string. this string is for debugging and produces
318
+ # a verbose translation. its not meant to be copied directly as an equation.
319
+ # pass the subviews hash just as you would to Layout#subviews=, followed by the NSLayoutConstraint
320
+ def self.describe_constraint(subviews, constraint)
321
+ subviews_inverse = subviews.invert
322
+ item = subviews_inverse[constraint.firstItem] || "view"
323
+ item_attribute = ATTRIBUTE_LOOKUP_INVERSE[constraint.firstAttribute]
324
+ related_by = RELATED_BY_LOOKUP_INVERSE[constraint.relation]
325
+ to_item = subviews_inverse[constraint.secondItem] || "view"
326
+ to_item_attribute = ATTRIBUTE_LOOKUP_INVERSE[constraint.secondAttribute]
327
+ multiplier = constraint.multiplier
328
+ constant = constraint.constant
329
+ priority = PRIORITY_LOOKUP_INVERSE[constraint.priority] || constraint.priority
330
+ "#{constraint.description}\n#{item}.#{item_attribute} #{related_by} #{to_item}.#{to_item_attribute} * #{multiplier} + #{constant} @ #{priority}"
331
+ end
332
+
333
+ # transforms a view's NSLayoutConstraints into strings.
334
+ # pass the subviews hash just as you would to Layout#subviews=, followed by the view to
335
+ # describe
336
+ def self.describe_view(subviews, view)
337
+ view.constraints.map do |constraint|
338
+ describe_constraint(subviews, constraint)
339
+ end.join("\n")
340
+ end
341
+
342
+ private
343
+
344
+ def view_for_item(item)
345
+ if item == "view"
346
+ @view
347
+ elsif item == "topLayoutGuide"
348
+ @block_owner && @block_owner.topLayoutGuide
349
+ elsif item == "bottomLayoutGuide"
350
+ @block_owner && @block_owner.bottomLayoutGuide
351
+ elsif v = (@subviews && @subviews[item])
352
+ v
353
+ end
354
+ end
355
+
356
+ end
357
+ end
data/lib/motion/ui.rb ADDED
@@ -0,0 +1,55 @@
1
+ class RMX
2
+
3
+ def self.app
4
+ UIApplication.sharedApplication
5
+ end
6
+
7
+ def self.ios_version
8
+ @ios_version ||= UIDevice.currentDevice.systemVersion.split(".").take(2).join(".").to_f
9
+ end
10
+
11
+ def self.screen_pixel
12
+ 1.0 / UIScreen.mainScreen.scale
13
+ end
14
+
15
+ def self.keyboardWillChangeFrame(notification)
16
+ @keyboardWillChangeFrameNotification = notification
17
+ processKeyboardWillChange
18
+ end
19
+
20
+ def self.processKeyboardWillChange
21
+ return unless notification = @keyboardWillChangeFrameNotification
22
+ info = notification.userInfo
23
+ keyboardFrame = info.objectForKey(UIKeyboardFrameEndUserInfoKey).CGRectValue
24
+ bounds = UIScreen.mainScreen.bounds
25
+ animationDuration = info.objectForKey(UIKeyboardAnimationDurationUserInfoKey).doubleValue
26
+ # below the screen # above the screen # left of the screen # right of the screen
27
+ currentKeyboardHeight = if keyboardFrame.origin.y >= bounds.size.height || keyboardFrame.origin.y <= bounds.origin.y - keyboardFrame.size.height || keyboardFrame.origin.x <= bounds.origin.x - keyboardFrame.size.width || keyboardFrame.origin.x >= bounds.size.width
28
+ 0
29
+ else
30
+ keyboardFrame.size.height
31
+ end
32
+ # p "================>"
33
+ if currentKeyboardHeight != @currentKeyboardHeight
34
+ @currentKeyboardHeight = currentKeyboardHeight
35
+ # p "currentKeyboardHeight", currentKeyboardHeight
36
+ # p "keyboardFrame", keyboardFrame
37
+ # p "UIScreen.mainScreen.bounds", UIScreen.mainScreen.bounds
38
+ NSNotificationCenter.defaultCenter.postNotificationName("rmxKeyboardChanged", object:nil, userInfo:{
39
+ :height => currentKeyboardHeight,
40
+ :animationDuration => animationDuration
41
+ })
42
+ end
43
+ @keyboardWillChangeFrameNotification = nil
44
+ end
45
+
46
+ def self.currentKeyboardHeight
47
+ @currentKeyboardHeight || 0
48
+ end
49
+ NSNotificationCenter.defaultCenter.addObserver(self, selector:'keyboardWillChangeFrame:', name:UIKeyboardWillChangeFrameNotification, object:nil)
50
+
51
+ end
52
+
53
+ def RMX(_object)
54
+ RMX.new(_object)
55
+ end
@@ -0,0 +1,155 @@
1
+ class RMX
2
+
3
+ def self.safe_block(block)
4
+ weak_block_owner_holder = RMXWeakHolder.new(block.owner)
5
+ block.weak!
6
+ proc do |*args|
7
+ if wbo = weak_block_owner_holder.value
8
+ block.call(*args)
9
+ end
10
+ end
11
+ end
12
+
13
+ # Raises an exception when called from a thread other than the main thread.
14
+ # Good for development and experimenting.
15
+ def self.assert_main_thread!
16
+ raise "Expected main thread. #{Dispatch::Queue.current.description}" unless NSThread.currentThread.isMainThread
17
+ end
18
+
19
+ # call the block immediately if called on the main thread,
20
+ # otherwise call it async on the main queue
21
+ def self.inline_or_on_main_q(&block)
22
+ if NSThread.currentThread.isMainThread
23
+ block.call
24
+ else
25
+ Dispatch::Queue.main do
26
+ block.call
27
+ end
28
+ end
29
+ end
30
+
31
+ # call the block immediately if called on the main thread with the given args,
32
+ # otherwise call it async on the main queue.
33
+ # silently ignores nil blocks to avoid if !block.nil? checks, useful for async callbacks
34
+ # that optionally take a callback
35
+ def self.block_on_main_q(block, *args)
36
+ unless block.nil?
37
+ inline_or_on_main_q do
38
+ block.call(*args)
39
+ end
40
+ end
41
+ end
42
+
43
+ def require_queue!(queue, file, line)
44
+ unless Dispatch::Queue.current.description == queue.description
45
+ raise "WRONG QUEUE: was: #{Dispatch::Queue.current.description}, expected: #{queue.description}. #{@object.value.inspect} #{file}:#{line}, #{caller.inspect}"
46
+ end
47
+ end
48
+
49
+ def own_methods
50
+ if object = unsafe_unretained_object
51
+ (object.methods - (object.superclass.methods)).sort
52
+ end
53
+ end
54
+
55
+ # Shortcut to instance_variable_get and instance_variable_get:
56
+ # 1 arg for instance_variable_get
57
+ # 1 arg and block for instance_variable_get || instance_variable_set
58
+ # 2 args for instance_variable_set
59
+ def ivar(*args, &block)
60
+ if object = unsafe_unretained_object
61
+ key = args[0]
62
+ val = nil
63
+ if args.size == 1
64
+ if block
65
+ val = object.instance_variable_get("@#{key}")
66
+ if val.nil?
67
+ val = block.call
68
+ object.instance_variable_set("@#{key}", val)
69
+ val
70
+ end
71
+ else
72
+ val = object.instance_variable_get("@#{key}")
73
+ end
74
+ elsif args.size == 2
75
+ val = args[1]
76
+ object.instance_variable_set("@#{key}", val)
77
+ else
78
+ raise "RMX#ivar called with invalid arguments: #{args.inspect}"
79
+ end
80
+ val
81
+ end
82
+ end
83
+
84
+ def nil_instance_variables!
85
+ if object = unsafe_unretained_object
86
+ ivars = [] + object.instance_variables
87
+ while ivar = ivars.pop
88
+ object.instance_variable_set(ivar, nil)
89
+ end
90
+ true
91
+ end
92
+ end
93
+
94
+ def debounce(unique_id, opts={}, &block)
95
+ if (seconds = opts[:seconds]) && seconds > 0
96
+ debounce_seconds(seconds, unique_id, opts[:now], &block)
97
+ else
98
+ debounce_runloop(unique_id, opts[:now], &block)
99
+ end
100
+ end
101
+
102
+ def debounce_runloop(unique_id, run_immediately=false, &block)
103
+ if object = unsafe_unretained_object
104
+ lookup = Thread.current["rmx_debounce_runloop"] ||= {}
105
+ key = [ object, unique_id ]
106
+ lookup[key] ||= begin
107
+ block.call if run_immediately
108
+ CFRunLoopPerformBlock(
109
+ CFRunLoopGetCurrent(),
110
+ KCFRunLoopDefaultMode,
111
+ lambda do
112
+ lookup.delete(key)
113
+ block.call
114
+ end
115
+ )
116
+ true
117
+ end
118
+ nil
119
+ end
120
+ end
121
+
122
+ def debounce_seconds(seconds, unique_id, run_immediately=false, &block)
123
+ if object = unsafe_unretained_object
124
+ lookup = Thread.current["rmx_debounce_seconds"] ||= {}
125
+ key = [ object, unique_id ]
126
+ lookup[key] ||= begin
127
+ block.call if run_immediately
128
+ units = CFGregorianUnits.new
129
+ units.seconds = seconds
130
+ CFRunLoopAddTimer(
131
+ CFRunLoopGetCurrent(),
132
+ CFRunLoopTimerCreateWithHandler(
133
+ KCFAllocatorDefault,
134
+ CFAbsoluteTimeAddGregorianUnits(
135
+ CFAbsoluteTimeGetCurrent(),
136
+ nil,
137
+ units
138
+ ),
139
+ 0,
140
+ 0,
141
+ 0,
142
+ lambda do |timer|
143
+ lookup.delete(key)
144
+ block.call
145
+ end
146
+ ),
147
+ KCFRunLoopDefaultMode
148
+ )
149
+ true
150
+ end
151
+ nil
152
+ end
153
+ end
154
+
155
+ end
@@ -0,0 +1,3 @@
1
+ class RMX
2
+ VERSION = "0.6.0"
3
+ end
data/lib/rmx.rb ADDED
@@ -0,0 +1,50 @@
1
+ require "rmx/version"
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+ %w(
9
+ RMXObjectExtensions
10
+ base
11
+ env
12
+ layout
13
+ util
14
+ accessors
15
+ events
16
+ ui
17
+ RMXCommonMethods
18
+ RMXWeakHolder
19
+ RMXUnsafeUnretainedHolder
20
+ RMXWeakToStrongHash
21
+ RMXStrongToWeakHash
22
+ RMXSynchronizedStrongToWeakHash
23
+ RMXEventsFromProxy
24
+ RMXExecutionBlock
25
+ RMXSetAttributes
26
+ RMXViewControllerPresentation
27
+ RMXKeyboardHelpers
28
+ RMXNavigationController
29
+ RMXTableViewController
30
+ RMXViewController
31
+ RMXSegmentedController
32
+ RMXView
33
+ RMXActionSheet
34
+ RMXAutoLayoutLabel
35
+ RMXAutoLayoutScrollView
36
+ RMXTableHandler
37
+ RMXTableViewCell
38
+ RMXTableViewCellInnerContentView
39
+ ).reverse.each do |x|
40
+ app.files.unshift(File.join(File.dirname(__FILE__), "motion/#{x}.rb"))
41
+ end
42
+ FileUtils.mkdir_p(File.expand_path("../build", File.dirname(__FILE__)))
43
+ env_filename = File.expand_path("../build/env.rb", File.dirname(__FILE__))
44
+ rmx_env = ENV['rmx_env'] == '1' ? ENV.to_hash : {}
45
+ File.open(env_filename, "w") do |f|
46
+ f.puts %Q{class RMX\n Env = #{rmx_env.inspect}\nend\n}
47
+ end
48
+ App.log "RMX::Env", rmx_env.inspect
49
+ app.files.unshift(env_filename)
50
+ end
Binary file
data/rmx.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rmx/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "rmx"
8
+ gem.version = RMX::VERSION
9
+ gem.authors = ["Joe Noon"]
10
+ gem.email = ["joenoon@gmail.com"]
11
+ gem.description = %q{Extensions and helpers for dealing with various areas of rubymotion}
12
+ gem.summary = %q{Extensions and helpers for dealing with various areas of rubymotion}
13
+ gem.homepage = "https://github.com/joenoon/rmx"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end