A blog about iOS dev with RubyMotion

Paul Sturgess

How to Setup a Test Only Group in Bundler for RubyMotion

Coming from a Ruby on Rails background, it’s common place to see the Gemfile declarations in logical groups. This ensures your gems only get required in the environment they are needed.

A similar setup can be achieved in RubyMotion by tweaking your Gemfile and Rakefile.

In your Gemfile:

source "https://rubygems.org"
gem 'rake'
gem 'motion-cocoapods'

group :spec do
  gem 'motion-redgreen'
end

In your Rakefile:

if ARGV.join(' ') =~ /spec/
  Bundler.require :default, :spec
else
  Bundler.require
end

Thanks to the TinyMon application where I first saw this setup.

Using Native Objective-C Cocoapod Libraries in RubyMotion

Whilst RubyMotion is new, and the number of RubyMotion specific libraries is growing fast, there are already loads of native Objective-C libraries out there.

These instructions show you how to use Cocoapods in combination with Bundler.

Cocoapods is a dependency manager, like RubyGems, but for Objective-C projects.

In this example, I’ve chosen to install ViewDeck. ViewDeck makes it easy to implement the sliding panel user interface made popular by the Facebook iOS app.

The CocoaPods website is a great place to search for available ‘Pods’.

Summary of steps

  • Include the motion-cocoapods gem
  • Setup Cocoapods
  • Add ViewDeck to your application Rakefile

Bundler

If you haven’t got Bundler setup, I’ve written some instructions for using Bundler with RubyMotion.

Cocoapods

Add cocoapods to your Gemfile:

gem 'motion-cocoapods'

Install the gem via bundler:

$ bundle

Setup Cocoapods via:

$ pod setup

Add ViewDeck to your Rakefile

In your Rakefile you need to add the ViewDeck pod and QuartzCore Framework (required by ViewDeck):

Motion::Project::App.setup do |app|
  # Frameworks
  app.frameworks += [
    'QuartzCore'
  ]

  # Cocoapods
  app.pods do
    pod 'ViewDeck'
  end
end

ViewDeck will be automatically downloaded, built and linked the next time your build your app.

Using ViewDeck

I’ve ported the Objective-C example ViewDeck application over to RubyMotion.

Feel free to check it out.

Setting Up Bundler and RVM for a RubyMotion App

Create your rvmrc file via:

$ rvm use 1.9.3@yourgemsetname --create --rvmrc

Add bundler to your Rakefile

require 'bundler'
Bundler.require

Create your Gemfile via:

$ bundle init

Update your Gemfile

source "https://rubygems.org"
gem "bubble-wrap"

Install gems

$ bundle

You’re done.

Using RubyMotion to Provision an App Onto Your iPhone

So you’ve got your Apple developer account and now you want to get your RubyMotion app onto your iPhone.

At the end of these instructions you will be able to deploy multiple apps using the same provisioning profile. Ideal for prototyping.

Summary of what you need to do

  • Generate an iOS certificate
  • Create an App ID
  • Register your iPhone with your Apple Developer account
  • Create a Provisioning Profile
  • Update your RubyMotion Rakefile to use the Certificate and the Provisioning Profile

Generate an iOS certificate

Open the Keychain Access program on your Mac and from the dropdown menu choose:

Keychain Access > Certificate Assistant > Request a certificate from a certificate authority

The ‘common name’ is the name for your private key. You can choose whatever you like.

Just make sure you select to save to disk.

Now you need to sync this up with your Apple Developer account.

Visit The Apple iOS Dev Centre and go to the Certificates, Identities & Profiles section.

Go to Certificates > Development and select to add a new certificate. Follow the step process, uploading the certificate you just created.

At the end you need to download the .cer file that gets generated. Double click it to add to your Keychain.

Create an App ID

In that same section of the website you can create an App ID by going to Identifiers > App ID's.

I chose a name of exampleapp and opted for the Wildcard App ID. The wildcard ID means I don’t need to create a new App ID & Profile for each new app I want to try out on my iPhone.

Obviously when it comes to App Store submission, then it will make sense to have a dedicated App ID. Also Apple recommend a dedicated App ID if you’re testing advanced features like Push Notifications.

Register your iPhone with your Apple Developer account

Again staying on the iOS Dev Center website, you need to register all the devices you want to deploy your app onto.

You only need to do this once for each device, but you’ll need to know the UDID for each one.

I decided to install a handy free app (simply called UDID) that emails you this reference and a host of other info straight from your iPhone. There are loads of free apps that do similar things on the App Store.

Create a Provisioning Profile

The last task on the iOS Dev Center website is to create a Development Provisioning Profile.

All the instructions are self-explanatory so I won’t repeat them here.

Just make sure you download and double click the .mobileprovision file at the end.

Update your RubyMotion Rakefile to use the Certificate & Provisioning Profile

Update your Rakefile in your app:

Motion::Project::App.setup do |app|
  app.name = 'ExampleApp'
  app.identifier = 'com.yourdomain.exampleapp'
  app.codesign_certificate = 'iPhone Developer: Your Name (XXXXXXXXXX)'
  app.provisioning_profile = '/path/to/your/provisioning/profile/Example_App.mobileprovision'
end

Note that Wildcard App Id means you can use any name for the third part of the identifier.

Also for the codesign_certificate, you can view this in the Keychain Access program.

Finally deploy to the device via:

$ rake device

Objective-C for a Rubyist

RubyMotion does a great job of allowing iOS apps to be written in Ruby. However, whilst I want to avoid writing Objective-C, I do want to learn how to read it.

  • It’ll make it easier to learn Apple’s SDK
  • I want to be able to read existing iOS books/articles/stackoverflow solutions
  • It just seems like a good idea

Fortunately both languages stem from Smalltalk, so they’re not a million miles apart.

Instance variables

- (void)instanceVariable;
  • - means instance.
  • next is the return type: void which means it returns nothing.
  • Finally we have the method name, in this case instanceVariable.

Everything in Objective-C is camelCase. The common idiom in RubyMotion is to write Ruby in camel case where you are implementing classes that use Apple’s Objective-C methods. Reverting back to snake_case when the class is pure Ruby.

Class methods

+ (User *)userWithName:(NSString *)name;
  • + means class method
  • next is the return type. In this case a User pointer.
  • next is the method name: userWithName
  • next is a colon :, which means there is an argument.
  • next, in brackets, is the argument type. A pointer to an NSString instance.
  • Finally the argument variable name

So just be clear, in Ruby this is:

def self.userWithName(name)
    #...
end

Sending messages

As with all Smalltalk based languages, you are essentially creating methods in classes to send messages around. I believe Objective-C does have a dot notation, like Ruby, but most code examples I’ve come across use spaces and lots of square brackets.

For example in Objective-C sending the logOut message to a user object is:

[user logOut];

The Ruby equivalent:

user.logOut

To chain methods in Objective-C it looks like:

NSMutableArray *myArray = [NSMutableArray alloc] init];

This is equivalent to the Ruby:

myArray = NSMutableArray.alloc.init

reallyLongMethod:WithNamedParameters:

In Objective-C named parameters are heavily used. This is great for clarity, as they are intended to be as descriptive as possible. Removing the ambiguity is really good, but it is important to know that named parameters are actually included in the method name.

So an example Apple SDK method is tableView:numberOfRowsInSection:. Where the colons indicate an argument is required. So in this case, two. In Objective-C it looks like:

- (Integer) tableView(tableView, numberOfRowsInSection:section)

RubyMotion currently runs on Ruby 1.9.3, so named arguments have been added especially. The above method looks like the following in RubyMotion:

def tableView(tableView, numberOfRowsInSection: section)
  # ...
end

This can look a bit strange at times when the Apple SDK requires you to implement methods that start with the same name, but take different arguments. If you are not aware that the named named arguments are used in the method name, it actually looks like you’re implementing the same method multiple times.

For example, another Apple SDK method tableView:editingStyleForRowAtIndexPath: looks very similar in RubyMotion:

def tableView(tableView, editingStyleForRowAtIndexPath: indexPath)
  # ...
end

In summary

Objective-C is definitely more verbose, but I really like the RubyMotion implementation. There’s loads more to get my head around, but this is a good starting point.

Hello Octopress & Github Pages

Octopress is a static blog generator. It uses Jekyll which was created by Github to run Github Pages and now I’m using it to power my re-launched blog.

I’m attracted by the prospect of using Octopress because it’s dead simple. It generates the blog content as flat pages so it’s super fast. It allows me to write using Markdown and deploy via Git.

There’s no server setup and no hosting fees, as it’s hosted using Github Pages. Also it’s written in Ruby, so it works with all the tools I’m familiar with.

What follows is more for my reference than anything, so I can remember how I set things up.

Initial setup

Create a new Github repo named yourgithubusername.github.io.

The name is important here as Github Pages will automatically find this repo and serve up the content it finds in the master branch as your website at http://yourgithubusername.github.io.

Grab Octopress and change directory:

$ git clone git://github.com/imathis/octopress.git yourgithubusername.github.io
$ cd yourgithubusername.github.io

Octopress has its’ own rvmrc file, but I like to use gemsets, so I created my own before installing bundler and the required gems:

$ rvm use 1.9.3@yourgemsetname --create --rvmrc
$ gem install bundler
$ bundle install

Install the default theme:

$ rake install

Octopress has a configuration rake task that automatically sets the repo up for easy deployment to Github Pages:

$ rake setup_github_pages

This task does quite a few things. The most important is that it creates a new _deploy directory that is another git repository. This is where Octopress generates the flat website for deployment to the master branch of your repo on Github.

All the Octopress code used to generate the website into the _deploy directory now lives in new branch called source. Note in the source branch the .gitignore includes _deploy so it doesn’t get committed in two places!

This sounds more complicated than it is, Octopress has rake tasks to make this really easy to manage. It’s worth pushing up at this point to check everything works before tinkering:

$ rake generate
$ rake deploy

This copies the generated files into _deploy, adds them to git, commits and pushes them up to the master branch.

Visit http://yourgithubusername.github.io

Note at this point only the website has been committed, the source needs to be comitted separately via:

$ git add .
$ git commit -m 'Initial source commit'
$ git push origin source

Running Octopress locally

Octopress works really well with POW server.

$ cd ~/.pow
$ ln -s /path/to/your/octopress/site yoursitename

Now that you’re setup with POW, in the root of your source branch run:

$ rake watch

Load up http://yoursitename.dev

Theme customisation

I’m using the ‘Whitespace’ theme by lucaslew. Other themes are available.

I’ve tweaked the header to remove the search and include navigation links to my Twitter and Github accounts.

I installed the theme by running the following in the root of the source branch. Say yes when it asks you to overwrite existing files.

$ git clone git://github.com/lucaslew/whitespace.git .themes/whitespace
$ rake install['whitespace']
$ rake generate

_config.yml

This is where the main site configuration lives. Things like the blog title and various 3rd Party Settings, your Twitter and Github handles etc.

Changes to _config.yml will require you to restart the rake watch task if you’re using POW server.

Creating this post

As easy as:

rake new_post["Hello Octopress and Github pages"]

Deploying to Github Pages

$ rake generate
$ rake deploy

Just rememeber to manually commit changes made in the source branch.

Custom domain

Github have full details on how to do this in their GitHub Pages Documentation.

Inside your source branch run the following:

echo 'your-domain.com' >> source/CNAME

Regenerate your site and deploy up to Github. In your DNS settings point an A record (for your naked domain) to 204.232.175.78.

For www just point a CNAME record to yourgithubusername.github.io

Working from another machine

As the _deploy directory is in the .gitignore, the easiest thing is to clone the source branch and then setup the _deploy branch manually.

$ git clone -b source git@github.com:username/username.github.io.git username.github.io
$ cd username.github.io
$ bundle install
$ mkdir _deploy
$ cd _deploy
$ git init
$ git remote add origin git@github.com:username/username.github.io.git
$ git pull origin master
$ cd ..