diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..afae923 --- /dev/null +++ b/.yardopts @@ -0,0 +1 @@ +motion/**/*.rb diff --git a/README.md b/README.md index eb66870..7634376 100755 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ ![RQM logo](http://ir_wp.s3.amazonaws.com/wp-content/uploads/sites/9/2013/07/rmq_logo.png) -RubyMotionQuery - RMQ - A small, light, muggle, nonpolluting, jQuery-like library for [RubyMotion](http://rubymotion.com). +# RubyMotionQuery - RMQ +A light, muggle, nonpolluting, jQuery-like library for [RubyMotion](http://rubymotion.com). -#### The [RMQ Introductory Guide and other info][1] is a great place to start. - ----------- +**The [RMQ Introductory Guide and other info][1] is a great place to start.** [![Dependency Status](https://gemnasium.com/infinitered/rmq.png)](https://gemnasium.com/infinitered/rmq) [![Build Status](https://travis-ci.org/infinitered/rmq.png?branch=master)](https://travis-ci.org/infinitered/rmq) ----------- -#### Some of the very cool features: +## General + +### Some of the very cool features: - **selecting** (*querying*) views - **traversal** through view hierarchy (moving around the tree) - tagging @@ -24,7 +24,13 @@ RubyMotionQuery - RMQ - A small, light, muggle, nonpolluting, jQuery-like librar - app - device -#### Other wrapper libraries +---------- + +**Tested only on iOS only, not OS X (nor is there any OS X specific code)** + +---------- + +### Other wrapper libraries There are a lot of great wrappers out there such as Teacup and Sugarcube. I've used these and I enjoy them. However, many of the wrappers heavily pollute the standard classes, which is great if you like that sort of thing. RMQ is designed to have minimal pollution, to be very simple and high performance (it will be when it's done). RMQ shouldn't conflict with anything. RMQ **doesn't require any** other wrapper or gem. @@ -33,19 +39,6 @@ RMQ **doesn't require any** other wrapper or gem. Some of the code in RMQ came from BubbleWrap and Sugarcube. Not too much but some did. I thank you BubbleWrap and Sugarcube teams for your work. ----------- - -### * Alpha * Warning * - -This is in the **alpha** stage right now, it works well and we've used some of RMQ in production apps, but it **needs** more **testing**, **performance** optimizations, **documentation**, and the **TODOs** to be finished. - -RDocs are not done. I'd appreciate help on these. This readme isn't up to the quality I'd like either. I figure it's better to get it out to the community sooner rather than wait for it to be more finished. My ideal is jQuery quality docs in addition to basic RDoc reference. - -Somethings still need to be optimized for speed - -Tested only on iOS, not OS X (nor is there any OS X specific code) - ----------- ## Installation @@ -59,7 +52,6 @@ or add it to your `Gemfile`: - `gem 'ruby_motion_query'` - ## Usage ### Example App diff --git a/motion/ruby_motion_query/base.rb b/motion/ruby_motion_query/base.rb index 02277d8..3ca2338 100644 --- a/motion/ruby_motion_query/base.rb +++ b/motion/ruby_motion_query/base.rb @@ -1,4 +1,20 @@ module RubyMotionQuery + + # 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 RMQ attr_accessor :context, :parent_rmq @@ -6,10 +22,14 @@ module RubyMotionQuery @selected_dirty = true end + # Do not use def selected=(value) @_selected = value @selected_dirty = false end + + # The UIViews currently selected + # Use {#get} instead to get the actual UIView objects def selected if @selected_dirty @_selected = [] @@ -51,7 +71,13 @@ module RubyMotionQuery # Normally used to get the only view in selected. # # @example - # rmq(foo).parent.get.some_method_on_parent + # # returns my_view + # rmq(my_view).get + # + # # returns an array + # rmq(UILabel).get + # + # rmq(foo).parent.get.some_method_on_parent def get sel = self.selected if sel.length == 1 @@ -61,10 +87,17 @@ module RubyMotionQuery end end + # 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. def root? (selected.length == 1) && (selected.first == @context) end + # 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. + # @return the controller's view or the view you are in when calling rmq def context_or_context_view if @context.is_a?(UIViewController) @context.view @@ -73,45 +106,43 @@ module RubyMotionQuery end end - def extract_views_from_selectors(view_container, working_selectors) - unless RMQ.is_blank?(working_selectors) - working_selectors.each do |selector| - if selector.is_a?(UIView) - view_container << working_selectors.delete(selector) - end - end - end - [view_container, working_selectors] - end - - def all_subviews_for(view) - # TODO maybe cache this, and invalidate cache properly - out = [] - if view.subviews - view.subviews.each do |subview| - out << subview - out << all_subviews_for(subview) - end - out.flatten! - end - - out - end - - def all_superviews_for(view, out = []) - if (nr = view.nextResponder) && nr.is_a?(UIView) - out << nr - all_superviews_for(nr, out) - end - out - end - + # Changed inspect to be useful + # @example + # (main)> rmq.all + # => RMQ 172658240. 26 selected. selectors: []. .log for more info 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 + # Super useful in the console. log outputs to the console a table of the selected views + # @param :wide outputs wide format (really wide, but awesome: rmq.all.log :wide) + # @example + # (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]# def log(opt = nil) wide = (opt == :wide) out = "\n object_id | class | style_name | frame |" @@ -157,5 +188,40 @@ module RubyMotionQuery attr_accessor :cache_controller_rmqs @cache_controller_rmqs = true end + + protected + def extract_views_from_selectors(view_container, working_selectors) + unless RMQ.is_blank?(working_selectors) + working_selectors.each do |selector| + if selector.is_a?(UIView) + view_container << working_selectors.delete(selector) + end + end + end + [view_container, working_selectors] + end + + def all_subviews_for(view) + # TODO maybe cache this, and invalidate cache properly + out = [] + if view.subviews + view.subviews.each do |subview| + out << subview + out << all_subviews_for(subview) + end + out.flatten! + end + + out + end + + def all_superviews_for(view, out = []) + if (nr = view.nextResponder) && nr.is_a?(UIView) + out << nr + all_superviews_for(nr, out) + end + out + end + end end diff --git a/motion/ruby_motion_query/color.rb b/motion/ruby_motion_query/color.rb index f973052..38ec4bb 100644 --- a/motion/ruby_motion_query/color.rb +++ b/motion/ruby_motion_query/color.rb @@ -9,6 +9,32 @@ module RubyMotionQuery end end + # @example + # # Standard colors: + # + # color.clear + # color.white + # color.light_gray + # color.gray + # color.dark_gray + # color.black + # + # color.red + # color.green + # color.blue + # color.yellow + # color.orange + # color.purple + # color.brown + # color.cyan + # color.magenta + # + # color.table_view + # color.scroll_view + # color.flipside + # color.under_page + # color.light_text + # color.dark_text class Color < UIColor class << self @@ -36,6 +62,7 @@ module RubyMotionQuery alias :light_text :lightTextColor alias :dark_text :darkTextColor + # Add your own standard color def add_named(key, hex_or_color) color = if hex_or_color.is_a?(String) Color.from_hex(hex_or_color) @@ -49,6 +76,12 @@ module RubyMotionQuery end # Thanks bubblewrap for this method + # + # @param hex with or without the # + # @return UIColor + # @example + # color.from_hex('#ffffff') + # color.from_hex('ffffff') def from_hex(hex_color) hex_color.gsub!("#", "") case hex_color.size diff --git a/motion/ruby_motion_query/image.rb b/motion/ruby_motion_query/image.rb index 435ef3f..561a204 100644 --- a/motion/ruby_motion_query/image.rb +++ b/motion/ruby_motion_query/image.rb @@ -37,7 +37,7 @@ module RubyMotionQuery image.resizableImageWithCapInsets([opts[:top], opts[:left], opts[:bottom], opts[:right]], resizingMode: UIImageResizingModeStretch) end - # [FROM Sugarcube, thanks Sugarcube] + # Note: FROM Sugarcube, thanks Sugarcube # # Easily take a snapshot of a `UIView`. # diff --git a/motion/ruby_motion_query/position.rb b/motion/ruby_motion_query/position.rb index d89ef51..cf7b9ab 100644 --- a/motion/ruby_motion_query/position.rb +++ b/motion/ruby_motion_query/position.rb @@ -20,11 +20,11 @@ module RubyMotionQuery end alias :resize :move - def align(direction) - # TODO - # rmq(UILabel).align(:left) - # rmq(UILabel).align(:left, :top) - end + #def align(direction) + ## TODO + ## rmq(UILabel).align(:left) + ## rmq(UILabel).align(:left, :top) + #end def nudge(opts) left = opts[:left] || opts[:l] || 0 diff --git a/motion/ruby_motion_query/selectors.rb b/motion/ruby_motion_query/selectors.rb index 6133d55..b0f8b46 100644 --- a/motion/ruby_motion_query/selectors.rb +++ b/motion/ruby_motion_query/selectors.rb @@ -1,15 +1,24 @@ module RubyMotionQuery class RMQ + # Do not use def selectors=(value) @selected_dirty = true normalize_selectors(value) @_selectors = value end + + # @return the selectors, which is what you used for the query + # @example + # (main)> rmq(UILabel, UIImageView).selectors + # => [UILabel, UIImageView] def selectors @_selectors end + + protected + def match_context(new_selectors) match(context_or_context_view, new_selectors) end diff --git a/motion/ruby_motion_query/traverse.rb b/motion/ruby_motion_query/traverse.rb index b29f2b5..6bbe43d 100644 --- a/motion/ruby_motion_query/traverse.rb +++ b/motion/ruby_motion_query/traverse.rb @@ -1,7 +1,13 @@ module RubyMotionQuery class RMQ - # Most everthing uses filter to do its work + # 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* + # + # @param return_array returns array not rmq: return_array: true + # @param uniq removes duplicate views: uniq: true + # @param limit limits the number of views *per selected view*: limit: true def filter(opts = {}, &block) out = [] limit = opts[:limit] @@ -25,10 +31,14 @@ module RubyMotionQuery end end + # @return all selected views def all self.view_controller.rmq.find end + # @return a new rmq instance reducing selected views to those that match selectors provided + # + # @param selectors def and(*working_selectors) return self unless working_selectors normalize_selectors(working_selectors) @@ -38,6 +48,9 @@ module RubyMotionQuery end end + # @return a new rmq instance removing selected views that match selectors provided + # + # @param selectors def not(*working_selectors) return self unless working_selectors normalize_selectors(working_selectors) @@ -47,6 +60,7 @@ module RubyMotionQuery end end + # @return a new rmq instance adding the context to the selected views def and_self if @parent_rmq out = @parent_rmq.selected.dup @@ -59,15 +73,23 @@ module RubyMotionQuery end alias :add_self :and_self + # @return the parent rmq instance + # + # @example + # rmq(test_view).find(UIImageView).tag(:foo).end.find(UILabel).tag(:bar) def end @parent_rmq || self end + # @return rmq instance selecting the parent of the selected view(s) def parent closest(UIView) end alias :superview :parent + # @return rmq instance selecting the parents, grandparents, etc of the selected view(s) + # + # @param selectors def parents(*working_selectors) normalize_selectors(working_selectors) @@ -86,6 +108,11 @@ module RubyMotionQuery end alias :superviews :parents + # Get the descendants of each view in the current set of selected views, filtered by a selector(s) + # + # @return rmq instance selecting the children, grandchildren, etc of the selected view(s) + # + # @param selectors def find(*working_selectors) normalize_selectors(working_selectors) @@ -103,6 +130,9 @@ module RubyMotionQuery end end + # @return rmq instance selecting the children of the selected view(s) + # + # @param selectors def children(*working_selectors) normalize_selectors(working_selectors) @@ -121,12 +151,20 @@ module RubyMotionQuery end alias :subviews :children + + # @return rmq instance selecting the siblings of the selected view(s) + # + # @param selectors def siblings(*working_selectors) normalize_selectors(working_selectors) self.parent.children.not(selected) end + + # @return rmq instance selecting the sibling above to the selected view(s) + # + # @param selectors def next(*working_selectors) normalize_selectors(working_selectors) @@ -139,6 +177,9 @@ module RubyMotionQuery end end + # @return rmq instance selecting the sibling below to the selected view(s) + # + # @param selectors def prev(*working_selectors) normalize_selectors(working_selectors) @@ -151,6 +192,12 @@ module RubyMotionQuery end end + # For each view in the set, get the first view that matches the selector by testing the view itself and + # traversing up through its ancestors in the tree + # + # @return rmq instance selecting the first parent or grandparent or ancestor up the tree of the selected view(s) + # + # @param selectors def closest(*working_selectors) normalize_selectors(working_selectors) @@ -159,6 +206,7 @@ module RubyMotionQuery end end + # @return UIViewController of this rmq instance def view_controller @_view_controller ||= begin if @context.is_a?(UIViewController) @@ -169,6 +217,7 @@ module RubyMotionQuery end end + # @return UIView of this rmq instance's controller def root_view vc = self.view_controller if RMQ.is_blank?(vc) diff --git a/motion/ruby_motion_query/utils.rb b/motion/ruby_motion_query/utils.rb index 6ce6436..570126b 100644 --- a/motion/ruby_motion_query/utils.rb +++ b/motion/ruby_motion_query/utils.rb @@ -20,9 +20,8 @@ module RubyMotionQuery end end - - # Given a UIView, returns the UIViewController it is sitting in, or nil if it's not - # sitting anywhere in particular + # @param view + # @returns the UIViewController it is sitting in, or nil if it's not sitting anywhere in particular def controller_for_view(view) # Non-recursive for speed while view