Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

@RayHightower WisdomGroup.com

Slide 3

Slide 3 text

What Why How Q & A

Slide 4

Slide 4 text

What

Slide 5

Slide 5 text

Xcode + + Editor

Slide 6

Slide 6 text

Why

Slide 7

Slide 7 text

If you need a mobile MVP right now.

Slide 8

Slide 8 text

If you want to learn more about Ruby.

Slide 9

Slide 9 text

Why not?

Slide 10

Slide 10 text

Ruby’s future on iOS?

Slide 11

Slide 11 text

How

Slide 12

Slide 12 text

~/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)>

Slide 13

Slide 13 text

~/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$

Slide 14

Slide 14 text

~/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$

Slide 15

Slide 15 text

~/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$

Slide 16

Slide 16 text

~/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$

Slide 17

Slide 17 text

~/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$

Slide 18

Slide 18 text

~/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$

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

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)

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

~/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$

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

What about UX?

Slide 31

Slide 31 text

Human Interface Guidelines (HIG)

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

NSObject UIViewController UIWindow UIKit UIView UILabel UITableView

Slide 35

Slide 35 text

3: Fizz 5: Buzz 15: FizzBuzz

Slide 36

Slide 36 text

Interface Builder .xib files

Slide 37

Slide 37 text

view.viewWithTag 1

Slide 38

Slide 38 text

view.viewWithTag 2

Slide 39

Slide 39 text

view.viewWithTag 3

Slide 40

Slide 40 text

view.viewWithTag 4

Slide 41

Slide 41 text

~/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$

Slide 42

Slide 42 text

resources/fbib.xib

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

TDD MacBacon, Guard, & rm-redgreen

Slide 46

Slide 46 text

~/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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

$ gem install formotion

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Source: http://clayallsopp.com

Slide 53

Slide 53 text

Source: http://clayallsopp.com

Slide 54

Slide 54 text

$ gem install bubble-wrap

Slide 55

Slide 55 text

// 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/

Slide 56

Slide 56 text

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/

Slide 57

Slide 57 text

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/

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Ruby Tools with RubyMotion

Slide 60

Slide 60 text

Ruby Version Manager (RVM)

Slide 61

Slide 61 text

$ gem install cupertino

Slide 62

Slide 62 text

~/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

Slide 63

Slide 63 text

Auto Layout ARC

Slide 64

Slide 64 text

RubyMotion or Objective-C ?

Slide 65

Slide 65 text

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.

Slide 66

Slide 66 text

@RayHightower Thanks!