DevCon Tlv 2013, by Vitaly Kushner
Dreaming of having your own app in the AppStore but dont know Objective C?
RubyMotion makes your dreams come true! You can start building native apps for OS X and iOS using Ruby language today!
We will introduce the toolchain and workflow, discuss compatability with native APIs and libraries, and compare RubyMotion to other alternatives.
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
RubyMotion: Put your Dreams in Motion with Ruby
1. Put Your Dreams in
Motion
with Ruby
Vitaly Kushner
@vkushner
Monday, June 24, 13
2. Vitaly Kushner
programming since middle 80s
professionally since early 90s
Rails since 2005
founded Astrails in 2008
Monday, June 24, 13
Hello everybody, my name is Vitaly Kushner. I'm a co-founder of Astrails. A Ruby on Rails consulting company.
For the last 8 years we’ve been building web applications using Ruby on Rails, but this is not what I’m going to talk about
today.
For a while I didn't know what to talk about.
4. http://www.flickr.com/photos/52462679@N06/5913851944
Monday, June 24, 13
Nah, everybody knows already that for most web applications Rails is the best tool for the job.
I wanted something more interesting.
So instead I decided to choose a topic that I'm much less of an expert in, actually not an expert at all, but
rather something that I'm currently learning and very excited about.
5. Rails
blog in 5 minutes
Monday, June 24, 13
In fact I’m as excited as I was back in 2005 when I saw for the first time the legendary "blog in
5 min" Rails screencast.
I remember when I saw it for the first time I decided right there that Rails will be the
framework for my next web project.
6. New Toy
shiny
Monday, June 24, 13
Recently I had a similar experience, and now I have a new shiny toy to play with.
8. RubyMotion
Monday, June 24, 13
We are going to talk about RubyMotion. What is it, why and when would you want to use it
and when not, and how it compares to alternatives.
9. Purpose?
Monday, June 24, 13
But first I'd like to talk about the purpose of this talk.
We don't have much time, so we are not going to go into much technical details. But I'll be
very glad if at least some of you will come back to work or home and decide to try
RubyMotion for your next great app.
so…
10. I hate IDEs
seriously, they are all crap
Monday, June 24, 13
For a long time I wanted to develop for iOS and OS X, and I even started to go through the
tutorials a couple of times, but I got frustrated every time. I got spoiled by the ruby
ecosystem, toolset and development process. To the point that dealing with the archaic
IDE was too much of a pain and in some ways reminded me of the bad days of my Windows
GUI programming.
Google for 'Xcode sucks' and you will find tens of thousands of people that agree with me.
Whenever I tried to follow Xcode tutorials, at some stage Xcode would just freeze and refuse
to continue. There is no need to bash Apple here though, the same shit happens with Eclipse
and any other IDS there is. They are just too big and complex to reliably work and allow me
to understand exactly what they do. They impose workflow on you that you can't change to
suit your needs.
So, frustrated, I've put away the iOS tutorials for a while.
And then I saw the RubyMotion screencast and I immediately felt the excitement that
reminded me of my first days of Rails.
12. "RubyMotion is a revolutionary toolchain
that lets you quickly develop and test
native iOS and OS X applications for
iPhone, iPad and Mac, all using the
awesome Ruby language you know and
love."
Monday, June 24, 13
"RubyMotion is a revolutionary toolchain that lets you quickly develop and test native iOS and
OS X applications for iPhone, iPad and Mac, all using the awesome Ruby language you know
and love."
13. Why RubyMotion?
Monday, June 24, 13
So why would you want to use RubyMotion instead of Objective C?
There are several reasons, but there is no a single killer feature. Instead the whole approach
to development and workflow is what makes RubyMotion so special. Its not the features, its
how it feels to build stuff with RubyMotion that makes the difference.
That being said, there are features too:
14. Ruby
Monday, June 24, 13
First of all it uses Ruby, which is a language that I love very much. The syntax is great and
very readable. the language is very powerful and allows you to do some very impressive feats.
Looking at Cocoa documentation and Objective C tutorials, you will find a lot of boilerplate
verbose code and archaic interfaces.
And if there is something Ruby community is allergic to its unnecessary boilerplate. So, as you
would expect, many of the Cocoa APIs have idiomatic Ruby wrappers. They reduce the amount
of code you need to write to use them by a whole lot.
15. Simple
and readable
Monday, June 24, 13
Another thing is that Ruby code is simpler and more readable as a whole. Objective C is a very
old language that also descends from C, so there is a lot of 'cruft' that was accumulated.
Apple is doing a great job of modernizing it lately, removing quite a bit of boilerplate code
that is no longer needed, but still, Objective C code is much less readable then Ruby, and
there is more of it. For example, in Objective C you need to declare interface for every class,
even if you only use it in a single place. in Ruby you just write your class.
16. REPL
Read Eval Print Loop
Monday, June 24, 13
Its hard to overstate the importance of Read-Eval-Print-Loop console (REPL). Its utility is
immediately obvious to anyone that programmed in a language that has it.
When you use RubyMotion you get a REPL with tab completion just like regular ruby's IRB. You
can poke inside your running application and call methods on your running application
objects while application is running. This is very very cool and improves the speed of
development quite a bit. Instead of recompiling for every simple change you can tweak things
from the console while the app is running until you are satisfied. Then you can incorporate
the changes into the source code.
There is a special REPL feature in RubyMotion that allows you to Command-click any UI
element in the emulator and have it’s context made available in the running console, I’m
going to show it to you later.
One of the biggest thing about RubyMotion is that it achieves all those cool things without
sacrificing performance. It compiles your application to the native code that runs as fast as if
you were writing it in Objective C (with one caveat I’ll mention later).
17. workflow
Monday, June 24, 13
Another very important thing is the workflow.
As I already said I hate IDEs. I spent quite a bit of time configuring my command line tools
and editor. RubyMotion allows me to continue to use the same tools I use for writing web
applications with Rails to develop applications for OS X and iOS. There are no configuration
dialogs for the application, all is done through simple ruby configuration files just like in
Rails. There are no big xml files to sift through. And its trivial to see the difference between
versions in source control.
18. rake
Monday, June 24, 13
The whole workflow is built around Rake - ruby's excellent build management tool.
To compile and run app on the emulator you just type 'rake' and it does the rest.
20. testing
Monday, June 24, 13
For various reasons most iOS developers do not use automated tests much. The tools exist,
but they are not as pervasive and advanced as in the Ruby land. And RubyMotion comes with
an Rspec like testing and UI automation framework that you can use to test your applications.
No more mindless clicking to test the most basic flows. You will of course still need to
actually use the app, but a lot of functionality can be tested by the framework, without human
intervention.
21. community
Monday, June 24, 13
In addition to already huge Objective C community, there is a new and growing RubyMotion
community. And Ruby developers are known to produce some pretty innovative libraries and
tools.
22. JoyBox
http://joybox.io
Monday, June 24, 13
For example, there is a library called JoyBox (http://joybox.io), which is a game wrapper for
RubyMotion. I suggest you find a JoyBox REPL demo video on Vimeo. its amazing how you can
do very impressive things with just a line of ruby.
23. • write less code
• use better tools
• have more fun
Monday, June 24, 13
Did I mention that its actually a lot of fun programming in RybyMotion? ;)
27. http://www.flickr.com/photos/68751915@N05/6355811869
Monday, June 24, 13
Its a commercial product. While most of the toolchain and workflow tools are open source the
compiler itself is the 'secret souse' and it costs money.
So this kind of puts it out of the 'I just want to fool with it' category. On the other hand Apple
developers already pay to $100 to Apple for the access to the development platform, so this
isn't a big deal. In any kind of commercial environment, the benefits of RubyMotion will pay
for its price many times over.
28. downsides?
• expensive
• no low level data access
• no static checks during compilation
Monday, June 24, 13
Second, Ruby doesn't give you low level bit access to the native memory, like C does. so if you
are writing a 3D game with lots of graphics processing, RubyMotion might not be a good fit.
2D games are perfectly OK though (see JoyBox).
That being said, RubyMotion can call any function available from Objective-C. So you can
localize your hard-core data processing into a simple Objective-C lib, then drive it with the
rest of the UI from RubyMotion.
Also, as with all dynamic languages, you loose static type checks by compiler. if you have a
typo in a variable name you will find out at runtime, not during compilation.
29. Alternatives
Phonegap, Titanium
Monday, June 24, 13
We of course can't ignore the alternatives, so I'd like to dedicate a bit of time to discuss them.
There were other solutions available, like Phonegap and Titanium.
30. multi-platform
Monday, June 24, 13
The big selling point for those is that they are multi platform. So that you can theoretically
reuse a lot of the code to support both iOS and Android platforms
31. HTML/JS
Monday, June 24, 13
Another thing is that you can use simple HTML and Javascript to develop your applications.
33. No native API access
Monday, June 24, 13
But those very same benefits are also the biggest downside. You do not talk directly to your
runtime, you talk to the library which in turns talks to the OS. So if some API call is not
supported by the wrapper, you don't get to call it. Also, while HTML/JS is a viable solution for
many applications, it is very limiting in what you can do. Where RubyMotion can accommodate
all but the most graphics and data intensive applications like 3D games, html/js apps simply
can't deliver the same slick UI you might want to implement for your native application.
Its really easy to develop applications for those platforms because the APIs are much simpler
then the native ones, but it just means that you have much less APIs to work with. Lots of
things are impossible to do.
34. RubyMotion is Native
Monday, June 24, 13
RubyMotion on the other hand has all the native APIs.
While it wraps some of the API's into idiomatic Ruby interfaces It also makes all of Apple's
APIs available.
For example, if Apple releases NFC API tomorrow you can start using it the same day, you
don't need to wait until some 3rd party provides you with a wrapper. You can wrap it with
idiomatic Ruby yourself, or just go and use the API directly. Your choice.
35. RubyMotion is FAST
Monday, June 24, 13
As I already mentioned RubyMotion is fast. Almost as fast as Objective C. IT compiles your
Ruby code to native executable.
How does it do it? Its quite ingenious in fact. And its only possible because Objective C and
Ruby are very similar in many respects. They both descend from Smalltalk and it shows.
36. smalltalk
Monday, June 24, 13
The message dispatch is quite similar in semantics, so that RubyMotion implements Ruby
syntax by using native ObjectiveC internals.
38. no eval
Monday, June 24, 13
Some parts of ruby are made unavailable. For example, there is no 'eval', but that has more to
do with Apple's AppStore guidelines then with technical limitations. Also there is no 'require',
but we'll get to this a bit later.
39. named parameters
Monday, June 24, 13
Some of the syntax was changed to support platform features. For example, Objective C code
uses named parameters. And in Ruby they are only available since Ruby 2.0. RubyMotion
changed ruby syntax to support named parameters from the beginning.
40. ## Objective C
NSError *error = nil;
NSData *data = [[NSData alloc]
initWithContentsOfFile: answerFile,
options: NSDataReadingUncached,
error: &error];
# Same in Ruby
error = Pointer.new(:object)
data = NSData.alloc.initWithContentsOfFile(answerFile,
options:NSDataReadingUncached,
error: error)
# Dereferencing error
do_something_with_error error[0]
Monday, June 24, 13
To show you an example, here is a typical Objective C call that constructs an NSData object
from a content of a file:
Two things to note here: use of error pointer and named arguments.
To support this frequently used ObjectiveC idiom of error pointer RubyMotion introduces
Pointer class, which encapsulates the functionality, and lets you de-reference the pointer
using ruby array syntax.
we can dereference the error pointer using array syntax.
41. blocks
Monday, June 24, 13
It is actually quite remarkable how little changes had to be done to Ruby syntax to allow
native Objective C interface support. There is another cool Objective C feature that directly
maps into ruby: blocks.
42. # block in Objective C
[UIView animateWithDuration: 1.0
animations: ^{
@label.alpha = 1
}];
# block in Ruby
UIView.animateWithDuration(1.0,
animations: ->{
@label.alpha = 1
})
Monday, June 24, 13
Lets see another typical Objective C code snippet. This time we 'animate' a text label:
This is very similar to Ruby blocks, just a bit different syntax.
As you can see it is quite trivial to translate Objective C code into Ruby.
Thats why you don't need special adopted documentation. You can just use the regular API
docs and translate the syntax to ruby on the fly.
That being said, RubyMotion comes with lots of Apple API docs translated and accessible to
RubyMotion version of Ruby "ri" documentation reader.
43. magic
Monday, June 24, 13
But enough of talking, lets see how the magic happens.
We will create a very simple iOS application. Creating a hello world is trivial, but that would be
too boring, so we will do something a little more interesting. We will create an app that finds
out your current GPS location, and then requests weather information about the location.
45. > motion create weather
Create weather
Create weather/.gitignore
Create weather/app/app_delegate.rb
Create weather/Rakefile
Create weather/resources/Default-568h@2x.png
Create weather/spec/main_spec.rb
Monday, June 24, 13
Note: since we don't have much time I won't explain every little detail.
When you install RubyMotion you get the 'motion' command line tool that does most of the
work.
To create a new application you just write 'motion create AppName'.
As you can see, just like Rails, RubyMotion creates a skeleton application with some basic
tests.
Lets review the files.
46. > cat Rakefile
# -*- coding: utf-8 -*-
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project/template/ios'
Motion::Project::App.setup do |app|
# Use `rake config' to see complete project settings.
app.name = 'weather'
end
Monday, June 24, 13
Rakefile contains the application configuration block. You can see what configuration options
are available by running 'rake config'.
48. > rake -T
rake archive # Create an .ipa archive
rake archive:distribution # Create an .ipa archive for distribution (AppStore)
rake build # Build everything
rake build:device # Build the device version
rake build:simulator # Build the simulator version
rake clean # Clear build objects
rake config # Show project config
rake ctags # Generate ctags
rake default # Build the project, then run the simulator
rake device # Deploy on the device
rake simulator # Run the simulator
rake spec # Same as 'spec:simulator'
rake spec:device # Run the test/spec suite on the device
rake spec:simulator # Run the test/spec suite on the simulator
rake static # Create a .a static library
Monday, June 24, 13
You can see other commands by running rake -T:
I suggest you always run 'rake crags' to build tags database.
to run the app you just run rake.
49. > rake config
background_modes : []
build_dir : "./build"
codesign_certificate : "Error"
delegate_class : "AppDelegate"
deployment_target : "6.1"
device_family : :iphone
entitlements : {}
files : ["./app/app_delegate.rb"]
fonts : []
framework_search_paths : []
frameworks : ["UIKit", "Foundation", "CoreGraphics"]
icons : []
identifier : "com.yourcompany.weather"
interface_orientations : [:portrait, :landscape_left, :landscape_right]
libs : []
...
Monday, June 24, 13
“delegate_class” config is site to “AppDelegate” by default. This is the name of the class that
will be instantiated by the environment and receive lifecycle callbacks.
50. # app/app_delegate.rb
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
true
end
end
Monday, June 24, 13
Lets check out the AppDelagate class. It is placed in “app/app_delegate.rb”.
As you can see it doesn't do anything yet.
51. > rake config
background_modes : []
build_dir : "./build"
codesign_certificate : "Error"
delegate_class : "AppDelegate"
deployment_target : "6.1"
device_family : :iphone
entitlements : {}
files : ["./app/app_delegate.rb"]
fonts : []
framework_search_paths : []
frameworks : ["UIKit", "Foundation", "CoreGraphics"]
icons : []
identifier : "com.yourcompany.weather"
interface_orientations : [:portrait, :landscape_left, :landscape_right]
libs : []
...
Monday, June 24, 13
Another thing in config is “icons”. It is blank by default. Lets change it.
52. # copy icon file into resources directory
> cp ../icon.png resources
# add icon filename to app.icons in Rakefile
app.icons << 'icon.png'
Monday, June 24, 13
We need to copy the icon png file into the resources directory.
53. Monday, June 24, 13
As you can see our app has a custom icon now.
55. class AppDelegate
def application(application,
didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.backgroundColor = UIColor.lightGrayColor
@window.rootViewController = WeatherController.alloc.init
@window.makeKeyAndVisible
true
end
end
# app/weather_controller.rb
class WeatherController < UIViewController
def viewDidLoad
@label = UILabel.alloc.initWithFrame([[10, 10], [300, 50]])
@label.text = "DevCon 2013"
@label.textColor = UIColor.darkGrayColor
@label.backgroundColor = UIColor.orangeColor
@label.textAlignment = UITextAlignmentCenter
view.addSubview @label
end
end
Monday, June 24, 13
Cocoa is an MVC framework, so now we need a controller. we will put it into app/
weather_controller.rb:
We inherit from UIViewController. It will create a view for us by default, and viewDidLoad
method will be called once the view is loaded.
Here we can initialize the rest of the application. Lets add a tex label.
56. def viewDidLoad
@label = setup_label [[10, 10], [300, 50]], UIColor.orangeColor
@label.text = "DevCon 2013"
end
def setup_label frame, bgcolor
label = UILabel.alloc.initWithFrame(frame)
label.textColor = UIColor.darkGrayColor
label.backgroundColor = bgcolor
label.textAlignment = UITextAlignmentCenter
view.addSubview label
label
end
Monday, June 24, 13
Lets refactor it a bit to prepare for multiple labels that we need.
57. @name_label = setup_label [[10, 10], [300, 50]], UIColor.orangeColor
@place_label = setup_label [[10, 80], [300, 50]], UIColor.yellowColor
@temp_label = setup_label [[10, 150], [300, 50]], UIColor.greenColor
Monday, June 24, 13
Here you can see we created 3 labels of different colors.
58. Bubble Wrap
http://bubblewrap.io
http://rubymotion-wrappers.com
Monday, June 24, 13
So far we used Objective-C API as is, which is not very ruby like. Lets see how better can it be
by using idiomatic Ruby.
RubyMotion has quite a bit of “wrappers” available. Ruby libraries that provide a more ruby-
like interface to common APIs.
You can find many wrappers on http://rubymotion-wrappers.com and simply on github.
BubbleWrap (http://bubblewrap.io) is one of the basic ones. it wraps Cocoa Touch into nice
ruby APIs.
59. # Gemfile
source 'https://rubygems.org'
gem 'rake'
gem 'bubble-wrap'
# Rakefile
require 'bundler'
Bundler.require
require 'bubble-wrap/all'
Monday, June 24, 13
As mentioned before, RubyMotion doesn’t have “require” support.
So instead of requiring your libraries from your RubyMotion code, you do it in your Rakefile,
where it becomes the part of the build.
We will of course use Rubygems and Bundler to manage our libraries.
60. @name_label = setup_label [[10, 10], [300, 50]], 'orange'
@place_label = setup_label [[10, 80], [300, 50]], 'yellow'
@temp_label = setup_label [[10, 150], [300, 50]], 'green'
label.textColor = 'dark_gray'.to_color
label.backgroundColor = bgcolor.to_color
Monday, June 24, 13
Now we can use some ruby goodies. First lest try something simple, like String#to_color.
61. def viewDidLoad
...
get_location
end
def get_location
BW::Location.get_once do |loc|
puts loc.inspect
end
end
Monday, June 24, 13
But that is not what we added BubbleWrap for.
Lets try the Location services. Using natie API that would be a screenful of code. Using
BubbleWrap its a one liner.
You can see that the application now asks for permission to access location data.
62. def get_location
BW::Location.get_once do |loc|
get_weather loc.latitude, loc.longitude
end
end
def get_weather lat, lon
BW::HTTP.get(
"http://api.openweathermap.org/data/2.5/weather?lat=#{lat}
&lon=#{lon}"
) do |res|
puts res.inspect
end
end
Monday, June 24, 13
Now that we have location we can fetch weather information. We will use
openweathermap.org API for that.
And we will use bubble-wrap HTTP wrapper to fetch it.
63. def get_weather lat, lon
...
update_weather res.body.to_str
...
end
def update_weather json
res = BW::JSON.parse(json)
name = res['name']
weather = res['weather'][0]['description']
temp = res['main']['temp'] - 273.15
@place_label.text = name
@weather_label.text = weather
@temp_label.text = "%f.2" % temp
end
Monday, June 24, 13
Now that we have the weather json response, lets parse it and update our labels with the
information.
Note that even such a simple thing as JSON parse would be much more verbose without
BubbleWrap.
64. • http://blog.rubymotion.com
• http://rubymotion-tutorial.com
• https://learn.thoughtbot.com/rubymotion
Monday, June 24, 13
For the end a couple of useful resources for you to learn RubyMotion.
The official blog is something that you will want to follow http://blog.rubymotion.com when
developing with RubyMotion.
http://rubymotion-tutorial.com is a nice place to start.
https://learn.thoughtbot.com/rubymotion is the “things to do/read to lean” list for
RubyMotion from ThoughtBot.
65. Thank you!
Slides and video will be published at
http://astrails.com/blog
Vitaly Kushner
@vkushner
Monday, June 24, 13
As mentioned before the slides and the video will be posted on our blog at http://
astrails.com/blog
Follow me on twitter (@vkusher) to be notified about new presentations, updates to “The Rails
4 Way” book that I co-authored with Obie Fernandez and our open source libraries.