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

Building iOS Apps With RubyMotion

Ray Hightower
October 06, 2012

Building iOS Apps With RubyMotion

RubyMotion lets developers write native iOS apps using the Ruby programming language. Ray Hightower delivered this presentation at MagicRuby and Aloha Ruby in October 2012. Video is available at RayHightower.com.

Ray Hightower

October 06, 2012
Tweet

More Decks by Ray Hightower

Other Decks in Technology

Transcript

  1. Building iOS Apps
    With RubyMotion
    Aloha Ruby
    October 8-9, 2012
    Honolulu, HI, USA

    View Slide

  2. @RayHightower
    WisdomGroup.com

    View Slide

  3. What
    Why
    How
    Q & A

    View Slide

  4. What

    View Slide

  5. Xcode
    +
    +
    Editor

    View Slide

  6. Why

    View Slide

  7. If you need a
    mobile MVP
    right now.

    View Slide

  8. If you want to
    learn more about
    Ruby.

    View Slide

  9. Why not?

    View Slide

  10. Ruby’s future
    on iOS?

    View Slide

  11. How

    View Slide

  12. ~/Code/Ruby/RubyMotion/helloruby$ rake
    Build ./build/iPhoneSimulator-6.0-Development
    Compile ./app/app_delegate.rb
    Compile ./app/home_controller.rb
    Link ./build/iPhoneSimulator-6.0-Development/helloruby.app/helloruby
    Create ./build/iPhoneSimulator-6.0-Development/helloruby.dSYM
    Simulate ./build/iPhoneSimulator-6.0-Development/helloruby.app
    (main)>

    View Slide

  13. ~/Code/Ruby/RubyMotion$ motion create helloruby
    Create helloruby
    Create helloruby/.gitignore
    Create helloruby/Rakefile
    Create helloruby/app
    Create helloruby/app/app_delegate.rb
    Create helloruby/resources
    Create helloruby/spec
    Create helloruby/spec/main_spec.rb
    ~/Code/Ruby/RubyMotion$

    View Slide

  14. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  15. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  16. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  17. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  18. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  19. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    1 class AppDelegate

    View Slide

  20. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    2 def application(application,
    didFinishLaunchingWithOptions:launchOptions)

    View Slide

  21. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    3 @window = UIWindow.alloc.initWithFrame
    (UIScreen.mainScreen.bounds)

    View Slide

  22. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    4 @window.rootViewController =
    HomeController.new

    View Slide

  23. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    5 @window.makeKeyAndVisible

    View Slide

  24. 1 class AppDelegate
    2 def application(application, didFinishLaunchingWithOptions:launchOptions)
    3 @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    4 @window.rootViewController = HomeController.new
    5 @window.makeKeyAndVisible
    6
    7 @window.backgroundColor = UIColor.grayColor
    8
    9 true
    10 end
    11 end
    7 @window.backgroundColor =
    UIColor.grayColor

    View Slide

  25. ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # !"" app_delegate.rb
    # $"" home_controller.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 4 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  26. 1 class HomeController < UIViewController
    2 def loadView
    3 self.view = UIView.alloc.init
    4 end
    5
    6 def viewDidLoad
    7 label = UILabel.alloc.initWithFrame([[15,100], [280,140]])
    8 label.text = "Hello MagicRuby!"
    9 label.font = UIFont.boldSystemFontOfSize(25)
    10 label.textColor = UIColor.blueColor
    11 label.textAlignment = UITextAlignmentCenter
    12 view.addSubview(label)
    13 end
    14
    15 end
    1 class HomeController < UIViewController

    View Slide

  27. 1 class HomeController < UIViewController
    2 def loadView
    3 self.view = UIView.alloc.init
    4 end
    5
    6 def viewDidLoad
    7 label = UILabel.alloc.initWithFrame([[15,100], [280,140]])
    8 label.text = "Hello Ruby!"
    9 label.font = UIFont.boldSystemFontOfSize(25)
    10 label.textColor = UIColor.blueColor
    11 label.textAlignment = UITextAlignmentCenter
    12 view.addSubview(label)
    13 end
    14
    15 end
    2 def loadView

    View Slide

  28. 1 class HomeController < UIViewController
    2 def loadView
    3 self.view = UIView.alloc.init
    4 end
    5
    6 def viewDidLoad
    7 label = UILabel.alloc.initWithFrame([[15,100], [280,140]])
    8 label.text = "Hello Ruby!"
    9 label.font = UIFont.boldSystemFontOfSize(25)
    10 label.textColor = UIColor.blueColor
    11 label.textAlignment = UITextAlignmentCenter
    12 view.addSubview(label)
    13 end
    14
    15 end
    6 def viewDidLoad

    View Slide

  29. 1 class HomeController < UIViewController
    2 def loadView
    3 self.view = UIView.alloc.init
    4 end
    5
    6 def viewDidLoad
    7 label = UILabel.alloc.initWithFrame([[15,100], [280,140]])
    8 label.text = "Hello Ruby!"
    9 label.font = UIFont.boldSystemFontOfSize(25)
    10 label.textColor = UIColor.blueColor
    11 label.textAlignment = UITextAlignmentCenter
    12 view.addSubview(label)
    13 end
    14
    15 end
    7 label =
    UILabel.alloc.initWithFrame(
    [[15,100],[280,140]])

    View Slide

  30. What
    about
    UX?

    View Slide

  31. Human Interface Guidelines
    (HIG)

    View Slide

  32. http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIKit_Framework/Introduction/Introduction.html
    UIKit

    View Slide

  33. http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIKit_Framework/Introduction/Introduction.html
    UIKit

    View Slide

  34. NSObject
    UIViewController
    UIWindow
    UIKit
    UIView
    UILabel
    UITableView

    View Slide

  35. 3: Fizz
    5: Buzz
    15: FizzBuzz

    View Slide

  36. Interface Builder
    .xib files

    View Slide

  37. view.viewWithTag 1

    View Slide

  38. view.viewWithTag 2

    View Slide

  39. view.viewWithTag 3

    View Slide

  40. view.viewWithTag 4

    View Slide

  41. ~/Code/Ruby/RubyMotion$ cd helloruby/
    ~/Code/Ruby/RubyMotion/helloruby$ tree
    .
    !"" Rakefile
    !"" app
    # $"" app_delegate.rb
    !"" resources
    $"" spec
    $"" main_spec.rb
    3 directories, 3 files
    ~/Code/Ruby/RubyMotion/helloruby$

    View Slide

  42. resources/fbib.xib

    View Slide

  43. 1 class FizzBuzzViewController < UIViewController
    2
    3 def loadView
    4 views = NSBundle.mainBundle.loadNibNamed "fbib", owner:self,
    options:nil
    5 self.view = views[0]
    6 @counter = 0
    7 @view_handle = self.view
    8 end
    4 views = NSBundle.mainBundle.loadNibNamed"fbib",
    owner:self, options:nil

    View Slide

  44. 10 def viewDidLoad
    11 @label = view.viewWithTag 1
    12 plus_button = view.viewWithTag 2
    13 minus_button = view.viewWithTag 3
    14 reset_button = view.viewWithTag 4
    15 end

    View Slide

  45. TDD
    MacBacon, Guard,
    & rm-redgreen

    View Slide

  46. ~/Code/Ruby/RubyMotion/fizzbuzzrm[master]$ tree
    .
    !"" Gemfile
    !"" Gemfile.lock
    !"" Guardfile
    !"" Rakefile
    !"" app
    # !"" app.rb
    # !"" app_delegate.rb
    # !"" fizzbuzz_view_controller.rb
    # !"" home_controller.rb
    # !"" kernel.rb
    # !"" rm-ansiterm.rb
    # $"" string.rb
    !"" interfaces
    !"" resources
    # !"" f.png
    # !"" fbib.xib
    # !"" fizzbuzzbackground.jpg
    # $"" fizzbuzzbackground.png
    $"" spec
    !"" 00-redgreen.rb
    !"" home_controller_spec.rb
    $"" main_spec.rb
    4 directories, 18 files
    ~/Code/Ruby/RubyMotion/fizzbuzzrm[master]$
    $" spec
    !" 00-redgreen.rb
    !" home_controller_spec.rb
    $" main_spec.rb

    View Slide

  47. 1 describe "FizzBuzz Calculator Function" do
    2 before do
    3 @this_number = 38
    4 end
    5
    ...
    17
    18 (1..10).each do |this_number|
    19 if this_number % 15 == 0
    20 it 'should return buzz for multiples of 15' do
    21 HomeController.fizzbuzz_calc(this_number).should == 'fizzbuzz'
    22 end
    23 elsif this_number % 3 == 0
    24 it 'should return fizz for multiples of 3' do
    25 HomeController.fizzbuzz_calc(this_number).should == 'fizz'
    26 end
    27 elsif this_number % 5 == 0
    28 it 'should return buzz for multiples of 5' do
    29 HomeController.fizzbuzz_calc(this_number).should == 'buzz'
    30 end
    31 else
    32 it 'should return the original number' do
    33 HomeController.fizzbuzz_calc(this_number).should == this_number
    34 end
    35 end
    36 end
    37 end
    home_controller_spec.rb

    View Slide

  48. describe "FizzBuzz Calculator Function" do
    before do
    @this_number = 38
    end
    ...
    (1..10).each do |this_number|
    if this_number % 15 == 0
    it 'should return buzz for mults of 15' do
    HomeController.fizzbuzz_calc(this_number)
    .should == 'fizzbuzz'
    end
    home_controller_spec.rb

    View Slide

  49. $ gem install formotion

    View Slide

  50. 1 $:.unshift("/Library/RubyMotion/lib")
    2 require 'motion/project'
    3 require "bundler/gem_tasks"
    4 require "bundler/setup"
    5
    6 $:.unshift("./lib/")
    7 require './lib/formotion'
    8
    9 Motion::Project::App.setup do |app|
    10 # Use `rake config' for project settings.
    11 app.name = 'Formotion'
    12 end
    Rakefile
    Source: http://clayallsopp.com

    View Slide

  51. 1 class LoginController < Formotion::FormController
    2 def init
    3 form = Formotion::Form.new({
    4 title: "Login",
    5 sections: [{
    6 rows: [{
    7 title: "User Name",
    8 type: :string,
    9 placeholder: "name",
    10 key: :user
    11 }, {
    12 ...
    login_controller.rb
    Source: http://clayallsopp.com

    View Slide

  52. Source: http://clayallsopp.com

    View Slide

  53. Source: http://clayallsopp.com

    View Slide

  54. $ gem install bubble-wrap

    View Slide

  55. // Objective-C
    [button addTarget:self
    action:@selector(buttonTapped:) forControlEvents:
    UIControlEventTouchUpInside];
    - (void)buttonTapped:(id)sender {
    self.view.backgroundColor =
    [UIColor redColor];
    }
    # RubyMotion with BubbleWrap
    button.when(UIControlEventTouchUpInside) do
    self.view.backgroundColor = UIColor.redColor
    end
    Source: http://clayallsopp.com/posts/the-ruby-motion-way/

    View Slide

  56. 2 $:.unshift("/Library/RubyMotion/lib")
    3 require 'motion/project'
    4 require 'bubble-wrap/core'
    5 require 'bubble-wrap/http'
    6
    7 Motion::Project::App.setup do |app|
    8 # Use `rake config'...
    9 app.name = 'NSScreencast'
    10 end
    Rakefile
    Source: Ben Scheirman of http://nsscreencast.com/

    View Slide

  57. 1 class ApiClient
    2 def self.fetch_episodes(&block)
    3 @myurl = "http://nsscreencast.com/api/episodes.json"
    4 BubbleWrap::HTTP.get(@myurl) do |response|
    5 if response.ok?
    6 json = BubbleWrap::JSON.parse(response.body)
    7 episodes = json.map {|ej| Episode.from_json(ej["episode"])}
    8 block.call(true, episodes)
    9 else
    10 block.call(false, nil)
    11 end
    12 end
    13 end
    14 end
    api_client.rb
    Source: Ben Scheirman of http://nsscreencast.com/

    View Slide

  58. Source: Ben Scheirman of http://nsscreencast.com/

    View Slide

  59. Ruby Tools
    with RubyMotion

    View Slide

  60. Ruby Version Manager
    (RVM)

    View Slide

  61. $ gem install cupertino

    View Slide

  62. ~/Code/Ruby/RubyMotion$ ios profiles:list
    +----------------------------------+--------------+---------+
    | Profile | App ID | Status |
    +----------------------------------+--------------+---------+
    | WisdomGroup iOS Development | ABCDEFGHIJ.* | Active |
    | WisdomGroup RubyMotion | ABCDEFGHIJ.* | Active |
    | ChicagoRubyRubyMotion iPad | ABCDEFGHIJ.* | Active |
    | iOS Team Provisioning Profile: * | ABCDEFGHIJ.* | Active |
    | RTHiPhone4S | ABCDEFGHIJ.* | Active |
    +----------------------------------+--------------+---------+
    ~/Code/Ruby/RubyMotion$ ios help

    View Slide

  63. Auto Layout
    ARC

    View Slide

  64. RubyMotion
    or
    Objective-C ?

    View Slide

  65. Resources
    http://rubymotion-tutorial.com
    Multi-page tutorial by Clay Allsopp. Also see http://clayallsopp.com
    http://pragmaticstudio.com/screencasts/rubymotion
    Pragmatic Studio’s intro to RubyMotion (free) plus a paid intro to Ruby.
    http://chicagoruby.org/videos/archives/2012/09/04/rubymotion-for-rubyists/
    Bill Svec builds a simple RubyMotion weather app in about 90 minutes.
    http://motioncasts.tv
    Tutorial videos by Michael Erasmus and Hendrik Swanepoel.
    http://nshipster.com
    Mattt Thompson's weekly journal of Objective-C and Cocoa.
    http://nsscreencast.com/
    Ben Scheirman’s Objective-C screencasts, plus a short one on RubyMotion.
    http://4steps5minutes.com
    Minimum viable products (MVPs) described in a 5-minute video.

    View Slide

  66. @RayHightower
    Thanks!

    View Slide