Class: RubyMotionQuery::RMQ

Inherits:
Object show all
Defined in:
motion/ruby_motion_query/base.rb,
motion/ruby_motion_query/app.rb,
motion/ruby_motion_query/font.rb,
motion/ruby_motion_query/tags.rb,
motion/ruby_motion_query/color.rb,
motion/ruby_motion_query/utils.rb,
motion/ruby_motion_query/image.rb,
motion/ruby_motion_query/events.rb,
motion/ruby_motion_query/format.rb,
motion/ruby_motion_query/device.rb,
motion/ruby_motion_query/factory.rb,
motion/ruby_motion_query/actions.rb,
motion/ruby_motion_query/version.rb,
motion/ruby_motion_query/subviews.rb,
motion/ruby_motion_query/position.rb,
motion/ruby_motion_query/traverse.rb,
motion/ruby_motion_query/selectors.rb,
motion/ruby_motion_query/stylesheet.rb,
motion/ruby_motion_query/enumerablish.rb

Overview

The main class for RubyMotionQuery

What's an rmq instance?

  • an rmq instance is an array-like object containing UIViews

  • rmq() never returns nil. If nothing is selected, it's an empty [ ] array-like object

  • an rmq object always (almost always) returns either itself or a new rmq object. This is how chaining works. You do not need to worry if an rmq is blank or not, everything always works without throwing a nil exception

  • jQuery uses the DOM, what is rmq using for the "DOM"? It uses the controller it was called in. The "DOM" is the controller's subview tree. If you call rmq inside a view, it will attach to the controller that the view is currently in or to the current screen's controller

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (RMQ) initialize

Returns a new instance of RMQ



20
21
22
# File 'motion/ruby_motion_query/base.rb', line 20

def initialize
  @selected_dirty = true
end

Class Method Details

+ (App) app

Returns:



9
10
11
# File 'motion/ruby_motion_query/app.rb', line 9

def self.app
  App
end

+ (Color) color

Returns:



4
5
6
# File 'motion/ruby_motion_query/color.rb', line 4

def self.color
  Color
end

+ (UIViewController) controller_for_view(view)

Returns The controller the view it is sitting in, or nil if it’s not sitting anywhere in particular

Parameters:

  • view

Returns:

  • (UIViewController)

    The controller the view it is sitting in, or nil if it’s not sitting anywhere in particular



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'motion/ruby_motion_query/utils.rb', line 28

def controller_for_view(view)
  if view && (vc = view.rmq_data.view_controller)
    vc 
  else

    # Non-recursive for speed
    while view
      view = view.nextResponder
      if view.is_a?(UIViewController)
        break
      elsif view.is_a?(UIView)
        if vc = view.rmq_data.view_controller
          view = vc
          break
        end
      else
        view = nil
      end
    end

    view

  end
end

+ (RMQ) create_with_array_and_selectors(array, selectors, context, parent_rmq = nil)

This is used internally, to get a new rmq instance, just call "rmq" in your view or controller or just create a new one like so: RubyMotionQuery::RMQ.new

Returns:



37
38
39
40
41
42
43
44
# File 'motion/ruby_motion_query/factory.rb', line 37

def create_with_array_and_selectors(array, selectors, context, parent_rmq = nil) # TODO, convert to opts
  q = RMQ.new
  q.context = context
  q.selectors = selectors
  q.parent_rmq = parent_rmq
  q.selected = array # Must be last
  q
end

+ (RMQ) create_with_selectors(selectors, context, parent_rmq = nil)

This is used internally, to get a new rmq instance, just call "rmq" in your view or controller or just create a new one like so: RubyMotionQuery::RMQ.new

Returns:



25
26
27
28
29
30
31
# File 'motion/ruby_motion_query/factory.rb', line 25

def create_with_selectors(selectors, context, parent_rmq = nil)
  q = RMQ.new
  q.context = context
  q.parent_rmq = parent_rmq
  q.selectors = selectors
  q
end

+ (Object) debugging=(flag)



309
310
311
# File 'motion/ruby_motion_query/base.rb', line 309

def debugging=(flag)
  @debugging = flag
end

+ (Boolean) debugging?

Returns:

  • (Boolean)


305
306
307
# File 'motion/ruby_motion_query/base.rb', line 305

def debugging?
  @debugging ||= ENV['rmq_debug'] == 'true'
end

+ (Device) device

Returns:



9
10
11
# File 'motion/ruby_motion_query/device.rb', line 9

def self.device
  Device
end

+ (Font) font

Returns:



4
5
6
# File 'motion/ruby_motion_query/font.rb', line 4

def self.font
  Font
end

+ (Format) format

Returns:



9
10
11
# File 'motion/ruby_motion_query/format.rb', line 9

def self.format
  Format
end

+ (ImageUtils) image

Returns:



4
5
6
# File 'motion/ruby_motion_query/image.rb', line 4

def self.image
  ImageUtils
end

+ (Boolean) is_blank?(o)

This is purposely not blank? as to not conflict with many libraries that add .blank? to Object

Returns:

  • (Boolean)


18
19
20
21
22
23
24
# File 'motion/ruby_motion_query/utils.rb', line 18

def is_blank?(o)
  if o.is_a?(RubyMotionQuery::RMQ)
    RubyMotionQuery::RMQ.is_blank?(o.to_a)
  else
    o.respond_to?(:empty?) ? o.empty? : !o
  end
end

+ (Boolean) is_class?(o)

Returns:

  • (Boolean)


6
7
8
9
10
11
12
# File 'motion/ruby_motion_query/utils.rb', line 6

def is_class?(o)
  # This line fails in spec, causes exit without message. It works fine in production
  #(o.class == Class) && (defined?(o) == 'constant')
  
  # So I'm doing this instead
  !!(o.respond_to?(:name) && o.name.to_s[0] =~ /[A-Z]/)
end

+ (String) view_to_s(view)

Mainly used for console and logging

Returns:

  • (String)


76
77
78
79
80
81
82
83
# File 'motion/ruby_motion_query/utils.rb', line 76

def view_to_s(view)
  out = "\n"
  out << "  VIEW  class:o #{view.class.name}  object_id: #{view.object_id}\n"
  out << "    RECTANGLE  left: #{view.origin.y}, top: #{view.origin.y}, width: #{view.size.width}, height: #{view.size.height}\n"
  out << "    SUPERVIEW  class: #{view.superview.class.name}  object_id: #{view.superview.object_id} \n" if view.superview
  out << "    SUBVIEWS   count: #{view.subviews.length}\n"
  out
end

+ (Object) weak_ref(o)

Creates a weak reference to an object. Unlike WeakRef.new provided by RubyMotion, this will not wrap a weak ref inside another weak ref (which causes bugs).

This is fairly performant. It's about twice as slow as WeakRef.new. However, you can create a million weak refs in about 651 miliseconds, compared to 319 for WeakRef.new

Creating a WeakRef with a literal like a string will cause your app to crash instantly, it's fun, try it. Only create weak refs of variables

foo = RubyMotionQuery::RMQ.weak_ref(bar)



64
65
66
67
68
69
70
71
# File 'motion/ruby_motion_query/utils.rb', line 64

def weak_ref(o)
  weak = WeakRef.new(o)
  if weak.is_a?(WeakRef)
    o # Already a weak ref, return original
  else
    weak
  end
end

Instance Method Details

- (RMQ) <<(value)

Returns:



8
9
10
11
# File 'motion/ruby_motion_query/enumerablish.rb', line 8

def <<(value)
  selected << value if value.is_a?(UIView)
  self
end

- (RMQ) [](i) Also known as: eq

Examples:

rmq(UILabel)[3]
or
rmq(UILabel)[1..5]

Returns:



19
20
21
# File 'motion/ruby_motion_query/enumerablish.rb', line 19

def [](i)
  RMQ.create_with_array_and_selectors([selected[i]], @selectors, @context)
end

- (RMQ) add_subview(view_or_constant, opts = {}) Also known as: insert

Returns:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'motion/ruby_motion_query/subviews.rb', line 12

def add_subview(view_or_constant, opts={})
  subviews_added = []
  style = opts[:style]

  selected.each do |selected_view|
    created = false
    appended = false


    if view_or_constant.is_a?(UIView)
      new_view = view_or_constant
    else
      created = true
      new_view = create_view(view_or_constant, opts)
    end

    new_view.rmq_data.view_controller = self.view_controller

    subviews_added << new_view

    unless opts[:do_not_add]
      if at_index = opts[:at_index]
        selected_view.insertSubview(new_view, atIndex: at_index)
      elsif below_view = opts[:below_view]
        selected_view.insertSubview(new_view, belowSubview: below_view)
      else
        selected_view.addSubview(new_view)
      end

      appended = true
    end

    if self.stylesheet
      apply_style_to_view(new_view, style) if style
    end

    if created
      new_view.rmq_did_create(self.wrap(new_view)) 
      new_view.rmq_created
    end
    new_view.rmq_build
    new_view.rmq_appended if appended
  end

  RMQ.create_with_array_and_selectors(subviews_added, selectors, @context, self)
end

- (RMQ) all

Returns All selected views

Examples:

rmq.all.log

Returns:

  • (RMQ)

    All selected views



38
39
40
# File 'motion/ruby_motion_query/traverse.rb', line 38

def all
  self.view_controller.rmq.find
end

- (RMQ) and(*working_selectors)

Returns A new rmq instance reducing selected views to those that match selectors provided

Examples:

rmq(UIImage).and(:some_tag).attr(image: nil)

Parameters:

  • selectors

    your selector

Returns:

  • (RMQ)

    A new rmq instance reducing selected views to those that match selectors provided



48
49
50
51
52
53
54
55
# File 'motion/ruby_motion_query/traverse.rb', line 48

def and(*working_selectors)
  return self unless working_selectors
  normalize_selectors(working_selectors)

  self.select do |view|
    match(view, working_selectors)
  end
end

- (RMQ) and_self Also known as: add_self

Returns A new rmq instance adding the context to the selected views

Examples:

rmq(my_view).children.and_self

Returns:

  • (RMQ)

    A new rmq instance adding the context to the selected views



77
78
79
80
81
82
83
84
85
86
# File 'motion/ruby_motion_query/traverse.rb', line 77

def and_self
  if self.parent_rmq
    out = self.parent_rmq.selected.dup
    out << selected
    out.flatten!
    RMQ.create_with_array_and_selectors(out, selectors, @context, self)
  else
    self
  end
end

- (App) app

Returns:



4
5
6
# File 'motion/ruby_motion_query/app.rb', line 4

def app
  App
end

- (RMQ) append(view_or_constant, style = nil, opts = {})

Returns:



61
62
63
64
# File 'motion/ruby_motion_query/subviews.rb', line 61

def append(view_or_constant, style=nil, opts = {})
  opts[:style] = style
  add_subview(view_or_constant, opts)
end

- (RMQ) apply_style(style_name)

Returns:



29
30
31
32
33
34
# File 'motion/ruby_motion_query/stylesheet.rb', line 29

def apply_style(style_name)
  selected.each do |selected_view|
    apply_style_to_view selected_view, style_name
  end
  self
end

- (RMQ) attr(new_settings)

Returns:



5
6
7
8
9
10
11
12
# File 'motion/ruby_motion_query/actions.rb', line 5

def attr(new_settings)
  selected.each do |view|
    new_settings.each do |k,v|
      view.send "#{k}=", v
    end
  end
  self
end

- (Object) build(view, style = nil, opts = {})

Build a view, similar to create and append, but only inits an existing view. Usefull in collectionview cells for example

# In your collectionview rmq.build(cell) unless cell.reused

# Then in your cell

def rmq_build

rmq.append(UIView, :foo)

end



112
113
114
115
116
# File 'motion/ruby_motion_query/subviews.rb', line 112

def build(view, style = nil, opts = {})
  opts[:do_not_add] = true
  opts[:style] = style
  add_subview view, opts
end

- (RMQ) children(*working_selectors) Also known as: subviews

Returns Instance selecting the children of the selected view(s)

Examples:

rmq(my_view).children.show

Parameters:

  • selectors

Returns:

  • (RMQ)

    Instance selecting the children of the selected view(s)



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'motion/ruby_motion_query/traverse.rb', line 162

def children(*working_selectors)
  normalize_selectors(working_selectors)

  filter do |view|
    subviews = view.subviews

    if RMQ.is_blank?(working_selectors)
      subviews
    else
      subviews.inject([]) do |out, subview|
        out << subview if match(subview, working_selectors)
        out
      end
    end
  end
end

- (RMQ) clear_tags

Returns:



24
25
26
27
28
29
# File 'motion/ruby_motion_query/tags.rb', line 24

def clear_tags
  selected.each do |view|
    view.rmq_data.tags.clear
  end
  self
end

- (RMQ) closest(*working_selectors)

For each selected view, get the first view that matches the selector(s) by testing the view's parent and traversing up through its ancestors in the tree

Examples:

rmq.closest(UIScrollView).get.setContentOffset([0,0])

Parameters:

  • selectors

Returns:

  • (RMQ)

    Instance selecting the first parent or grandparent or ancestor up the tree of the selected view(s)



239
240
241
242
243
244
245
# File 'motion/ruby_motion_query/traverse.rb', line 239

def closest(*working_selectors)
  normalize_selectors(working_selectors)

  filter do |view|
    closest_view(view, working_selectors)
  end
end

- (Color) color

Returns:



9
10
11
# File 'motion/ruby_motion_query/color.rb', line 9

def color 
  Color
end

- (Object) context



38
39
40
# File 'motion/ruby_motion_query/base.rb', line 38

def context
  @context
end

- (Object) context=(value)

This is mostly used internally

If rmq was called in a view, context will be that view. If it was called in a UIViewController, it will be that controller. If it is called in another object, it will be current controller's rmq instance and thus context will be that controller



30
31
32
33
34
35
36
# File 'motion/ruby_motion_query/base.rb', line 30

def context=(value)
  if value.is_a?(UIViewController)
    @context = RubyMotionQuery::RMQ.weak_ref(value)
  else
    @context = value
  end
end

- (UIView) context_or_context_view

The context is where rmq was created (not the selectors).

Normally you are inside a controller or a UIView when you execute the rmq method.

Returns:

  • (UIView)

    the controller’s view or the view you are in when calling rmq



161
162
163
164
165
166
167
# File 'motion/ruby_motion_query/base.rb', line 161

def context_or_context_view
  if @context.is_a?(UIViewController)
    @context.view
  else
    @context
  end
end

- (RMQ) create(view_or_constant, style = nil, opts = {})

Creates a view then returns an rmq with that view in it. It does not add that view to the view tree. This is useful for stuff like creating table cells. You can use the rmq_did_create method, just like you do when you append a subview

Examples:

def tableView(table_view, cellForRowAtIndexPath: index_path)
  cell = tableView.dequeueReusableCellWithIdentifier(CELL_IDENTIFIER) || begin 
    rmq.create(StoreCell, :store_cell, reuse_identifier: CELL_IDENTIFIER)
  end
end

class StoreCell < UITableViewCell 
  def rmq_did_create(self_in_rmq)
    self_in_rmq.append(UILabel, :title_label)
  end
end

Returns:

  • (RMQ)

    wrapping the view that was just create



93
94
95
96
97
98
# File 'motion/ruby_motion_query/subviews.rb', line 93

def create(view_or_constant, style = nil, opts = {})
  # TODO, refactor so that add_subview uses create, not backwards like it is now
  opts[:do_not_add] = true
  opts[:style] = style
  add_subview view_or_constant, opts
end

- (RMQ) create_blank_rmq

This is used internally, to get a new rmq instance, just call "rmq" in your view or controller or just create a new one like so: RubyMotionQuery::RMQ.new

Returns:



7
8
9
# File 'motion/ruby_motion_query/factory.rb', line 7

def create_blank_rmq
  RMQ.create_with_array_and_selectors([], self.selectors, @context)
end

- (RMQ) create_rmq_in_context(*selectors)

This is used internally, to get a new rmq instance, just call "rmq" in your view or controller or just create a new one like so: RubyMotionQuery::RMQ.new

Returns:



15
16
17
# File 'motion/ruby_motion_query/factory.rb', line 15

def create_rmq_in_context(*selectors)
  RMQ.create_with_selectors(selectors, @context)
end

- (RMQ) detect(&block)

Returns:



44
45
46
47
# File 'motion/ruby_motion_query/enumerablish.rb', line 44

def detect(&block) # Unlike enumerable, detect and find are not the same. See find in transverse
  return self unless block
  RMQ.create_with_array_and_selectors(selected.select(&block), @selectors, @context)
end

- (Device) device

Returns:



4
5
6
# File 'motion/ruby_motion_query/device.rb', line 4

def device
  Device
end

- (Object) distribute(type = :vertical, params = {})



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'motion/ruby_motion_query/position.rb', line 40

def distribute(type = :vertical, params = {})
  return 0 if selected.length == 0

  margins = params[:margins]
  margin = params[:margin] || 0
  current_end = nil

  selected.each_with_index do |view, i|
    st = self.styler_for(view)
    next if st.height == 0

    view_margin = if (margins && margins[i])
      margins[i]
    else
      margin
    end

    current_end = (st.top - view_margin) unless current_end

    if type == :horizontal
      st.left = current_end + view_margin
      current_end = st.right
    else
      st.top = current_end + view_margin
      current_end = st.bottom
    end
    
  end

  self
end

- (RMQ) each(&block)

Returns:



25
26
27
28
# File 'motion/ruby_motion_query/enumerablish.rb', line 25

def each(&block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.each(&block), @selectors, @context)
end

- (RMQ) end

Returns The parent rmq instance

Examples:

rmq(test_view).find(UIImageView).tag(:foo).end.find(UILabel).tag(:bar)

Returns:

  • (RMQ)

    The parent rmq instance



93
94
95
# File 'motion/ruby_motion_query/traverse.rb', line 93

def end
  self.parent_rmq || self
end

- (RMQ) filter(opts = {}, &block)

Most everything uses filter to do its work. This is mostly used internally but you can use it too. Just pass a block that returns views, it will be called for every view that is selected

Parameters:

  • return_array

    returns array not rmq: return_array: true

  • uniq

    removes duplicate views: uniq: true

  • limit

    limits the number of views *per selected view*: limit: true

Returns:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'motion/ruby_motion_query/traverse.rb', line 13

def filter(opts = {}, &block)
  out = []
  limit = opts[:limit]

  selected.each do |view|
    results = yield(view)
    unless RMQ.is_blank?(results)
      out << results 
      break if limit && (out.length >= limit)
    end
  end
  out.flatten!
  out.uniq! if opts[:uniq]

  if opts[:return_array]
    out
  else
    RMQ.create_with_array_and_selectors(out, selectors, @context, self)
  end
end

- (RMQ) find(*working_selectors)

Get the descendants of each view in the current set of selected views, filtered by a selector(s)

Examples:

rmq(my_view).find(UIButton).show

Parameters:

  • selectors

Returns:

  • (RMQ)

    Instance selecting the children, grandchildren, etc of the selected view(s)



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'motion/ruby_motion_query/traverse.rb', line 139

def find(*working_selectors)
  normalize_selectors(working_selectors)

  filter(uniq: true) do |view|
    subviews = all_subviews_for(view)

    if RMQ.is_blank?(working_selectors)
      subviews
    else
      subviews.inject([]) do |out, subview|
        out << subview if match(subview, working_selectors)
        out
      end
    end
  end
end

- (RMQ) first

Returns:



69
70
71
# File 'motion/ruby_motion_query/enumerablish.rb', line 69

def first
  RMQ.create_with_array_and_selectors([selected.first], @selectors, @context)
end

- (RMQ) focus Also known as: become_first_responder

Sets the last selected view as the first responder

Examples:

rmq(my_view).next(UITextField).focus

Returns:



32
33
34
35
36
37
# File 'motion/ruby_motion_query/actions.rb', line 32

def focus
  unless RMQ.is_blank?(selected)
    selected.last.becomeFirstResponder
  end
  self
end

- (Font) font

Returns:



9
10
11
# File 'motion/ruby_motion_query/font.rb', line 9

def font
  Font
end

- (Format) format

Returns:



4
5
6
# File 'motion/ruby_motion_query/format.rb', line 4

def format
  Format
end

- (UIView or Array) get

Returns a view or array of views. Normally used to get the only view in selected.

Examples:

# returns my_view
rmq(my_view).get

# returns an array
rmq(UILabel).get

rmq(foo).parent.get.some_method_on_parent

Returns:



137
138
139
140
141
142
143
144
# File 'motion/ruby_motion_query/base.rb', line 137

def get
  sel = self.selected
  if sel.length == 1
    sel.first
  else
    sel
  end
end

- (RMQ) grep(&block)

Returns:



50
51
52
53
# File 'motion/ruby_motion_query/enumerablish.rb', line 50

def grep(&block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.grep(&block), @selectors, @context)
end

- (RMQ) hide

Returns:



41
42
43
44
# File 'motion/ruby_motion_query/actions.rb', line 41

def hide
  selected.each { |view| view.hidden = true }
  self
end

- (ImageUtils) image

Returns:



9
10
11
# File 'motion/ruby_motion_query/image.rb', line 9

def image
  ImageUtils
end

- (RMQ) inject(o, &block) Also known as: reduce

Returns:



62
63
64
65
# File 'motion/ruby_motion_query/enumerablish.rb', line 62

def inject(o, &block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.inject(o, &block), @selectors, @context)
end

- (String) inspect

Changed inspect to be useful

Examples:

(main)> rmq.all
=> RMQ 172658240. 26 selected. selectors: []. .log for more info

Returns:

  • (String)


176
177
178
179
180
# File 'motion/ruby_motion_query/base.rb', line 176

def inspect
  out = "RMQ #{self.object_id}. #{self.count} selected. selectors: #{self.selectors.to_s}. .log for more info"
  out << "\n[#{selected.first}]" if self.count == 1
  out
end

- (RMQ) last

Returns:



73
74
75
# File 'motion/ruby_motion_query/enumerablish.rb', line 73

def last
  RMQ.create_with_array_and_selectors([selected.last], @selectors, @context)
end

- (Integer) length Also known as: size, count

Returns number of views selected

Returns:

  • (Integer)

    number of views selected



83
84
85
# File 'motion/ruby_motion_query/enumerablish.rb', line 83

def length
  selected.length
end

- (Array) location_in(view)

Returns or [CGSize]

Returns:

  • (Array)

    or [CGSize]



98
99
100
101
102
103
104
105
# File 'motion/ruby_motion_query/position.rb', line 98

def location_in(view)
  out = []
  selected.each do |selected_view|
    out << selected_view.convertRect(selected_view.bounds, toView: view).origin
  end
  out = out.first if out.length == 1
  out
end

- (Array) location_in_root_view

Returns or [CGSize]

Returns:

  • (Array)

    or [CGSize]



93
94
95
# File 'motion/ruby_motion_query/position.rb', line 93

def location_in_root_view
  self.location_in(self.root_view)
end

- (String) log(opt = nil)

Super useful in the console. log outputs to the console a table of the selected views

log in a tree form

Examples:

(main)> rmq(UIImageView).log

object_id   | class                 | style_name              | frame                           |
sv id       | superview             | subviews count          | tags                            |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
168150976   | UIImageView           | logo                    | {l: 60, t: 10, w: 200, h: 95.5} |
168128784   | UIView                | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
168180640   | UIImageView           |                         | {l: 1, t: 1, w: 148, h: 19}     |
168173616   | UIRoundedRectButton   | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
168204336   | UIImageView           |                         | {l: 1, t: 0, w: 77, h: 27}      |
168201952   | _UISwitchInternalView | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
172600352   | UIImageView           |                         | {l: -2, t: 0, w: 79, h: 27}     |
168204512   | UIView                | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
168205504   | UIImageView           |                         | {l: -2, t: 0, w: 131, h: 27}    |
168204512   | UIView                | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
168205600   | UIImageView           |                         | {l: 49, t: 0, w: 29, h: 27}     |
168204512   | UIView                | 0                       |                                 |
- - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |
RMQ 278442176. 6 selected. selectors: [UIImageView]#
rmq.log :tree
rmq.all.log :wide

Parameters:

  • :wide

    outputs wide format (really wide, but awesome: rmq.all.log :wide). :tree outputs the

Returns:

  • (String)


220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'motion/ruby_motion_query/base.rb', line 220

def log(opt = nil)
  if opt == :tree
    puts tree_to_s(selected) 
    return
  end

  wide = (opt == :wide)
  out =  "\n object_id   | class                 | style_name              | frame                           |"
  out << "\n" unless wide
  out <<   " sv id       | superview             | subviews count          | tags                            |"
  line =   " - - - - - - | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - |\n"
  out << "\n"
  out << line.chop if wide
  out << line

  selected.each do |view| 
    out << " #{view.object_id.to_s.ljust(12)}|"
    out << " #{view.class.name[0..21].ljust(22)}|"
    out << " #{(view.rmq_data.style_name || '')[0..23].ljust(24)}|"

    s = ""
    if view.origin
      format = '#0.#'
      s = " {l: #{RMQ.format.numeric(view.origin.x, format)}"
      s << ", t: #{RMQ.format.numeric(view.origin.y, format)}"
      s << ", w: #{RMQ.format.numeric(view.size.width, format)}"
      s << ", h: #{RMQ.format.numeric(view.size.height, format)}}"
    end
    out << s.ljust(33)
    out << '|'

    out << "\n" unless wide
    out << " #{view.superview.object_id.to_s.ljust(12)}|"
    out << " #{(view.superview ? view.superview.class.name : '')[0..21].ljust(22)}|"
    out << " #{view.subviews.length.to_s.ljust(23)} |"
    #out << "  #{view.subviews.length.to_s.rjust(8)} #{view.superview.class.name.ljust(20)} #{view.superview.object_id.to_s.rjust(10)}"
    out << " #{view.rmq_data.tag_names.join(',').ljust(32)}|"
    out << "\n"
    out << line unless wide
  end

  out << "RMQ #{self.object_id}. #{self.count} selected. selectors: #{self.selectors.to_s}"

  puts out
end

- (RMQ) map(&block) Also known as: collect

Returns:



31
32
33
34
# File 'motion/ruby_motion_query/enumerablish.rb', line 31

def map(&block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.map(&block), @selectors, @context)
end

- (RMQ) move(opts) Also known as: resize

Returns:



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'motion/ruby_motion_query/position.rb', line 5

def move(opts) 
  # TODO, add centered and from_bottom and from_top, and bottom and top
  # TODO, add animate option
  left = opts[:left] || opts[:l] || opts[:x]
  top = opts[:top] || opts[:t] || opts[:y]
  width = opts[:width] || opts[:w]
  height = opts[:height] || opts[:h]

  selected.each do |view|
    view.frame = [
      [left || view.origin.x, top || view.origin.y],
      [width || view.size.width, height || view.size.height]
    ]
  end

  self
end

- (RMQ) next(*working_selectors)

Returns Sibling above to the selected view(s)

Examples:

rmq(my_view).next(UITextField).focus

Parameters:

  • selectors

Returns:

  • (RMQ)

    Sibling above to the selected view(s)



200
201
202
203
204
205
206
207
208
209
210
# File 'motion/ruby_motion_query/traverse.rb', line 200

def next(*working_selectors)
  normalize_selectors(working_selectors)

  filter do |view|
    subs = view.superview.subviews
    location = subs.index(view)
    if location < subs.length - 1
      subs[location + 1]
    end
  end
end

- (RMQ) not(*working_selectors)

Returns A new rmq instance removing selected views that match selectors provided

Examples:

# Entire family of labels from siblings on down
rmq(my_label).parent.find(UILabel).not(my_label).move(left: 10)

Parameters:

  • selectors

Returns:

  • (RMQ)

    A new rmq instance removing selected views that match selectors provided



64
65
66
67
68
69
70
71
# File 'motion/ruby_motion_query/traverse.rb', line 64

def not(*working_selectors)
  return self unless working_selectors
  normalize_selectors(working_selectors)

  self.reject do |view|
    match(view, working_selectors)
  end
end

- (RMQ) nudge(opts)

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'motion/ruby_motion_query/position.rb', line 25

def nudge(opts) 
  left = opts[:left] || opts[:l] || 0
  right = opts[:right] || opts[:r] || 0
  up = opts[:up] || opts[:u] || 0
  down = opts[:down] || opts[:d] || 0

  selected.each do |view|
    f = view.frame
    f.origin = [view.origin.x - left + right, view.origin.y + down - up]
    view.frame = f
  end

  self
end

- (RMQ) off(*events)

Removes events/gestures from all views selected

Returns:



94
95
96
97
98
99
100
# File 'motion/ruby_motion_query/events.rb', line 94

def off(*events)
  selected.each do |view|
    events(view).off(events)
  end

  self
end

- (Object) on(event, args = {}, &block)

Options for gestures

:cancels_touches_in_view 
:delegate 
:taps_required 
:fingers_required 
:maximum_number_of_touches 
:minimum_number_of_touches 
:allowable_movement 
:minimum_press_duration 
:direction 
:rotation 
:scale

rmq.append(UIButton).on(:touch) do |sender|

# Do something when button is touched

end

rmq(my_view).on(:tap, taps_required: 2 ) do |sender, event|

# Do something when event fires

end

# These both are the same rmq(button).on(:tap, init: ->(recongnizer){recongnizer.numberOfTapsRequired = 2) do |sender|

puts 'tapped'

end

rmq(button).on(:tap, taps_required: 2) do |sender|

puts 'tapped'

end



83
84
85
86
87
88
89
# File 'motion/ruby_motion_query/events.rb', line 83

def on(event, args = {}, &block)
  selected.each do |view|
    events(view).on(view, event, args, &block) 
  end

  self
end

- (Array) origin_views

The view(s) this rmq was derived from

Returns:

  • (Array)


116
117
118
119
120
121
122
# File 'motion/ruby_motion_query/base.rb', line 116

def origin_views
  if pq = self.parent_rmq
    pq.selected
  else
    [self.view_controller.view]
  end
end

- (RMQ) parent Also known as: superview

Returns rmq instance selecting the parent of the selected view(s)

Examples:

rmq(my_view).parent.find(:delete_button).toggle_enabled

Returns:

  • (RMQ)

    rmq instance selecting the parent of the selected view(s)



101
102
103
# File 'motion/ruby_motion_query/traverse.rb', line 101

def parent
  closest(UIView)
end

- (RMQ) parent_rmq

Untested and I don' think it's getting set right in some situations

Returns:

  • (RMQ)

    rmq that created this rmq, if any



106
107
108
# File 'motion/ruby_motion_query/base.rb', line 106

def parent_rmq
  @_parent_rmq
end

- (Object) parent_rmq=(value)



109
110
111
# File 'motion/ruby_motion_query/base.rb', line 109

def parent_rmq=(value)
  @_parent_rmq = value
end

- (RMQ) parents(*working_selectors) Also known as: superviews

of the selected view(s)

Examples:

rmq(my_view).parents.log

Parameters:

  • selectors

Returns:

  • (RMQ)

    Instance selecting the parents, grandparents, etc, all the way up the tree



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'motion/ruby_motion_query/traverse.rb', line 113

def parents(*working_selectors)
  normalize_selectors(working_selectors)

  filter(uniq: true) do |view|
    superviews = all_superviews_for(view)

    if RMQ.is_blank?(working_selectors)
      superviews
    else
      superviews.inject([]) do |subview, out|
        out << subview if match(subview, working_selectors)
        out
      end
    end
  end
end

- (RMQ) prev(*working_selectors)

Returns Sibling below to the selected view(s)

Examples:

rmq(my_view).prev(UITextField).focus

Parameters:

  • selectors

Returns:

  • (RMQ)

    Sibling below to the selected view(s)



218
219
220
221
222
223
224
225
226
227
228
# File 'motion/ruby_motion_query/traverse.rb', line 218

def prev(*working_selectors)
  normalize_selectors(working_selectors)

  filter do |view|
    subs = view.superview.subviews
    location = subs.index(view)
    if location > 0
      subs[location - 1]
    end
  end
end

- (RMQ) reapply_styles

Returns:



45
46
47
48
49
50
51
52
# File 'motion/ruby_motion_query/stylesheet.rb', line 45

def reapply_styles
  selected.each do |selected_view|
    if style_name = selected_view.rmq_data.style_name
      apply_style_to_view selected_view, style_name
    end
  end
  self
end

- (RMQ) reject(&block)

Returns:



56
57
58
59
# File 'motion/ruby_motion_query/enumerablish.rb', line 56

def reject(&block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.reject(&block), @selectors, @context)
end

- (RMQ) remove

Returns:



6
7
8
9
# File 'motion/ruby_motion_query/subviews.rb', line 6

def remove
  selected.each { |view| view.removeFromSuperview }
  self
end

- (Object) resize_to_fit_subviews



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'motion/ruby_motion_query/position.rb', line 72

def resize_to_fit_subviews
  selected.each do |view|
    st = self.styler_for(view)

    w = 0
    h = 0

    view.subviews.each do |subview|
      sub_st = self.styler_for(subview)
      w = [sub_st.right, w].max
      h = [sub_st.bottom, h].max
    end

    st.width = w if st.width < w
    st.height = h if st.height < h
  end

  self
end

- (Boolean) root?

Is this rmq a root instance?

Which means it only has 1 selected view, and that view is the view you called rmq in. Which is a tad confusing, but if you call just rmq inside a view, then only that view will be selected and this rmq will be root. If you call rmq inside a controller, only controller.view will be selected and the rma instance will be a root.

Returns:

  • (Boolean)


152
153
154
# File 'motion/ruby_motion_query/base.rb', line 152

def root?
  (selected.length == 1) && (selected.first == @context)
end

- (UIView) root_view

Returns Root view of this rmq instance’s controller

Examples:

rmq.root_view

Returns:

  • (UIView)

    Root view of this rmq instance’s controller



296
297
298
299
300
301
302
303
# File 'motion/ruby_motion_query/traverse.rb', line 296

def root_view
  vc = self.view_controller
  if RMQ.is_blank?(vc)
    self.context_or_context_view
  else
    self.view_controller.view
  end
end

- (RMQ) select(&block)

Returns:



38
39
40
41
# File 'motion/ruby_motion_query/enumerablish.rb', line 38

def select(&block)
  return self unless block
  RMQ.create_with_array_and_selectors(selected.select(&block), @selectors, @context)
end

- (Array) selected

The UIViews currently selected

Use #get instead to get the actual UIView objects

Returns:

  • (Array)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'motion/ruby_motion_query/base.rb', line 53

def selected
  if @selected_dirty
    @_selected = []

    if RMQ.is_blank?(self.selectors)
      @_selected << context_or_context_view
    else
      working_selectors = self.selectors.dup
      extract_views_from_selectors(@_selected, working_selectors)

      unless RMQ.is_blank?(working_selectors)
        subviews = all_subviews_for(root_view)
        subviews.each do |subview|
          @_selected  << subview if match(subview, working_selectors)
        end
      end

      @_selected.uniq!
    end

    @selected_dirty = false
  else
    @_selected ||= []
  end

  @_selected
end

- (Object) selected=(value)

Do not use



43
44
45
46
# File 'motion/ruby_motion_query/base.rb', line 43

def selected=(value)
  @_selected = value
  @selected_dirty = false
end

- (Array) selectors

Returns The selectors, which is what you used for the query

Examples:

(main)> rmq(UILabel, UIImageView).selectors
=> [UILabel, UIImageView] 

Returns:

  • (Array)

    The selectors, which is what you used for the query



15
16
17
# File 'motion/ruby_motion_query/selectors.rb', line 15

def selectors
  @_selectors
end

- (Object) selectors=(value)

Do not use



5
6
7
8
9
# File 'motion/ruby_motion_query/selectors.rb', line 5

def selectors=(value)
  @selected_dirty = true
  normalize_selectors(value)
  @_selectors = value
end

- (RMQ) send(method, args = nil)

Returns:



15
16
17
18
19
20
21
22
23
24
# File 'motion/ruby_motion_query/actions.rb', line 15

def send(method, args = nil)
  selected.each do |view|
    if args
      view.__send__ method, args
    else
      view.__send__ method
    end
  end
  self
end

- (RMQ) show

Returns:



47
48
49
50
# File 'motion/ruby_motion_query/actions.rb', line 47

def show
  selected.each { |view| view.hidden = false }
  self
end

- (RMQ) siblings(*working_selectors)

Returns Siblings of the selected view(s)

Examples:

rmq(my_view).siblings.send(:poke)

Parameters:

  • selectors

Returns:

  • (RMQ)

    Siblings of the selected view(s)



187
188
189
190
191
# File 'motion/ruby_motion_query/traverse.rb', line 187

def siblings(*working_selectors)
  normalize_selectors(working_selectors)

  self.parent.children.not(selected)
end

- (RMQ) style

Returns:



37
38
39
40
41
42
# File 'motion/ruby_motion_query/stylesheet.rb', line 37

def style()
  selected.each do |view|
    yield(styler_for(view))
  end
  self
end

- (Object) styler_for(view)



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'motion/ruby_motion_query/stylesheet.rb', line 54

def styler_for(view)
  # TODO should have a pool of stylers to reuse, or just assume single threaded and 
  # memoize this, however if you do that, make sure the dev doesn't retain them in a var
  custom_stylers(view) || begin
    case view
    when UILabel              then Stylers::UILabelStyler.new(view)
    when UIButton             then Stylers::UIButtonStyler.new(view)
    when UIImageView          then Stylers::UIImageViewStyler.new(view)
    when UITableView          then Stylers::UITableViewStyler.new(view)
    when UISwitch             then Stylers::UISwitchStyler.new(view)
    when UIDatePicker         then Stylers::UIDatePickerStyler.new(view)
    when UISegmentedControl   then Stylers::UISegmentedControlStyler.new(view)
    when UIRefreshControl     then Stylers::UIRefreshControlStyler.new(view)
    when UIPageControl        then Stylers::UIPageControlStyler.new(view)
    when UISlider             then Stylers::UISliderStyler.new(view)
    when UIStepper            then Stylers::UIStepperStyler.new(view)
    when UITabBar             then Stylers::UITabBarStyler.new(view)
    when UITableViewCell      then Stylers::UITableViewCellStyler.new(view)
    when UITextView           then Stylers::UITextViewStyler.new(view)
    when UITextField          then Stylers::UITextFieldStyler.new(view)
    when UINavigationBar      then Stylers::UINavigationBarStyler.new(view)
    when UIScrollView         then Stylers::UIScrollViewStyler.new(view)
    # TODO, all the controls are done, but missing some views, add
    when UIControl            then Stylers::UIControlStyler.new(view)
    else
      Stylers::UIViewStyler.new(view)
    end
  end
end

- (RubyMotionQuery::Stylesheet) stylesheet



17
18
19
20
21
22
23
24
25
26
# File 'motion/ruby_motion_query/stylesheet.rb', line 17

def stylesheet
  @_stylesheet ||= begin

    if self.view_controller && (ss = self.view_controller.rmq_data.stylesheet)
      ss
    elsif (prmq = self.parent_rmq) && prmq.stylesheet
      prmq.stylesheet
    end
  end
end

- (RMQ) stylesheet=(value)

Returns:



5
6
7
8
9
10
11
12
13
14
# File 'motion/ruby_motion_query/stylesheet.rb', line 5

def stylesheet=(value)
  controller = self.view_controller

  unless value.is_a?(RubyMotionQuery::Stylesheet)
    value = value.new(controller)
  end
  @_stylesheet = value
  controller.rmq_data.stylesheet = value
  self
end

- (RMQ) tag(*tag_or_tags)

Add tags You can optionally store a value in the tag, which can be super useful in some rare situations

Examples:

rmq(my_view).tag(:your_tag)
rmq(my_view).clear_tags.tag(:your_new_tag)
rmq(my_view).find(UILabel).tag(:selected, :customer)
rmq(my_view).tag(your_tag: 22)
rmq(my_view).tag(your_tag: 22, your_other_tag: 'Hello world')

Returns:



16
17
18
19
20
21
# File 'motion/ruby_motion_query/tags.rb', line 16

def tag(*tag_or_tags)
  selected.each do |view|
    view.rmq_data.tag(tag_or_tags)
  end
  self
end

- (Array) to_a

Returns:

  • (Array)


78
79
80
# File 'motion/ruby_motion_query/enumerablish.rb', line 78

def to_a
  selected
end

- (RMQ) toggle

Returns:



53
54
55
56
# File 'motion/ruby_motion_query/actions.rb', line 53

def toggle
  selected.each { |view| view.hidden = !view.hidden? }
  self
end

- (RMQ) toggle_enabled

Returns:



59
60
61
62
# File 'motion/ruby_motion_query/actions.rb', line 59

def toggle_enabled
  selected.each { |view| view.enabled = !view.enabled? }
  self
end

- (Object) tree_to_s(selected_views, depth = 0)



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'motion/ruby_motion_query/base.rb', line 266

def tree_to_s(selected_views, depth = 0)
  out = ""

  selected_views.each do |view| 
    first = (view == selected_views.first)
    last = (view == selected_views.last)

    if depth == 0
      out << "\n"
    else
      0.upto(depth - 1).each do |i|
        out << (i == (depth - 1) ? '' : '')
      end
    end

    out << '───'

    out << " #{view.class.name[0..21]}"
    out << "  ( #{view.rmq_data.style_name[0..23]} )" if view.rmq_data.style_name
    out << "  #{view.object_id.to_s}"
    out << "  [ #{view.rmq_data.tag_names.join(',')} ]" if view.rmq_data.tag_names.length > 0

    if view.origin
      format = '#0.#'
      s = "  {l: #{RMQ.format.numeric(view.origin.x, format)}"
      s << ", t: #{RMQ.format.numeric(view.origin.y, format)}"
      s << ", w: #{RMQ.format.numeric(view.size.width, format)}"
      s << ", h: #{RMQ.format.numeric(view.size.height, format)}}"
      out << s
    end

    out << "\n"
    out << tree_to_s(view.subviews, depth + 1)
  end

  out
end

- (RMQ) unshift(view_or_constant, style = nil, opts = {}) Also known as: prepend

Returns:



67
68
69
70
71
# File 'motion/ruby_motion_query/subviews.rb', line 67

def unshift(view_or_constant, style=nil, opts = {})
  opts[:at_index] = 0
  opts[:style] = style
  add_subview view_or_constant, opts
end

- (Object) version



5
6
7
# File 'motion/ruby_motion_query/version.rb', line 5

def version
  RubyMotionQuery::VERSION
end

- (UIViewController) view_controller

When you call rmq within a controller or view, a new instance of RMQ is created with the selectors you may or may not have supplied. That instance will determine what view_controller it should use for stuff like traversing, stylesheet, etc.

  • rmq method called in a controller: that controller is used

  • rmq method called in a view and that view is within the subview tree of a controller: that controller is used

  • rmq method called in a view and that view is NOT within any subview tree of any controller (common in a UITableViewCell for example). In this case it will use the view's controller or the "current controller". Generally that is what is desired, however there are some situations where another controller should be used. In that situation create your own rmq instance and assign the controller you'd rather use

  • if an rmq instance was created from another rmq instance, it will attempt to the parent_rmq's controller, if it exists

Examples:

rmq(my_view).view_controller

Returns:



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'motion/ruby_motion_query/traverse.rb', line 267

def view_controller
  if @_view_controller
    @_view_controller
  else
    if @context.is_a?(UIViewController)
      @context
    else # view
      vc = RMQ.controller_for_view(@context) ||
        (self.parent_rmq && self.parent_rmq.view_controller) ||
        RMQ.app.current_view_controller

      self.view_controller = vc
      @context.rmq_data.view_controller = @_view_controller if @context

      @_view_controller
    end
  end
end

- (Object) view_controller=(value)



285
286
287
# File 'motion/ruby_motion_query/traverse.rb', line 285

def view_controller=(value)
  @_view_controller = RubyMotionQuery::RMQ.weak_ref(value)
end

- (Object) weak_view_controller=(value)



288
289
290
# File 'motion/ruby_motion_query/traverse.rb', line 288

def weak_view_controller=(value)
  @_view_controller = value
end

- (UIWindow) window

Returns Window of the root_view

Examples:

rmq.window

Returns:

  • (UIWindow)

    Window of the root_view



309
310
311
# File 'motion/ruby_motion_query/traverse.rb', line 309

def window
  self.root_view.window
end

- (Object) wrap(*views)

Wraps 1 or more views in an rmq instance.

Normally you select a view or views using rmq(my_view). Which doesn't work if you have an instance of a RMQ, in which case it isn't a method. In some cases you want to save an instance of rmq and use it like the rmq method, for this you'd use #wrap

Examples:

q = RubyMotionQuery::RMQ.new

# Bad
q(my_view).view_controller 

# Good
q.wrap(my_view).view_controller


96
97
98
99
100
# File 'motion/ruby_motion_query/base.rb', line 96

def wrap(*views)
  views.flatten!
  views.select!{ |v| v.is_a?(UIView) }
  RMQ.create_with_array_and_selectors(views, views, views.first, self)
end