I finally got a chance to check out Thomas Kadauke’s TinyMon app that he has graciously posted on github. For one, it’s certainly a well designed, well written app! The tests in particular are commendable! They put my apps to shame…

This little guy caught my eye: https://github.com/tkadauke/TinyMon/blob/master/lib/teacup_gradient_handler.rb

I don’t think I’ve seen someone use this feature of teacup before! It is a perfect use of a Teacup handler (and I’m encouraging Thomas to add this to sweettea!)

So, I thought I would explain a little bit about what Teacup handlers are, how you write them, and I’ll write a bit more about sweettea, and why it is REALLY what you should be using in conjunction with teacup (even if you don’t use any other sugarcube features).


What teacup does do

Teacup does, basically, two things:

  1. Provides a DSL to create a view hierarchy (usually from within your controller). This is designed to be terse, so that your controller isn’t cluttered with lots of UIView-creation code, and you can assign views to instance variables with ease.

    “`ruby class MyController < UIViewController

    stylesheet :userform layout do @container = subview(UIView, :container) do subview(UILabel, :fullnamelabel) @fullnameinput = subview(UITextField, :fullname_input) subview(UIButton, :submit) end end

    end ”`

  2. Provides a DSL to style those views using a CSS-like language, which usually takes place in Teacup::Stylesheet objects (but doesn’t have to, you know!). There are a few “magical” keys, but for the most part they are UIKit methods. Also, the Stylesheet class defines a few helper methods

    “`ruby Teacup::Stylesheet.new :userform do import :appstyles

    style :container, frame: [[0, 0], appsize], # app_size takes the status bar into account autoresizingMask: flexiblewidth | flexible_height, # some resizing mask helpers backgroundColor: UIColor.lightGrayColor # traditional UIKit

    style :fullnamelabel, extends: :label, frame: [[20, 20], [100, 20]], text: ‘Your name:’

    style :fullnameinput, extends: :input, frame: [[110, 20], [200, 20]], placeholder: ‘Englebert Humperdink’

    end ”`

extends: is one “magical” key, constraints: is another. I’m not gonna go into constraints here - check out my post about them.

What teacup can do

Teacup doesn’t just map the style key to a method name. It maintains a list of “handlers”, and if you know about these and understand them, you can write stylesheets that are much more expressive!

There aren’t very many built-in handlers; this keeps the teacup library lean-and-mean. The ones that are there are related to positioning, and some very basic UIButton handlers, which are offered as examples of what a handler can do (the original teacup implementation, written by Conrad Irwin had these helpers as special cases - much later, they were re-implemented as handlers). Here are all the built in handlers:

“`ruby style :button, # size: width: 100, height: 20,

# x-position left: 10, x: 10, # same thing right: 10, # you must have a superview and width defined already # same as x: 220 on an iphone centerx: appsize.width / 2, # easy centering - again, you need the width middle_x: 160, # alias

# y-position top: 10, y: 10, # alias bottom: 10, # either 430 or 538 on an iphone w/ status bar visible centery: appsize.height / 2, middley: appsize.height / 2,

# assign size or origin size: [100, 20], origin: [10, 10], center: [appsize.width / 2, appsize.height / 2], # this isn’t an alias! center IS a property on UIView. here for completeness

# assign the frame - this is an interesting handler, because it assigns the frame, # but offers some shorthands and introspection capabilities… read on! frame: [[10, 10], [100, 20]],

# UIButton specific title: ‘Press Me’, # setTitle(‘Press Me’, forState:UIControlStateNormal) titleColor: UIColor.blueColor, titleFont: UIFont.systemFontOfSize(16), font: UIFont.systemFontOfSize(16) # alias ”`

These handlers don’t just assign the top/left/size/whatever - they can perform some introspection on the receiver, depending on the argument!

ruby style :button: x: '10%', # 320width screen => x: 32 center_x: '50%', # centered! width: 90%, frame: :full # takes up the entire bounds of the superview

Enter SugarCube, stage right

SugarCube offers a TON of shorthands, many of them are related to styling (this is not an accident, obviously). But you still have to pass the right type to these methods, so it’s shorter but still not a DSL:

ruby style :label, textAlignment: :center.uitextalignment, # this is only a modest "improvement" textColor: :blue.uicolor # (and many would argue that point!)

Nice, but it doesn’t really look like a stylesheet yet. It’s still a verbose iOS-y jumble…

Enter sweettea, stage left

In a nutshell, sweettea adds handlers to teacup that interface with sugarcube.

ruby style :label, alignment: :center, color: :blue

Is that much better!? I think so! It’s not magic, either - the handlers are expliticly defined in the sweettea handlers file. Keep that file handy!

I can’t go through all the sweettea shortcuts here, for the sake of brevity, but I’m updating the README today, once I’m done with this post.

Enter YOU, stage center!

Now we can understand how tkadauke’s gradient handler works!

“`ruby

the class UIView indicates that this handler can be applied to all subclasses

of UIView. :gradient is the name of the key in the style declaration

associated with this handler.

Teacup.handler UIView, :gradient { |layer| # self is the UIView being styled, # layer is the options you pass in your stylesheet gradient = CAGradientLayer.layer # create a gradient layer gradient.frame = self.bounds # have it fill the view layer layer.each do |key, value| # apply all the options in layer gradient.send(”#{key}=“, value) end self.layer.insertSublayer(gradient, atIndex:0) # add it to the layers } ”`

(btw, this is going to get added to sweettea SOON, in one form or another)

The sweettea handlers take Teacup out of just a DSL/wrapper for UIKit, into a full-blown framework to help you style your UIViews. I’ve heard a lot of comparisons between teacup and Pixate recently, but if you’re not using teacup handlers, you’re only touching the surface of what teacup can do to help you!