Need help with sugarcube?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

430 Stars 69 Forks Other 1.4K Commits 7 Opened issues


Some sugar for your cocoa. RubyMotion helpers.

Services available


Need anything else?

Contributors list


Join the chat at

Build Status Version


Cocoa and CocoaTouch are verbose frameworks. These extensions hope to make development in rubymotion more enjoyable. With SugarCube, you can create a color from an integer or symbol, or create a UIFont or UIImage from a string.

Many core classes are opened up as well, like adding the '<<' operator to a UIView instance, instead of view.addSubview(subview), you can use the more idiomatic:

view << subview

The basic idea of SugarCube is to turn operations on their head. So instead of:


How about:


It is possible that you will not like SugarCube. That is perfectly fine! Some people take milk in their coffee, some take sugar. Some crazy maniacs don't even drink coffee, if you can imagine that... All I'm saying is: to each their own. You should checkout BubbleWrap for another take on Cocoa-wrappage.


SugarCube is the result of the hard work of many developers, but it’s mostly maintained by Colin Gray, with help from members of the RubyMotion community. If you have an idea, please open a pull request so we can discuss it! All PRs must be submitted with specs.

If you use SugarCube on your projects, please consider donating a small amount via, or better yet: fork the project, add some specs, and improve the quality of this super-handy gem!


A work in progress. This README is the best source, but I am trying to be more diligent about adding Yard documentation, which is available here:


SugarCube uses FerVer: This means that minor breaking changes occur in minor version bumps, and sometimes a non-breaking change occures in the major version (like when we added OS X support).


gem install sugarcube

in Rakefile

require 'sugarcube'

or in Gemfile

gem 'sugarcube', :require => 'sugarcube-classic'

or for the bold:

gem 'sugarcube', :require => 'sugarcube-all'

or for the picky:

gem 'sugarcube', :require => [




in terminal

$ bundle install


SugarCube has grown over time to be a pretty massive collection of helpers. While some people choose to use the entire library, other people like to pick and choose the extensions they want to use. With that in mind, SugarCube is written so that it does not pollute any classes by default. So if all you do is

require "sugarcube"
, you are NOT going to get much mileage!

In the installation code above, I show the example of using

:require => 'sugarcube-all'
to include all of SugarCube's extensions. You can, alternatively require just the packages you need:
gem 'sugarcube', :require => [

Or, from your Rakefile:

require 'motion/project/template/ios'

require 'bundler' Bundler.require

require 'sugarcube-ui' require 'sugarcube-events' require 'sugarcube-gestures' require 'sugarcube-568' require 'sugarcube-attributedstring'

You can require the packages in piecemeal like this, or you can require a group of packages:

classic, common, or all
  • sugarcube-classic
    : Excludes 568, attributedstring, gestures, repl, awesome, anonymous, unholy, and legacy
  • sugarcube-common
    : Excludes awesome, anonymous, unholy, and legacy
  • sugarcube-all
    : Excludes legacy

So without further ado,


Packages are sorted more-or-less by their usefulness. The more esoteric ones are at the end.

REPL (wiki)

If you install SugarCube and only use the REPL package, you will benefit from some of SugarCube's greatest tricks!

require 'sugarcube-repl'

This package is useful during development because it adds methods to the REPL that make adjusting and introspecting views much easier. You'll get a lot more done in the REPL with these additions.

You should NEVER use these methods in your application, because this package is only included in 'development' mode. That means if you hard-code a call to 'tree' in your code, that will crash when you go to release your app. YIKES.

To keep this document lean-and-mean, I've put most of the REPL documentation in the wiki, but here's a quick overview:

  • Use the
    commands to output your view hierarchy. It can accept a UIView,
    , or
    object as the root object, or it defaults to your application's
  (main)> tree
    0: . UIWindow(#6e1f950: [[0.0, 0.0], [320.0, 480.0]])
    1: `-- UIView(#8b203b0: [[0.0, 20.0], [320.0, 460.0]])
    2:     +-- UIButton(#d028de0: [[10.0, 10.0], [320.0, 463.400512695312]])
  • The number can be passed to the
    method, aliased to
    , and that will become the view or object you are adjusting.
  (main)> a 2
  => UIButton(#d028de0: [[10.0, 10.0], [320.0, 463.400512695312]])
  • Now you can modify that view, either by accessing it via
    (with no arguments it returns the object being adjusted) or by using an adjust method:
  > up 1
  > wider 15
  # these have shorthands, too
  > u 1
  > w 15
  • Changed your mind? undo all adjustments to the object currently selected:
  > restore
  • Which element in the tree did I select with adjust? You can make the object selected flash in the simulator:
  > blink

Be sure to read more in the REPL Additions Wiki page.

UI on iOS: UIKit extensions (wiki)

A big package chock full of methods to make working in UIKit a joy.

require 'sugarcube-ui'

A few varieties of methods are in this package:

  • Conversions:
  • Helpers: shorthands for common operations, like
    a_view << a_subview
  • Symbols:
  • Frame accessors:
    a_view.x = 100

There are too many methods to define here. Instead: a complete list of methods is available in the documentation, and the wiki page is a great source as well.

UI on OS X: AppKit extensions

Similar extensions as the iOS version, but using the

prefix on method names:
  • Conversions:
  • Helpers:
    view << subview
  • Symbols:
  • Frame accessors:
    a_view.x = 100
    , and

UI on Android

(warning: extending built-in classes is not reliable in RubyMotion on Android)

ViewGroup gets the same

method that you see in UIView and NSView.


require 'sugarcube-constants'

There are lots and lots of constants in UIKit, so many that I wanted a way to write these as symbols instead of UILongConstantNames. This package adds methods to

s to convert them into a UIKit or Foundation constant.
:center.nsalignment  # => NSTextAlignmentCenter (formerly UITextAlignmentCenter)
:upside_down.uiorientation  # => UIDeviceOrientationPortraitUpsideDown
:rounded.uibuttontype  # => UIButtonTypeRoundedRect
:highlighted.uicontrolstate  # => UIControlStateHighlighted
:touch.uicontrolevent  # => UIControlEventTouchUpInside
:change.uicontrolevent  # => UIControlEventValueChanged
:all.uicontrolevent  # => UIControlEventAllEvents

these are really handy for custom buttons - touch_start means the finger is

inside the button, touch_stop is outside the button or canceled

:touch_start # => UIControlEventTouchDown | UIControlEventTouchDragEnter :touch_stop # => UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchDragExit

:large.uiactivityindicatorstyle # :large, :white, :gray :bar.uisegmentedstyle # :plain, :bordered, :bar, :bezeled

UITableView and UITableViewCell have LOTS of associated constants... I'm

adding them as I come across them.

:automatic.uitablerowanimation # or .uitableviewrowanimation :default.uitablecellstyle # or .uitableviewcellstyle :disclosure.uitablecellaccessory # or .uitableviewcellaccessorytype :blue.uitablecellselectionstyle # or .uitableviewcellselectionstyle

See the complete list by browsing the documentation, or open up symbol.rb.


require 'sugarcube-timer'

Methods get added to the Fixnum class, and are available as methods on

, and can be called via the SugarCube::Timer module.
# once
1.second.later do
# repeating
1.second.every do

you can assign the return value (an NSTimer)

timer = 1.second.every do @view.shake end

and invalidate it


the every method is available in the SugarCube::Timer module,

which you might find more readable

include SugarCube::Timer

every 1.minute do puts "tick" end

might as well make an alias for 'later', too

after 1.minute do puts "ding!" end

other time-related methods

for compatibility with Time methods, the mins/secs (and min/sec) aliases are provided. Personally,

I like the more verbose minutes/seconds.

1.millisecond || 2.milliseconds 1.millisec || 2.millisecs 1.second || 2.seconds 1.sec || 2.secs # aliases 1.minute || 2.minutes # 1.minute = 60 seconds 1.min || 2.mins # aliases 1.hour || 2.hours # 1.hour = 60 minutes || 2.days # = 24 hours 1.week || 2.weeks # 1.week = 7 days

sensible values for 'month' and 'year', even though we all know you can't

really define them this way (go back to python if you find your brain hemorrhaging):

1.month || 2.months # 1.month = 30 days 1.year || 2.years # 1.year = 365 days


require 'sugarcube-events'

Inspired by BubbleWrap's

method, but I prefer jQuery-style verbs and SugarCube symbols. Adds methods to UIControl and UITextView.


button = UIButton.alloc.initWithFrame([[0, 0] ,[10, 10]])

button.on(:touch) { my_code } button.on(:touch_up_outside, :touch_cancel) { |event| puts event.inspect



remove handlers, :touch_up_outside, :touch_cancel) # all events

You can only remove handlers by "type", not by the action. e.g. If you bind three

events, calling
will remove all three.


These handlers are functionally identical in usage to the same methods in

. They use the
method, but you do not have to worry about un-observing. When the text view is released, these observers will be removed.

There are two aliases for each event, or you can use the event notification. I prefer the present tense (jQuery-style

on :change
), but UIKit prefers past simple (
). The notifications, on the other hand, are in present simple (
). Whatever floats your boat.

Anyway, these are all the same:

:editing_did_begin   :begin   UITextViewTextDidBeginEditingNotification
:editing_did_change  :change  UITextViewTextDidChangeNotification
:editing_did_end     :end     UITextViewTextDidEndEditingNotification
text_view =
text_view.on :begin do |notification|  # <= you have to accept the notification in your block
  p 'wait for it...'
text_view.on :change do |notification|
  p text_view.text
text_view.on :end do |notification|
  p 'done!'

if you want to remove the block, use the off method :editing_did_change

or :change

or UITextViewTextDidChangeNotification


require 'sugarcube-gestures'

SugarCube's gesture support is very similar to BubbleWrap's, and it's entirely possible that the two will be merged into one thing. But SugarCube is all about extending base classes, whereas BubbleWrap tends to add new classes to do the heavy lifting. Plus the options you pass to SugarCube are very different, and the prefix is "on" instead of "when" (e.g. "onpan" instead of "whenpanned")

view.on_pan do |gesture|
  location = gesture.locationInView(view)

other gesture methods, with common options:

view.on_tap # use system defaults view.on_tap(1) # number of taps view.on_tap(taps: 1, fingers: 1) # number of taps and number of fingers

view.on_pinch # no options view.on_rotate # no options

view.on_swipe # use system defaults view.on_swipe :left view.on_swipe(direction: :left, fingers: 1) view.on_swipe(direction: UISwipeGestureRecognizerDirectionLeft, fingers: 1)

view.on_pan # use system defaults view.on_pan(2) # minimum and maximum fingers required view.on_pan(fingers: 2) view.on_pan(min_fingers: 2, max_fingers: 3)

If present, overrides fingers options and instead handles gestures originating at specified screen edges (UIScreenEdgePanGestureRecognizer)

view.on_pan(edges: []) # Some combination of [:left, :right, :top, :bottom, :all].

on_press is a continuous event (it uses UILongPressGestureRecognizer), so

you need to check the gesture:

view.on_press do |gesture| if gesture.state == UIGestureRecognizerStateBegan # handle press end end view.on_press(1.5) # duration view.on_press(duration: 1.5, taps: 1, fingers: 1)

this version is only fired when the long-press begins; this is probably more

useful to you:

view.on_press_begin do ... end

or, when the gesture ends:

view.on_press_ended do ... end


require 'sugarcube-notifications'

Makes it easy to post a notification to some or all objects.

# this one is handy, I think:
MyNotification = "my notification"
MyNotification.post_notification  # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:nil)
MyNotification.post_notification(obj)  # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj)
MyNotification.post_notification(obj, user: 'dict')  # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj, userInfo:{user: 'dict'})

you can access the userInfo dictionary directly from the notification

def notified(notification) notification[:user] # => 'dict' end

very similar to add or remove an observer

MyNotification.add_observer(observer, :method_name) MyNotification.add_observer(observer, :method_name, object)

remove the observer

MyNotification.remove_observer(observer) MyNotification.remove_observer(observer, object)


Image Manipulation - VERY handy! Includes some quick maniputions on UIImage, and adds an interface to chain together CIFilters. Plus, you can refer to

to find out what filters are supported in iOS (all supported filters get a class method in this file).

require 'sugarcube-image'
UIImage additions
image.scale_to [37, 37]
image.rounded  # default: 5 pt radius

image.in_rect([[10, 10], [100, 100]]) # get part of an image

image.darken # => good for "pressed" buttons image.darken(brightness: -0.5, saturation: -0.2) # these are the defaults image.gaussian_blur(radius: 5) image.inverted

image.rotate(:left) image.rotate(:right) image.rotate(:flip) # 180° - if you have a better name, let me know! image.rotate(45.degrees)

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])

default insets are UIEdgeInsetsZero

image.tileable image.tileable(insets) image.stretchable image.stretchable(insets)

Apply a mask to an image. The mask should be a grayscale image. White areas

will be made transparent, and black opaque.


Apply a color overlay to an image. This is used used on icons (PNG's), on which

you want to change the color.

image.overlay(UIColor.redColor) image.overlay(:red)

Combine two images

image_ab = image_a << image_b

Create an image from scratch!

UIImage.canvas([100, 100]) do |context| # opaque: false, scale: UIScreen.mainScreen.scale

draw here!


use an image as a background to draw on

image.draw do |context|

draw here!



image = UIImage.canvas(size: [10, 20]) image.width # => 10 image.height # => 20

CIFilter additions
# create a filter
gaussy = CIFilter.gaussian_blur(radius: 5)
gaussy = CIFilter.gaussian_blur(5)  # this also works - you can find the arg order by looking in cifilter.rb

apply a filter to a UIImage

new_image = image.apply_filter(gaussy).uiimage # apply_filter returns a CIImage, which is converted to UIImage

apply a chain of filters using the | operator or apply_filter

darken = CIFilter.color_controls(saturation: 0, brightness: 0) new_image = image.apply_filter(gaussy).apply_filter(darken).uiimage

If you include

you can use the
operator to chain filters:
# using the filters from above
new_image = image | gaussy | darken | UIImage
new_view = view | gaussy | darken | UIView

There are 91 filters available in iOS 6, I won't list them here, but check out the Apple documentation to read about them, and study cifilter.rb.


require 'sugarcube-color'

Methods to merge or manipulate a color, or to get information about a color. Works best on RGB colors, but HSB will work well, too.

s based on image patterns can't easily be inverted or mixed.

Any classes that have a well-defined "color" representation are given a

method, so it's easy to create a color from hex codes, css names, or images (as patterns).
:blue.uicolor  # UIColor.blueColor
# uicolor() accepts an alpha value, too

all CSS colors are supported (but no "grey" aliases, consistent with UIKit,

which only provides "grayColor")

:firebrick.uicolor # => 0xb22222.uicolor

RGB values, in the range 0..255.

[160, 210, 242].uicolor # => UIColor.colorWithRed(0.6274, green:0.8235, blue:0.9490, alpha:1.0) [160, 210, 242].uicolor(0.5) # => UIColor.colorWithRed(0.6274, green:0.8235, blue:0.9490, alpha:0.5)

create a UIColor from a hex value

0xffffff.uicolor # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:1.0) 0xffffff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)

works when using strings, too

"#fff".uicolor # => UIColor.whiteColor "#ffffff".uicolor # => UIColor.whiteColor "#ff00ff".uicolor == :fuchsia.uicolor == 0xff00ff.uicolor # => UIColor.colorWithRed(1.0, green:0.0, blue:1.0, alpha:1.0) "#f0f".uicolor(0.5) == :fuchsia.uicolor(0.5) == 0xff00ff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)

note: 0xf0f.uicolor == 0x000f0f.uicolor. There's no way to tell the difference

at run time between those two Fixnum literals.

UIColor from image name, if the first character is not "#"

"pattern".uicolor == "pattern".uiimage.uicolor # => UIColor.colorWithPatternImage(UIImage.imageNamed("pattern"))

These methods are added onto the UIColor class:

:red.uicolor.invert # => UIColor.cyanColor
:blue.uicolor.invert # => UIColor.yellowColor
:green.uicolor.invert # => UIColor.magentaColor
:red.uicolor + :blue.uicolor # => UIColor.purpleColor
:red.uicolor + :green.uicolor # => :olive.uicolor
# (I didn't know that until I tried it in the REPL, but it was pretty cool to
# see the UIColor#to_s method match that mixture to olive!)

a more generic color mixing method (+ delegates to this method):

:white.uicolor.mix_with(:black.uicolor, 0) # => :white :white.uicolor.mix_with(:black.uicolor, 0.25) # => 0x404040.uicolor :white.uicolor.mix_with(:black.uicolor, 0.5) # => :gray, same as :white.uicolor + :black.uicolor :white.uicolor.mix_with(:black.uicolor, 0.75) # => 0xbfbfbf.uicolor :white.uicolor.mix_with(:black.uicolor, 1) # => :black

you can get information about a color: # => 0 # => 1 # => 1 :cyan.uicolor.hue # => 0.5 :cyan.uicolor.saturation # => 1.0 :cyan.uicolor.brightness # => 1.0 :cyan.uicolor(0.9).alpha # => 0.9

convert to CGColor



require 'sugarcube-factories'

Accepts multiple buttons and handlers. In its simplest form, you can pass just a title and block. An optional

can either be passed in as an option, or as the 2nd positional arg.


UIAlertView.alert(title, options)
UIAlertView.alert(title, message, options)
0 => title => String - title of the alert.  optional positional arg.
1 => message => String - message of the alert.  optional positional arg.
:title => String - title of the alert.
:message => String - message of the alert.
:success => Proc - the success handler
:cancel => Proc - the cancel handler
:buttons => [] - List of buttons ([cancel, others...])
:buttons => {} - Hash of buttons ({cancel:, others: ...}) in any order of course
:style => Symbol | Fixnum - A symbol (uialertstyle) or constant (UIAlertViewStyle*)
:show => Boolean - Whether to show the action sheet (default: true)
# simple title/message alert
UIAlertView.alert('This is happening, OK?', 'An optional message') do

a little more complex - the cancel button should be first, and the block will

receive a string and an index

UIAlertView.alert('This is happening, OK?', message: 'Don't worry, it'll be fine.', buttons: ['Nevermind', 'OK'], ) do |button, button_index| if button == 'OK' # or: button_index == 1 self.happened! end end

Full on whiz-bangery. The cancel button should be the first entry in

buttons:. When you specify the success and cancel button handlers this way,

you need not assign both.

UIAlertView.alert('I mean, is this cool?', buttons: ['No!', 'Sure!', 'Hmmmm'], message: 'No going back now', cancel: proc { self.cancel }, success: proc { |pressed| self.proceed if pressed == 'Sure!' } )

To keep up with BubbleWrap's awesome BW::ActionSheet and BW::AlertView

helpers, SugarCube provides a similar interface.

UIAlertView.alert('Confirm action!', 'Are you sure you want to do this?', buttons: { cancel: 'No!', success: 'Sure!', unsure: 'Hmmm', }) do |button|

button will be :cancel, :success or :unsure



This is very similar to

, but instead of
handlers, you can have
cancel, success, and destructive
handlers, and there is no

If you use an array of buttons (which you probably should), the order of arguments is

[:cancel, :destructive, :others, ...]
. If you dont want a cancel or destructive button, pass
in place.


UIActionSheet.alert(title, options)
0 => title => String - title of the action sheet
:title => Proc - title of the action sheet
:success => Proc - the success handler
:cancel => Proc - the cancel handler
:destructive => Proc - the destructive handler
:buttons => [] - List of buttons ([cancel, destructive, others...])
:buttons => {} - Hash of buttons ({cancel:, destructive:, others: ...}) in any order of course
:style => Symbol | Fixnum - A symbol (uiactionstyle) or constant (UIActionSheetStyle*)
:show => Boolean - Whether to show the action sheet (default: true)
:from => CGRect | UIBarButtonItem | UIToolbar | UITabBar | UIView (default: first window)
         Where to display the alert.  Mostly relevant on iPad.
:view => UIView (default: first window)
         The view to display the alert when used with :from => CGRect
# simple
UIActionSheet.alert 'This is happening, OK?' do

a little more complex, with cancel and destructive buttons

UIActionSheet.alert('This is happening, OK?', buttons: ['Cancel', 'Kill it!', 'Uh, what?'] ) do |button|

button is 'Cancel', 'Kill it!' or 'Uh, what?'


skip cancel and destructive buttons:

UIActionSheet.alert('Should I?', buttons: [nil, nil, 'OK', 'Nevermind']) { |pressed| self.do_it if pressed == 'OK' }

UIActionSheet.alert 'I mean, is this cool?', buttons: ['Nah', 'With fire!', 'Sure', 'whatever'], cancel: proc { self.cancel }, destructive: proc { self.kill_it_with_fire } success: proc { |pressed| self.proceed if pressed == 'Sure' }

By passing a Hash to buttons you can get this improved interface, similar to

BubbleWrap's awesome interface.

UIActionSheet.alert('Well, how bout it?', buttons: { cancel: 'Cancel', destructive: 'Kill it with fire!', help: 'Tell me more' }) do |button|

button is :cancel, :destructive or :help



Starting with iOS 8.0, UIActionSheet and UIAlertView are deprecated and replaced by UIAlertController.

This is very similar to

but you have to pass a
as first argument.


UIAlertController.alert(controller, options)
UIAlertController.alert(controller, title, options)
0 => title => String - title of the action sheet
:title => Title of the alert sheet
:buttons => [] - List of buttons ([cancel, destructive, others...])
:style => Symbol | Fixnum - A symbol (uialertcontrollerstyle) or constant (UIAlertControllerStyle*)
:show => Boolean - Whether to show the alert controller (default: true)
:from => CGRect | UIBarButtonItem | UIView (default: first window)
         Where to display the alert.  Mostly relevant on iPad.
:view => UIView (default: first window)
         The view to display the alert when used with :from => CGRect
# simple
UIAlertController.alert(self, 'This is happening, OK?', buttons: ['Cancel', 'Kill it!', 'Uh, what?']
  ) do |button|
  # button is 'Cancel', 'Kill it!' or 'Uh, what?'
# =>

many of these are obsolete since iOS 7

UIButton.custom => UIButton.buttonWithType(:custom.uibuttontype) UIButton.rounded => UIButton.buttonWithType(:rounded.uibuttontype) UIButton.rounded_rect => UIButton.buttonWithType(:rounded_rect.uibuttontype) UIButton.detail => UIButton.buttonWithType(:detail.uibuttontype) UIButton.detail_disclosure => UIButton.buttonWithType(:detail_disclosure.uibuttontype) => UIButton.buttonWithType(:info.uibuttontype) UIButton.info_light => UIButton.buttonWithType(:info_light.uibuttontype) UIButton.info_dark => UIButton.buttonWithType(:info_dark.uibuttontype) => UIButton.buttonWithType(:contact.uibuttontype) UIButton.contact_add => UIButton.buttonWithType(:contact_add.uibuttontype) UIButton.system => UIButton.buttonWithType(:system.uibuttontype)


Default frame is

[[0, 0], [0, 0]]
, but most containers will resize it to be the correct size. But heads up, it was
[[0, 0], [320, 480]]
(until the iphone 5 / 4-inch retina came out).
UITableView.alloc.initWithFrame([[0, 0], [0, 0]], style: :plain.uitableviewstyle)
UITableView.alloc.initWithFrame([[0, 0], [320, 480]], style: :plain.uitableviewstyle)
UITableView.alloc.initWithFrame([[0, 0], [320, 568]], style: :plain.uitableviewstyle)
# custom frame:
UITableView.alloc.initWithFrame([[0, 0], [320, 400]], style: :grouped.uitableviewstyle)


UITableView.plain UITableView.plain([[0, 0], [320, 480]]) UITableView.plain([[0, 0], [320, 568]])

custom frame:

UITableView.grouped([[0, 0], [320, 400]])

# factory methods, named for the cell style. cell identifier is required.

you can options for the common settings

cell = UITableViewCell.default('cell_identifier', accessory: :disclosure, selection: :blue, text: 'text', image: 'icon', # coerced into a UIImage )

control = UISegmentedControl.alloc.initItems(["one", "ah-two-whoo", "thr-r-r-ree"])
control.segmentedControlStyle = :bar.uisegmentedstyle

=>["one", "ah-two-whoo", "thr-r-r-ree"])

plain, bordered, and bezeled are the other types



UIActivityIndicatorView.white UIActivityIndicatorView.large UIActivityIndicatorView.gray


These factory methods accept a block, which will get wired up as a target/action.

# Get an instance containing the specified system item.
UIBarButtonItem.done do
  self.dismissViewControllerAnimated true, completion:nil
# =>
UIBarButtonItem.alloc.initWithBarButtonSystemItem(:done.uibarbuttonitem, target:self, action:"action:")
# with 'action' defined as:
def action(sender)
  self.dismissViewControllerAnimated true, completion:nil

the method names are 1::1 with the uibarbuttonitem constants in symbol.rb

UIBarButtonItem.cancel { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:cancel.uibarbuttonitem, target:self, action:"action:") UIBarButtonItem.edit { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:edit.uibarbuttonitem, target:self, action:"action:") { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:save.uibarbuttonitem, target:self, action:"action:") . . . UIBarButtonItem.page_curl { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:page_curl.uibarbuttonitem, target:self, action:"action:")

For custom

s, you can use the
# Create a UIBarButtonItem, specifying the title
UIBarButtonItem.titled('Close') do
  self.dismissViewControllerAnimated(true, completion:nil)
# =>
UIBarButtonItem.alloc.initWithTitle('Close', style: :bordered.uibarbuttonstyle, target:self, action:"action:")
def action(sender)
  self.dismissViewControllerAnimated(true, completion:nil)

You can also specify the style.

UIBarButtonItem.titled('Close', :plain) do # :plain, :bordered, :done



Or specify the image instead

UIBarButtonItem.imaged('close_icon') do # 'close_icon' will be coerced into a UIImage




UIBarButtonItem.alloc.initWithImage('Close'.uiimage, style: :bordered.uibarbuttonstyle, ...)

And, like titled, specify the style

UIBarButtonItem.imaged('close'.uiimage, :done) do



If you provide two images, they will be used as the portrait and landscape images

UIBarButtonItem.imaged(['portrait'.uiimage, 'landscape'.uiimage) do




UIBarButtonItem.alloc.initWithImage('portrait'.uiimage, landscapeImagePhone:'landscape'.uiimage, style: :bordered.uibarbuttonstyle, target:self, action:"action:")

Example Usage:

toolbar =
toolbar.items = [
  @image_picker_button = { presentImagePickerController(self) },
  @saveButton = { save_photo(self) }

Easy to create system or custom

UITabBarItem.titled('My Title')
# with optional :image and :selected_image options:
UITabBarItem.titled('My Title', image: 'my_icon', selected_image: 'my_icon_selected')
# also supports :tag and :badge
UITabBarItem.titled('My Title', tag: MY_TABBAR_ITEM, badge: '+1')

system items:

UITabBarItem.more UITabBarItem.favorites

Most of the UITabBarItem init methods accept the UIView#tag, and so there is

support for that in the UITabBarItem factory methods. Defaults to 0. The

:badge option is supported here as well

UITabBarItem.featured(tag: MY_TABBAR_ITEM, badge: 10)

All of the UITabBarSystemItem helpers delegate to the 'UITabBarItem.system'

method, which you can call direcly as well. It accepts :tag and :badge


UITabBarItem.system(:top_rated, tag: MY_ITEM_TAG, badge: 'hi')


WARNING: Breaking change in 3.3.0, this method name was

, but that caused conflicts with a bunch of 3rd party CocoaPods.
# usually, NSError.error doesn't work, because the only initializer for NSError
# needs more arguments.  This method passes some defaults in.
# same as =>
NSError.error('message', domain: 'Error', code: 0, userInfo: {})

WARNING: Breaking change in 3.3.0, this method name was

, but that caused conflicts with a bunch of 3rd party CocoaPods.
# supports text, font, and font size
UILabel.label('label text')
UILabel.label('label text'.attrd)  # detects attributed strings, too
UILabel.label('label text', 'Font name')  # You can pass just a font name
UILabel.label('label text', UIFont.fontWithName('Font name', size: 20))  # Or a UIFont object
UILabel.label('label text', 'Font name', 20)  # Or the name *and* the size

Animations (wiki)

require 'sugarcube-animations'

Careful, once you start using these helpers, you'll never go back.

view.move_to [100.0, 100.0] # origin
view.center_to [100.0, 100.0] # center
view.scale_to 2  # double the size, and preserves existing rotation transform
# view.scale_to 4 -> CGAffineTransformMakeScale(4, 4)
# view.scale_to [4, 3] -> CGAffineTransformMakeScale(4, 3)
view.slide :left, 100
view.rotate_to 180.degrees
view.shake  # great for showing invalid form elements
view.tumble  # great way to dismiss an alert-like-view
# tumbles in the other direction (towards the right side instead of left)
view.tumble(side: :right)
# wow, this is a SuperGoodDeleteWiggle!
# if you modify the AppDelegate to load the WiggleAnimationController you can
# see an example of this animation in action.

the complement to 'tumble' is 'tumble_in' - the view starts above the window

and drops in with the same kind of animation as 'tumble'. Before you call

this method, set the view.frame to the destination location.

view.tumble_in(side: :right)

These helpers all delegate to the

method, which accepts all the options that
accept. All options are optional, and they will play nicely inside an animation chain (see below, and the wiki page).
UIView.animate do
  view.alpha = 0

The "spring" animations use the method

, available in iOS 7. In testing, I've found this method to be slightly unreliable, so use with caution. To "enable" it, pass in the
option. You can also use
to set an initial velocity, if there is an animation in progress.
new_frame = [[110, 200], [100, 20]]

UIView.animate(damping: 0.1) do # default velocity is 0 view.frame = new_frame end


view.reframe_to(new_frame, damping: 0.1, velocity: 1)

The [wiki] page documents all the different animation methods, and documents animation chaining, which looks like this:

# fade out and slide left, then fade back in while returning to original position
UIView.animation_chain do
  view.slide :left
end.and_then do
  view.slide :right

Core Animation classes get some love, too!

view.layer.basic_animation('opacity', from: 0, to: 1, duration: 0.1)

Lots more information in the Wiki!


require 'sugarcube-modal'

It is nice that any

can present a modal, but if you have tabs or navs or crap in the way, this is actually NOT what you want. You should use the
(whatever it may be) to present to modal.

And since this is a property on

, which is more-or-less a constant, we can make this the easiest to do!
include SugarCube::Modal  # make these methods available globally

view_ctlr = present_modal(view_ctlr)

...later, when all is well...


These accept completion blocks:

present_modal(view_ctlr) { puts "Now You See Me!" }
dismiss_modal { puts "Now You Don't!" }

If you like these methods, but you want to specify the reciever, they are re-defined on

for this purpose:
controller.present_modal(other_controller) { puts "presented" }


require 'sugarcube-numbers'

Converting input


to try and parse a human-readable number string.
if input.nan?
  UIAlertView.alert('not a number!')
  number = input.to_number
  # convert a currency
  number = input.to_number(NSNumberFormatterCurrencyStyle)
  # convert from symbol, requires 'sugarcube-constants'
  number = input.to_number(:currency)

Pretty print numbers

Use NSNumberFormatter to easily format a number in the current locale

10000.string_with_style  # => "10,000"
10000.string_with_style(NSNumberFormatterCurrencyStyle)  # => "$10,000.00"
# will convert symbol-constants using the sugarcube-constants package, if it is available
10000.string_with_style(:currency)  # => "$10,000.00"


100.0.percent # => 1.00
55.0.percent # => 0.55


# some number-to-string stuff
1.nth  # => 'st'
2.nth  # => 'nd'
3.nth  # => 'rd'
4.nth  # => 'th'
11.nth  # => 'th'
13.nth  # => 'th'
21.nth  # => 'st'
23.nth  # => 'rd'


Since you always want to work in radians, calling

returns 10°, in radians. You can convert back to degrees using
. Lastly, you can specify a multiple of π as a number:
10.degrees  # => π / 18
45.degrees  # => π / 4
3.14159.to_degrees  # => approx 180
2.pi  # => 6.28318...


If you thought conversion from degrees to radians looks weird, you'll hate conversion from meters to miles:

distance = 1500  # this is in meters.  why?  because all the methods that return
                 # a "distance" return it in meters
distance = 2.miles  # => 3218.688, that's how many meters are in 2 miles
1500.in_miles  # converts meters to miles => 0.932056427001953


By now you have probably "gotten it" and are hooked on these number helpers. Heads up, though, some of these conflict with MotionSupport's definition.

1.second * 5.per_second = 5 * 3.per_hour = 72
1.year.in_minutes = 525960.0


Similar conversion methods for hard disk sizes. Uses the "mebi-byte" concepts, e.g. 1024 bytes in a kilobyte.

1.byte      # => 1
1.kilobyte  # => 1024
1.megabyte  # => 1048576
1.gigabyte  # => 1073741824
1.terabyte  # => 1099511627776
1.petabyte  # => 1125899906842624
1.exabyte   # => 1152921504606846976

1.megabyte.in_kilobytes # => 1024


1.pixel  # => 1 on non-retina, 0.5 on retina.
         # Useful when drawing if you want to specify the number of pixels


require 'sugarcube-attributedstring'

These are pretty fun! Check out [nsattributedstring_spec.rb][] for all the supported attributes (in theory they are all supported, but there's weird issues with missing constants).

'test'.nsattributedstring({})  #=> NSAttributedString.alloc.initWithString('test', attributes:{})
'test'.attrd  # => alias for `nsattributedstring`
'test'.bold  # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :bold.uifont})
'test'.italic  # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :italic.uifont})
'test'.underline  # => NSAttributedString.alloc.initWithString('test', attributes:{NSUnderlineStyleAttributeName => NSUnderlineStyleSingle})

you can chain 'em, too.


If you look up NSAttributedString Application Kit Additions, you can see all

the constants. Each of those has a method on NSAttributedString.

you can add 'em, but the FIRST one MUST be an NSAttributedString

'test'.attrd + '-ing'.italic

And there's where it gets FUN:

('This'.italic + ' is going to be ' + 'FUN'.bold).underline

and if you need to join a bunch of strings, there's a helper for that!

['This', 'is'.bold, 'handy!'].join_attrd(' ')

or join plain strings with an attributed string:

['a', 'b', 'c'].join_attrd('-'.bold)

join_attrd will always return an NSAttributedString

['a', 'b', 'c'].join_attrd(' ') # == NSAttributedString ('a b c')

You can even generate attributed text from html! This feature uses the

NSHTMLTextDocumentType option to convert the html to NSAttributedString

'Why on earth would you want to do that?'.attributed_html

And you can easily turn an attributed string into a label, if you include the

view << (("We just met\n".attrd +
          "and this is " + "CRAZY".italic + "\n"
          "But here's my " + "".monospace + " file,\n" +
          "so give me SSH access.").uilabel


require 'sugarcube-568'

If you

require 'sugarcube-568'
in your Rakefile, you can use
to load images that are specific to the 4" iphone.
'tall'.uiimage  # => UIImage.imageNamed('tall')
# => tall.png on iphone 3g
# => [email protected] on iphone 4
# => [email protected] on iphone 5

This code is ported from, which I had some problems with on RubyMotion (it worked, but not always. Very strange).


Methods to find document files, resource files, cache files, temporary files, access entries out of the Info.plist file, and write data/arrays/dictionaries to a file.

require 'sugarcube-files'
# file operations
"my.plist".file_exists?   # => NSFileManager.defaultManager.fileExistsAtPath("my.plist")

"my.plist".remove_file! # => NSFileManager.defaultManager.removeItemAtPath("my.plist".document, error: error) (returns error, if any occurred)

"my.plist".document_path # => NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist") "my.plist".cache_path # => NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist") "my.plist".temporary_path # => NSTemporaryDirectory().stringByAppendingPathComponent("my.plist")

all of these can be turned into a URL, too

"my.plist".temporary_path.file_url # => NSURL.fileURLWithPath("my.plist".temporary_path)

get the resource path, useful if you include json files or images you manipulate in the app

"my.plist".resource_path # => NSBundle.mainBundle.resourcePath.stringByAppendingPathComponent("my.plist")

same, but get a URL instead - often used to display a static HTML page that is stored in resources.

getting a path URL from a resource is just a little different from creating a URL from any other type of path

"index.html".resource_url # => NSBundle.mainBundle.URLForResource("index", withExtension:"html")

access data from Info.plist

"CFBundleVersion".info_plist # => NSBundle.mainBundle.infoDictionary["CFBundleVersion"]

write to file

[].write_to('array.plist'.document_path) array = NSArray.read_from('array.plist'.resource_path)

{}.write_to('dict.plist'.document_path) dict = NSDictionary.read_from('dict.plist'.resource_path)

data = UIImagePNGRepresentation('some_image'.uiimage)

using sugarcube-nsdata:

data = 'some_image'.uiimage.nsdata

data.write_to('some_image.png'.document_path) image_data = NSData.read_from('some_image.png'.document_path)


node_a = SKNode.node = 'parent'

node_b = SKNode.node = 'child' node_c = SKNode.node = 'child'

add child nodes

node_a << node_b node_a << node_c

set user data

node_a[:life] = 100

enumerate child nodes

node_a.each_named('child') do |node, stop_ptr| if node == node_b stop_ptr.value = true end end

node_a.run_action(SKAction.fadeOut) do

done fading out



require 'sugarcube-localized'
# NSLocalizedString from string
"hello".localized  # => NSBundle.mainBundle.localizedStringForKey("hello", value:nil, table:nil)
"hello"._          # == "hello".localized
"hello".localized('Hello!', 'hello_table')  # => ...("hello", value:'Hello!', table:'hello_table')

If you have an NSError object, you can retrieve the localizedDescription the same way:

error.localized error._


Shorthands and hash-like access to the coder/decoder objects.

require 'sugarcube-nscoder'
# hash access is the handiest
coder['key'] = self.value
@value = decoder['key']

if decoder.key?('key') value = decoder['key'] end

but if you want to store booleans and such (in their C form,

which will take up less space):

coder.set('sugarcube_is_neat', toBool: self.sugarcube_is_neat?) @sugarcube_is_neat = decoder.bool('sugarcube_is_neat')

coder.set('number_of_things', toInt:self.number_of_things) @number_of_things ='number_of_things')

Archiving and unarchiving is straightforward

archiving uses NSKeyedArchiver

NSCoder.archive(root_object) # returns NSData NSCoder.archive(root_object, to_file: 'foo'.document_path) # returns success boolean

unarchiving uses NSKeyedUnarchiver

NSCoder.unarchive(data) NSCoder.unarchive('foo'.document_path)

the entire list of encode/decode helpers:

coder.set(key, toBool:value) coder.set(key, toDouble:value) coder.set(key, toFloat:value) coder.set(key, toInt:value) coder.set(key, toPoint:value) coder.set(key, toRect:value) coder.set(key, toSize:value)

decoder.bool(key) decoder.double(key) decoder.float(key) decoder.point(key) decoder.rect(key) decoder.size(key)


require 'sugarcube-nsdata'

Going to and from

is really useful when doing HTTP posts.
# default string encoding is UTF8, you can pass other encodings to this method
string_data = 'String'.nsdata

PNG data representation

image = 'an image'.uiimage image_data = image.nsdata

this will download the URL contents

url = 'http://localhost'.nsurl url.nsdata # => NSData.dataWithContentsOfURL(self)

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

NSDate (wiki)

require 'sugarcube-nsdate'

This package includes additions to the

class, and related additions to
. There's a lot here, so check out the [wiki]NSDate Wiki for detailed information.


Smaller additions to the CoreFoundation classes. Some extensions, like

, are large enough that they get broken out into their own packages.

require 'sugarcube-foundation'
[1, 3].nsindexpath  # NSIndexPath.indexPathWithIndex(1).indexPathByAddingIndex(3)
[1, 3].nsindexset
[1, 3].nsset
index_set.to_a  # => [1, 2, ...]
index_path.to_a  # => [1, 2, ...]
'' + 'search terms'.escape_url  # => "..?q=search%20terms"
'%20'.unescape_url  #=> " "
'nô àccénts!'.remove_accents  # => "no accents!"
url = ''.nsurl
url.can_open?  # => true, it will open in safari  # opens in safari
url.nsurlrequest  # convert to NSURLRequest object


require 'sugarcube-indexpath

Use the

class to match
objects, for instance in a
index_path = [0, 2].nsindexpath
case index_path
when IndexPath[0]
when IndexPath[1, 0..5]
when IndexPath[1, 5..objects.length]
[0, 2].nsindexpath.to_a == [0, 2]  # => true


require 'sugarcube-nsuserdefaults'

This file does one thing very DANGEROUS... to "help" with defaults.

When storing

, it is converted into
, because Cocoa complains if you give it
, and the RubyMotion runtime refuses to allow the
object. Without relying on an external project (like nsnulldammit I don't know of a sensible workaround...

If you want to "tap into" the defaults system that SugarCube uses, add a

method and that will get called if you hand your object to
. However, there's no way to get it back later, so the usefulness of this is very limited.
NSUserDefaults['key'] = ['any', 'objects']  # => NSUserDefaults.standardUserDefaults.setObject(['any', 'objects'], forKey: :key)
NSUserDefaults['key']  # => NSUserDefaults.standardUserDefaults.objectForKey(:key)

symbols are converted to strings, so these are equivalent

NSUserDefaults[:key] = ['any', 'objects'] # => NSUserDefaults.standardUserDefaults.setObject(['any', 'objects'], forKey: :key) NSUserDefaults[:key] # => NSUserDefaults.standardUserDefaults.objectForKey(:key)

Keep in mind that NSUserDefaults serializes the object you pass to it, it doesn't maintain a reference. That means that if you modify an object in place, it will not get persisted. An example will explain this better:

NSUserDefaults['test'] = { my: 'test' }
NSUserDefaults['test']['my'] == 'test'
# NSUserDefaults['test'] returns the hash, and the 'my' key returns 'test', so
# this comparison returns `true`

but there is a temptation, perhaps, to modify that hash:

NSUserDefaults['test']['my'] = 'new' # BUG

the corrected code

test = NSUserDefaults['test'] test['my'] = 'new' NSUserDefaults['test'] = test # saved


This package is included by a few of the other packages, like repl, animations, and image.

Is it
? What arguments does

Instead, just use the coercion methods

. They will happily convert most sensible (and some non-sensible) arguments into a

These are namespaced in the

module, but I recommend you
include SugarCube::CoreGraphics
in app_delegate.rb.

For more CoreGraphics additions, you should use geomotion by Clay Allsopp. It adds methods to

, and
to make these structures more rubyesque (these methods used to be part of SugarCube, but were removed in an attempt to decrease the amount of duplicated code).
f = Rect(view.frame)  # the identity function - returns a copy of the CGRect
o = Point(view.frame.origin)  # returns a copy of CGPoint
s = Size(view.frame.size)  # returns a copy of CGSize

lots of other conversions are possible.

a UIView or CALayer => view.frame

f = Rect(view)

4 numbers

f = Rect(x, y, w, h)

or two arrays

f = Rect([x, y], [w, h])

one array

f = Rect([[x, y], [w, h]])

a CGPoint and CGSize

p = Point(x, y) # or just [x, y] works, too s = Size(w, h) # again, [w, h] is fine f = Rect(p, s)

any combination of point/array and size/array

f = Rect(p, [w, h]) f = Rect([x, y], s)


require 'sugarcube-base64'

Todo: add UIImage/NSImage support Todo: add Android support?

Uses the

methods to encode/decode base64 data. Normal use is to convert your image/binary data into an
instance, and then call
on that object.

There is a helper on

, so you can convert an
instance directly to base-64, using UTF8 encoding (or any encoding Apple supports).
base64_str = 'test string'.to_base64
NSString.from_base64(base64_str) == 'test string'

require 'sugarcube-nsdata'

image = 'some_image'.uiimage data = image.nsdata # defaults to PNG data base64_str = data.to_base64 ... data = NSData.from_base64(base64_str) image = data.uiimage # defaults to reading PNG data


require 'sugarcube-pointer'

These are not UIKit-related, so I reverted to Ruby's preferred

[0.0, 1.1, 2.2].to_pointer(:float)

is equivalent to

floats =, 3) floats[0] = 0.0 floats[1] = 1.1 floats[2] = 2.2


require 'sugarcube-to_s'

methods are defined on the following classes:
  • NSError
  • NSIndexPath
  • NSLayoutConstraint
  • NSNotification
  • NSSet
  • UIColor
  • UIEvent
  • UIView
  • UILabel
  • UITextField
  • UITouch
  • UIViewController

The output of these is (much?) more useful than the default.


require 'sugarcube-corelocation'

Open up

to provide handy-dandies
# distances

> denver_co =, -104.985223) => # > loveland_oh =, -84.257648) => # > denver_co.distance_to(loveland_oh) => 1779547.32010451 # in meters > denver_co.distance_to(loveland_oh).in_miles => 1105.75943993609

move around the globe using x/y distances in miles or kilometers

> denver_co.delta_miles(1101.6, -32.556) => #

our location is pretty close!

> denver_co.delta_miles(1101.6, -32.556).distance_to(loveland_oh).in_miles => 0.900871117223827

> denver_co.delta_kilometers(10, 10) # 10 kilometers east, 10 kilometers north => #


This package short-circuits the

operator to perform coercion and filtering between all sorts of objects.


Any object that defines a coercion method (image.uicolor, string.uiimage, :symbol.uifont) can use the

and the class name to perform the same method.
:label | UIFont  # => # :label.uifont
"image_name" | UIImage  # => "image_name".uiimage
view | UIImage | UIColor  # => view.uiimage.uicolor


You can pipe objects that have some idea of "filter", like using an image mask or image filter.

image | mask  # => image.masked(mask)
image | darken_cifilter  # => image.apply_filter(darken_cifilter)
# this one is... interesting!
"My name is Mud" | /\w+$/   # => "Mud"
"My name is Mud" | /\d+$/   # => nil
"My name is Mud" | "Mud"  # => "Mud"
"My name is Mud" | "Bob"    # => nil


require 'sugarcube-awesome'

SugarCube adds support for Motion-Awesome! The

method is added to
, which returns an NSAttributedString that uses the MotionAwesome font. You can pass in

is not required for this extension to function, but it adds
methods that really help. Below I'm usind
to construct an
# in Rakefile
require 'sugarcube-awesome'
require 'sugarcube-attributedstring'

in your app

label.attributedText = (:down_arrow.awesome_icon + ' Going down?'.bold).color(:white)

OR for buttons

button.setAttributedTitle(:twitter.awesome_icon, forState:UIControlStateNormal)


require 'sugarcube-anonymous'


es into an "anonymous object". Existing keys will be able to be accessed using method names. Uses the
class to accomplish this, though the usual interface is via
h = { foo: 'FOO', 'bar' => 'BAR' }.to_object

You can use methods instead of keys. # => h[:foo] # => h['bar'] = 'Foo' # => h[:foo] = 'Foo' = 'Bar' # => h['bar'] = 'Bar'

only existing keys are accessed this way

h.baz # => NoMethodError h.baz = 'baz' # => NoMethodError


require 'sugarcube-unholy'

I added these a long time ago to SugarCube, and so it's possible some people use these extensions. Honestly, I should have put them somewhere else, they are silly and not terribly useful, except maybe to me (I use them a lot!). :poop:

class Baz ; end
foo =

(:symbol || 'string').ivar

foo.instance_variable_set(:bar.ivar, value) # => foo.instance_variable_set(:@bar, value) foo.instance_variable_set(var_name.ivar, value) # => foo.instance_variable_set("@#{var_name}", value)

(:symbol || 'string').setter

foo.send(varname.setter, 'value')

(:symbol || 'string').cvar

Baz.class_variable_set(var_name.cvar, value) # => Baz.class_variable_set("@@#{var_name}", value)


require 'sugarcube-legacy'

This is where deprecated methods go to suffer a long, slow death.


If you want to see new features, please fork, commit, and pull-request! :smiley:

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.