If you're wondering when sugarcube will be v1.0...

...answer is: it's not that kind of tool! SugarCube will likely be an ongoing project, and I have a keen fondness of the "v0." prefix. SugarCube is not really a tool in-and-of-itself, it is a collection of helpers.

That being said, I would count each of these announcement emails as a "feature freeze". Unless something is broken or conflicts with Cocoa Touch, I will not change it just for grins. Of course, I might change the implementation, but that's a no-brainer.

REPL Goodness - Thanks Thom Parkin!

The center method

If you are using the SugarCube::Adjust module, you might be enjoying the "nudging" methods it provides (up, down, left, right), and you might even be playing with the shadow method (are you!?). Well add this to your arsenal:

> center

O_O. The center method is used to do just that - center the current 'adjusted' view in its parent view. The workflow would look something like this:

> tree
  0: . UIView(#cbf6610, [[0.0, 0.0], [320.0, 411.0]])
  1: `-- UIView(#cb273e0, [[0.0, 0.0], [320.0, 411.0]])
> a 1  # or `adjust 1`, if you're not into the whole brevity thing
=> UIView(#cb273e0, [[0.0, 0.0], [320.0, 411.0]]), child of UIView(#cbf6610)
> button = UIButton.rounded
=> UIRoundedRectButton(#139ba0c0, [[0.0, 0.0], [0.0, 0.0]])
> button.setTitle('hi!', forState: :normal.uicontrolstate)
=> UIRoundedRectButton(#139ba0c0, [[0.0, 0.0], [0.0, 0.0]])
> button.sizeToFit
=> UIRoundedRectButton(#139b9e60, [[0.0, 0.0], [43.0, 44.0]])
> a << button
=> UIView(#cb273e0, [[0.0, 0.0], [320.0, 411.0]]),  child of UIView(#cbf6610)

# ZOMG! There is a freakin' button!
# now we need to ADJUST this button:
> a button
=> UIRoundedRectButton(#139b9e60, [[0.0, 0.0], [43.0, 44.0]]),  child of UIView(#cb273e0)

# and, finally, center it!  this will output the frame (all the frame-adjusting methods do)
> center
[[138.5, 0.0], [43.0, 44.0]]
=> UIRoundedRectButton(#139b9e60, [[138.5, 0.0], [43.0, 44.0]]),  child of UIView(#cb273e0)

But that's not all! Act now!

The code above centered our button in the horizontal button. But Thom found an immediate need to center the button in all sorts of ways. Namely, you can center in the horizontal (aka x) OR vertical (aka y) direction, or both:

> center :h   # or :x
> center :v   # or :y
> center :hv  # or :xy

And you can tell center how many cells you want:

> center 4  # the button will be in row 1 of 4
> center 4, 3  # the button will be in row 3 of 4

You can mix & match the order. If this was a "real" API, I wouldn't like it, but since it's a development helper, we get away with this kind of crap ;-)

> center 3, :xy, 2  # center in the x&y direction, in the 2nd cell of 3

Another feature Thom added, kind of as an "aside" to the center method, is a way of formatting the frame output. Check it:

> repl_format :ruby  # this is the default, you've already seen it
=> UITableView(#b43f200, [[0.0, 0.0], [320.0, 368.0]]), child of UIView(#ad017b0)
> repl_format :json  # JSON dictionary
=> UITableView(#b43f200, {x: 0.0, y: 0.0, width: 320.0, height: 368.0}), child of UIView(#ad017b0)
> repl_format :objc  # uses NSStringFromCGRect
=> UITableView(#b43f200, {{0.0, 0.0}, {320.0, 368.0}}), child of UIView(#ad017b0)

If you're interested in the history of this feature, see Thom's pull request.

And Even More REPL Goodness!

I've beefed up the wonderous tree command to support any type of tree-like object, most importantly: UIViewControllers!

# pulls the rootViewController off the application window
> tree root  # hehe, yeah, clever
  0: . #
  1: +-- #
  2: |   `-- #
  3: +-- #
  4: +-- #
  5: |   `-- #
  6: +-- #
  7: `-- #

And, because you guys are so great, it even shows you the presentedViewController (this would be a bigger deal if you knew how often I abuse modal windows. LOVE EM)

(main)> tree root
  0: . #
  1: +-- #
  2: |   +-- #
  3: |   `-- #
  4: +-- #
  5: +-- #
  6: |   `-- #
  7: +-- #
  8: +-- #
  9: `-- # presented by #
 10:     `-- # presented by #
 11:         `-- # presented by #

Btw, did you know you can assign anything to the REPL's self using repl any_object? If this object is assigned and it is in the list that tree outputs, it will be highlighted in the terminal.

If you have a tree-like object and you want to output it using tree, just pass the method-name that will fetch the 'subitems'.

> tree App.window, :subviews

Or if you're feeling industrious, you can use a block:

(main)> tree(App.window) { |view| view.subviews[0...1] }
  0: . UIWindow(#ad59ae0, [[0.0, 0.0], [320.0, 480.0]])
  1: `-- UIView(#1317bec0, [[0.0, 20.0], [320.0, 460.0]])
  2:     `-- UIActivityIndicatorView(#13188630, [[141.5, 211.5], [37.0, 37.0]])
  3:         `-- UIImageView(#131888d0, [[0.0, 0.0], [37.0, 37.0]])

Awww, Poor Deprecated Methods

The defaults.rb file is forthwith deprecated. Stop using it! As soon as I push this version I'm removing it, so version 0.12 will no longer have 'key'.get_default.

New NSUserDefaults methods!

I think that including the NSUserDefaults class name really shows where this data is coming from, and it's still oh-so-sweetly-short.

if NSUserDefaults['key'].nil?
    NSUserDefaults['key'] = 'value!'
else
    puts NSUserDefaults['key']
end

This has the same gotcha that all other wrappers for NSUserDefaults have:

NSUserDefaults['key'] = { 'hi': 'there' }
puts NSUserDefaults['key']  # => {"hi"=>"there"}
NSUserDefaults['key']['hi'] = 'everyone!'
# ERROR! can't modify frozen/immutable hash (RuntimeError)
# you have to do this:
vals = {}.merge NSUserDefaults['key']
NSUserDefaults['key'] = vals

You might have heard of Ruby on Rails...

As I hear about extensions that RoR has added, I'll probably add those into SugarCube. The first is my new favorite: blank?

# truthiness with `blank?`
nil.blank?    # => true
false.blank?  # => true
''.blank?     # => true
[].blank?     # => true
{}.blank?     # => true

0.blank?        # => false
true.blank?     # => false
'a'.blank?      # => false
['a'].blank?    # => false
{a: 'a'}.blank? # => false

Factory methods for UIActivityIndicatorView

Michael Erasmus added factory methods for UIActivityIndicatorView: methods:

UIActivityIndicatorView.white  # => UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(:white.uiactivityindicatorstyle)
UIActivityIndicatorView.large  # => ...IndicatorStyle(:large.uiactivityindicatorstyle)
UIActivityIndicatorView.gray   # => ...IndicatorStyle(:gray.uiactivityindicatorstyle)

Of course, you still have to type UIActivityIndicatorView, but at least it saves you HALF of a giant mouthful.

NSCoder additions

I love the NSCoding protocol - I think it makes local persistence the easiest thing evar. Here are some friends:

# hash access is the handiest - stores and/or fetches an object
coder['key'] = self.value
self.value = decoder['key']

# but if you want to store booleans and such in the MOST compact way:
coder.set('sugarcube_is_neat', toBool:self.is_sugarcube_neat?)
self.sugarcube_is_neat = decoder.bool('sugarcube_is_neat')

All the C types are supported. See the README for the entire list.

Added can_open? to NSURL

Yup. I did. That about wraps it up!

Except for some sweet UIImage messer-uppers!

I'm getting into a little bit of UIImage manipulation here, which could really deserve to be its own library, so be warned: these might be extracted into a separate gem one day. But probably not - so enjoy 'em!

image.scale_to [37, 37]  # new image will be 37x37 pixels
image.rounded  # default: 5 pt radius
image.rounded(10)

I love image manipulation, so expect this to grow! :-)