rmx 0.6.0

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