As I warned, I'm removing most of the "CoreGraphics" module from SugarCube as of v0.12. The features it provides are duplicated by Clay Allsopp's geomotion gem (we worked together to bring the best of SugarCube's features into it).

WHAT'S OUT

These classes are leaving, never to be seen again:

Rect
Size
Point
EdgeInsets
Offset

BUT the METHOD versions are STAYING! WHY!? Because I like them! See more below.

These classes extended Array so that you could assign them to rect.frame, but they also implemented all the .x/.width/.size/.top methods so that you could treat them like either a Struct or an Array. An unholy marriage...

In geomotion, you work with the UIKit classes directly: CGRect and friends. geomotion extends those classes to make them more palatable.

The following methods are going away (unless there is major objection). They convert to/from hash and string. geomotion does not include them.

CGRect
  from_hash
  to_hash
  from_s
  to_s
CGPoint
  from_hash
  to_hash
  from_s
  to_s
CGSize
  from_hash
  to_hash
  from_s
  to_s

WHAT'S IN

All the methods that were added to the CGRect/CGSize/CGPoint classes remain, though some have changed names.

point.inside?(rect) (was 'intersects?') => CGRectContainsPoint(rect, point)
point == other_point => CGPointEqualToPoint(point, other_point)
point + size  => rect, aka point.rect_of_size(size)
point + other_point => vector addition
point - other_point => same as point + (-other_point)
-point => {x: -point.x, y: -point.y}

CGSize.infinite => creates a size of infinite extent
size.infinite? => test for infinite extent
CGSize.empty => creates a size of [0, 0], aka CGSizeZero
size.empty? => CGSizeEqualToSize(size, CGSize.empty)
size == other_size => CGSizeEqualToSize(size, other_size)
size + point => rect, aka size.rect_at_point(point)
size + other_size => adds the widths and heights

CGRect.infinite  => a rect of infinite extent.  All points should be contained in this rect
CGRect.null  => a rect of zero size that exists at infinity - no point should be contained by this rect
CGRect.empty => an empty rect, at [0, 0]

rect.intersection_with(other_rect) => CGRectIntersection(rect, other_rect) (was rect.intersection)
rect.intersects?(other_rect) => CGRectIntersectsRect(rect, other_rect)
rect.contains?(other_rect) => CGRectContainsRect(rect, other_rect)
rect.contains?(point) => CGRectContainsPoint(rect, point)  (rect.intersects?(point) used to be okay, too - no longer the case)
rect == other_rect => CGRectEqualToRect(rect, other_rect)
rect + other_rect => CGRectUnion(rect, other_rect)  (aka rect.union_with(other_rect))
rect + point => CGRectOffset(rect, point.x, point.y)
rect + offset (UIOffset) => CGRectOffset(rect, offset.horizontal, offset.vertical)
rect + size => increases the size of the rect by size.width and size.height
(this used to use CGRectInset - see rect.grow, rect.shrink)
rect + insets => UIEdgeInsetsInsetRect(rect, insets)

# does CGRectInset *grow* or *shrink* a rect?  use these methods instead of
# remembering the answer:
rect.grow(size) => CGRectInset(rect, -size.width, -size.height)
rect.shrink(size) => CGRectInset(rect, size.width, size.height)

rect.min_y => top of the rect (was rect.top)
rect.max_y => bottom of the rect (was rect.bottom)
rect.min_x => left side of the rect (was rect.left)
rect.max_x => right side of the rect (was rect.right)
rect.width => this width will always be positive (even if rect.size.width is negative)
rect.height => this height will always be positive (even if rect.size.height is negative)

The reason for these last few name changes is because geomotion has lots of rect-creation helpers, and the left and right methods were already taken. It made more sense to rename all the methods to (min|max)_(x|y) instead of having top/bottom/min_x/max_x.

I love these methods too much...

Rather than clutter geomotion's make factory methods (CGRect.make, CGPoint.make, etc.) with these, I'm leaving them in SugarCube::CoreGraphics.

Rect(), Point(), Size(), Offset() and EdgeInsets() accept pretty much ANYTHING and spit out the CG/UI version.

For instance, the Rect() method:

# four args:
Rect(0, 0, 100, 100) => CGRect.new([0, 0], [100, 100])

# two args:
Rect([0, 0], [100, 100]) => CGRect.new([0, 0], [100, 100])
Rect(CGPoint.new(0, 0), CGSize.new(100, 100)) => CGRect.new([0, 0], [100, 100])

# three args!?
Rect(CGPoint.new(0, 0), 100, 100) => CGRect.new([0, 0], [100, 100])
Rect([0, 0], 100, 100) => CGRect.new([0, 0], [100, 100])
Rect(0, 0, CGSize.new(100, 100)) => CGRect.new([0, 0], [100, 100])
Rect(0, 0, [100, 100]) => CGRect.new([0, 0], [100, 100])

# one arg
Rect(CGRect.new([0, 0], [100, 100]) => CGRect.new([0, 0], [100, 100])
Rect([[0, 0], [100, 100]]) => CGRect.new([0, 0], [100, 100])

...and so on for the other types. These are really sugary, because they take any number of arguments and always return a CGRect (or whatever). The REASON this is so helpful is because RubyMotion is very cavalier about arrays and structures. If your method accepts a "CGPoint-like value", wrap it in Point() and treat it like a point.

Believe it or not

These helper methods are now TESTED.

The month of SugarCube tests begins TODAY. Please contact me to help out! It basically consists of setting up an app that uses all this stuff and making sure the methods do what we think they will. Some will be easier than others, of course...