Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RubyMotion: Put your Dreams in Motion with Ruby

RubyMotion: Put your Dreams in Motion with Ruby

Devcon Tlv 2013 presentation 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.

Astrails

June 20, 2013
Tweet

Other Decks in Programming

Transcript

  1. 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.
  2. 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.
  3. 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.
  4. New Toy shiny Monday, June 24, 13 Recently I had

    a similar experience, and now I have a new shiny toy to play with.
  5. http://www.flickr.com/photos/joriel/2839872192/sizes/l/ Monday, June 24, 13 So.. What am I going

    to talk about today? Those of you that payed attention to the conference program already know, for the rest it will be a pleasant surprise ;)
  6. 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.
  7. 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…
  8. 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.
  9. "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."
  10. 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:
  11. 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.
  12. 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.
  13. 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).
  14. 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.
  15. 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.
  16. rubygems Monday, June 24, 13 Oh, and I can use

    Rubygems to manage your application libraries.
  17. 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.
  18. 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.
  19. 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.
  20. • 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? ;)
  21. YES of course Monday, June 24, 13 Yes, of course.

    Just as with most everything in life, there are tradeoffs.
  22. expensive shit $200 Monday, June 24, 13 First of all

    this shit is expensive. $200 a piece expensive.
  23. 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.
  24. 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.
  25. 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.
  26. 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
  27. HTML/JS Monday, June 24, 13 Another thing is that you

    can use simple HTML and Javascript to develop your applications.
  28. 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.
  29. 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.
  30. 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.
  31. smalltalk Monday, June 24, 13 The message dispatch is quite

    similar in semantics, so that RubyMotion implements Ruby syntax by using native ObjectiveC internals.
  32. RubyMotion != Ruby Monday, June 24, 13 Its important to

    understand though that RubyMotion is not Ruby.
  33. 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.
  34. 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.
  35. ## 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.
  36. 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.
  37. # 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.
  38. 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.
  39. > motion create weather Create weather Create weather/.gitignore Create weather/app/app_delegate.rb

    Create weather/Rakefile Create weather/resources/[email protected] 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.
  40. > 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'.
  41. > 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
  42. > 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.
  43. > 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.
  44. # 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.
  45. > 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.
  46. # 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.
  47. 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.
  48. 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.
  49. @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.
  50. 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.
  51. # 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.
  52. @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.
  53. 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.
  54. 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.
  55. 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.
  56. • 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.
  57. 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.