Differences since v0.13


SugarCube is slowly but surely growing it's test folder. If you follow sugarcube on twitter (@sugarcube_rb) I post the output of rake spec now and then, though I just found out that the twitter commandline tool I've been using has been grossly negligent in posting so far.

As of now: 249 specifications (1065 requirements), 0 failures, 0 errors

The Usual Sugar

More Date Methods

1.millisecond  || 2.milliseconds
1.millisec     || 2.millisecs

# relative to now, or another date
NSDate.new  # => 2013-01-03 11:42:24 -0700
5.days.ago  # => 2012-12-29 11:42:24 -0700
5.days.before(NSDate.new)  # => 2012-12-29 11:42:24 -0700
5.days.hence  # => 2013-01-08 11:42:24 -0700
5.days.after(NSDate.new)  # => 2013-01-08 11:42:24 -0700

# from_components
feb_1_2013 = NSDate.from_components(year: 2013, month: 2, day:1)

Number and Date, with style

10000.string_with_style(NSNumberFormatterCurrencyStyle)  # => "$10,000.00"
10000.string_with_style(:currency)  # => "$10,000.00"

now.string_with_style  # => "February 19, 2013"
now.string_with_style(NSDateFormatterShortStyle)  # => "2/19/13"
now.string_with_style(:short)  # => "2/19/13"

NSData conversion (strings, images)

string_data = 'String'.nsdata  # => default encoding is UTF8.
image_data = 'an image'.uiimage.nsdata  # PNG data representation

string_data.nsstring  # => 'String'
image_data.nsimage  # => whatever 'an image' was

Some more file operations

# rm a file
"my.plist".remove!  # => "my.plist".document.remove!
# get the resource path
# get the resource URL, useful for local HTML operations
# access data from Info.plist

New Image Operations

image.in_rect(frame)  # returns the part of the image contained in frame
image.scale_to(new_size)  # won't stretch, but the image might have transparent padding
image.scale_to(new_size, background: :white)  # adds a white background before padding
image.scale_within(new_size)  # same as scale_to in that it doesn't stretch the
# image, but the size is not guaranteed to be new_size.  It is guaranteed not to
# be *bigger* than new_size
image.scale_to_fill(new_size)  # again, like scale_to, but the image is guaranteed
# to completely fill new_size, even if some of the image has to be cropped to fit.
# You can control which side or corner you prefer to remain visible.  because the
# aspect ratio is maintained, only ONE dimension will need to be cropped.
image.scale_to_fill(new_size, position: :top_left)

# returns a UIColor (and supports retina images)
image.color_at([5, 5])

# Apply a mask to an image.  The mask should be a grayscale image.  White areas
# will be made transparent, and black opaque.

# Combine two images
image_ab = image_a << image_b

568 - 4" iPhone-specific images

If you require 'sugarcube-568' in your Rakefile, you can use UIImage.imageNamed(name) or name.uiimage to load images that are specific to the 4" iphone by using the suffix -568h, e.g. image-568h@2x.png

'tall'.uiimage  # => UIImage.imageNamed('tall')
# => tall.png on iphone 3g
# => tall@2x.png on iphone 4
# => tall-568h@2x.png on iphone 5

This code is ported from https://github.com/gaj/imageNamed568, which I had some problems with on RubyMotion (it worked, but not always. Very strange).


# convert a UIView to UIImage.  retina-ready.

# rotate animation
view.rotate_to Math::PI  # rotate view upside down
view.rotate_to(duration: 0.5, angle: 45.degrees)  # using options

When defining a UIView subclass, you often have attributes that affect your drawRect method (99% of the time, ALL the attributes affect drawing, right?). So SugarCube adds a attr_updates method, which creates an attribute identical to attr_accessor but the setter calls setNeedsDisplay if the new value != the old value.

class NiftyView < UIView
  attr_updates :insets, :pattern

This was pulled off warrenm's AHAlertView project. I thought the effect was awesome, and deserved more attention!


view.tumble  # the view will fall and rotate - a good 'cancel button effect'

Animation Chains

These are used to create a string of animations:

UIView.animation_chain {
  view.slide(:left, 20)
}.and_then {
  view.slide(:up, 20)
}.and_then {
  view.slide(:right, 20)
}.and_then {
  view.slide(:down, 20)
}.and_then {

The gotcha is that you have to assign animation options (easing, duration, delay) multiple times. The options you pass to and_then do not get assigned to the animations within the block.

UIView.animation_chain(duration:1) {
  view.slide(:left, size: 20, duration: 1)
}.and_then(duration: 1) {
  view.slide(:up, size: 20, duration: 1)

Not pretty, but the only solution I see is to assign the options to a class variable that all the animation methods would use. In the rare case that you create animations on separate threads, the options would get all messed up (and correct me if I'm wrong, but this does seem like a distinct possibility).

Okay, not the most exciting release, but I hope you enjoy nonetheless!