Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

RubyMotion

4,659 views

Published on

Presented on 8/14/2012 at BostonRb. This talk provides a nice intro and overview of what RubyMotion is and whether or not it's worth incorporating into your development toolkit.

Published in: Technology
  • Be the first to comment

RubyMotion

  1. 1. RubyMotioniOS Development with Ruby @markbates
  2. 2. I HATE iOSDEVELOPMENT!
  3. 3. Why I Hate iOS Development
  4. 4. Why I Hate iOS Development✦ XCode
  5. 5. Why I Hate iOS Development✦ XCode✦ Objective-C
  6. 6. Why I Hate iOS Development✦ XCode✦ Objective-C✦ Cocoa/iOS APIs
  7. 7. XCode
  8. 8. Objective-C
  9. 9. # Create a new array (mutable):myArray = %w{hello world etc}myArray << "new value"# Create a new hash (mutable):myHash = {"key-a" => "value-a", "key-b" => "value-b"}myHash["key-c"] = "value-c"
  10. 10. // Create a new array:NSArray *myArray = [NSArray arrayWithObjects:@"hello",@"world",@"etc",nil];// Create a mutable array:NSMutableArray *myArray = [[NSMutableArray alloc] init];[myArray addObject:@"hello world"];// Create a dictionary (hash):NSDictionary *myDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"value-a", @"key-a", @"value-b", @"key-b", nil];// Create a mutable dictionary:NSMutableDictionary *myDictionary = [NSMutableDictionary dictionary];[myDictionary setObject: @"value-c" forKey: @"key-c"];
  11. 11. now = -> {  puts "The date and time is: #{Time.now}"}now.call
  12. 12. void (^now)(void) = ^ {  NSDate *date = [NSDate date];  NSLog(@"The date and time is %@", date);};now();
  13. 13. Cocoa/iOS APIs
  14. 14. require net/httprequire jsonurl = "http://www.example.com/api.json"response = Net::HTTP.get_response(URI.parse(url))if response.code.to_i == 200  json = JSON.parse(response.body)  puts json.inspectelse  puts "An Error Occurred (#{response.code}): #{response.body}"end
  15. 15. - (void)viewDidLoad {  [super viewDidLoad];  responseData = [[NSMutableData data] retain];  NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com/api.json"]];  [[NSURLConnection alloc] initWithRequest:request delegate:self];}- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {  [responseData setLength:0];}- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {  [responseData appendData:data];}- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {  label.text = [NSString stringWithFormat:@"Connection failed: %@", [error description]];}- (void)connectionDidFinishLoading:(NSURLConnection *)connection {  [connection release];  NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];  [responseData release];    NSError *error;  SBJSON *json = [[SBJSON new] autorelease];  NSArray *myArray = [json objectWithString:responseString error:&error];  [responseString release];    if (myArray == nil)    label.text = [NSString stringWithFormat:@"JSON parsing failed: %@", [error localizedDescription]];  else {    NSMutableString *text = [NSMutableString stringWithString:@"Array Data:n"];        for (int i = 0; i < [myArray count]; i++)      [text appendFormat:@"%@n", [myArray objectAtIndex:i]];    label.text = text;  }}
  16. 16. Laurent Sansonetti✦ Worked for Apple for 7 years on iLife and OS X✦ Developed MacRuby✦ Developed RubyCocoa✦ Belgian
  17. 17. So What Does it Do?
  18. 18. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!)
  19. 19. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!)✦ Keep Your Editor (NO XCODE!)
  20. 20. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!)✦ Keep Your Editor (NO XCODE!)✦ IRB
  21. 21. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!)✦ Keep Your Editor (NO XCODE!)✦ IRB✦ Terminal Based Workflow (Rake)
  22. 22. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!)✦ Keep Your Editor (NO XCODE!)✦ IRB✦ Terminal Based Workflow (Rake)✦ Testing Framework (MacBacon)
  23. 23. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!) ✦ Native Applications✦ Keep Your Editor (NO XCODE!)✦ IRB✦ Terminal Based Workflow (Rake)✦ Testing Framework (MacBacon)
  24. 24. So What Does it Do?✦ Ruby!!! (NO OBJECTIVE-C!) ✦ Native Applications✦ Keep Your Editor (NO XCODE!) ✦ App Store Approved✦ IRB✦ Terminal Based Workflow (Rake)✦ Testing Framework (MacBacon)
  25. 25. Suck it Objective-C!
  26. 26. NSString *urlAsString = @"http://www.apple.com";NSURL *url = [NSURL URLWithString:urlAsString];NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];NSOperationQueue *queue = [[NSOperationQueue alloc] init];[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response,                     NSData *data,                     NSError *error) {      if ([data length] >0 &&       error == nil){          /* Get the documents directory */     NSString *documentsDir =     [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,                                          NSUserDomainMask,                                          YES) objectAtIndex:0];          /* Append the file name to the documents directory */     NSString *filePath = [documentsDir                           stringByAppendingPathComponent:@"apple.html"];          /* Write the data to the file */     [data writeToFile:filePath            atomically:YES];          NSLog(@"Successfully saved the file to %@", filePath);        }   else if ([data length] == 0 &&            error == nil){     NSLog(@"Nothing was downloaded.");   }   else if (error != nil){     NSLog(@"Error happened = %@", error);   }    }];
  27. 27. url = NSURL.URLWithString("http://www.apple.com")request = NSURLRequest.requestWithURL(url)queue = NSOperationQueue.alloc.initNSURLConnection.sendAsynchronousRequest(request,  queue: queue,  completionHandler: lambda do |response, data, error|    if(data.length > 0 && error.nil?)      doc_dir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,                                                    NSUserDomainMask,                                                    true).first      #p doc_dir      file_path = doc_dir.stringByAppendingPathComponent("apple.html")      data.writeToFile(file_path, atomically: true)      p "Saved file to #{file_path}"    elsif( data.length == 0 && error.nil? )      p "Nothing was downloaded"    elsif(!error.nil?)      p "Error: #{error}"    end  end)
  28. 28. But What About Those WeirdNamed Argument Methods?
  29. 29. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  // do something}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  // do something}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  // do something}
  30. 30. def tableView(tableView, didSelectRowAtIndexPath: indexPath)  # do somethingenddef tableView(tableView, numberOfRowsInSection: section)  # do somethingenddef tableView(tableView, cellForRowAtIndexPath: indexPath)  # do somethingend
  31. 31. Demo Time
  32. 32. Bubble Wraphttps://github.com/rubymotion/BubbleWrap
  33. 33. HTTPdata = {first_name: Matt, last_name: Aimonetti}BubbleWrap::HTTP.post("http://foo.bar.com/", {payload: data}) do |response| if response.ok? json = BubbleWrap::JSON.parse(response.body.to_str) p json[id] elsif response.status_code.to_s =~ /40d/ App.alert("Login failed") else App.alert(response.error_message) endend
  34. 34. App> App.documents_path# "~/iPhone Simulator/5.0/Applications/EEC6454E-1816-451E-BB9A-EE18222E1A8F/Documents"> App.resources_path# "~/iPhone Simulator/5.0/Applications/EEC64-1816-451E-BB9A-EE18221A8F/testSuite_spec.app"> App.name# "testSuite"> App.identifier# "io.bubblewrap.testSuite"> App.alert("BubbleWrap is awesome!")# creates and shows an alert message.> App.run_after(0.5) { p "Its #{Time.now}" }# Runs the block after 0.5 seconds.> App.open_url("http://matt.aimonetti.net")# Opens the url using the devices browser. (accepts a string url or an instance of NSURL.> App::Persistence[channels] # application specific persistence storage# [NBC, ABC, Fox, CBS, PBS]> App::Persistence[channels] = [TF1, France 2, France 3]# [TF1, France 2, France 3]
  35. 35. Device> Device.iphone?# true> Device.ipad?# false> Device.front_camera?# true> Device.rear_camera?# true> Device.orientation# :portrait> Device.simulator?# true> Device.retina?# false> Device.screen.width# 320> Device.screen.height# 480> Device.screen.width_for_orientation(:landscape_left)# 480> Device.screen.height_for_orientation(:landscape_left)# 320
  36. 36. Camera# Uses the front cameraBW::Device.camera.front.picture(media_types: [:movie, :image]) do |result| image_view = UIImageView.alloc.initWithImage(result[:original_image])end# Uses the rear cameraBW::Device.camera.rear.picture(media_types: [:movie, :image]) do |result| image_view = UIImageView.alloc.initWithImage(result[:original_image])end# Uses the photo libraryBW::Device.camera.any.picture(media_types: [:movie, :image]) do |result| image_view = UIImageView.alloc.initWithImage(result[:original_image])end
  37. 37. JSONBW::JSON.generate({foo => 1, bar => [1,2,3], baz => awesome})=> "{"foo":1,"bar":[1,2,3],"baz":"awesome"}"BW::JSON.parse "{"foo":1,"bar":[1,2,3],"baz":"awesome"}"=> {"foo"=>1, "bar"=>[1, 2, 3], "baz"=>"awesome"}
  38. 38. Media# Plays in your custom framelocal_file = NSURL.fileURLWithPath(File.join(NSBundle.mainBundle.resourcePath, test.mp3))BW::Media.play(local_file) do |media_player| media_player.view.frame = [[10, 100], [100, 100]] self.view.addSubview media_player.viewend# Plays in an independent modal controllerBW::Media.play_modal("http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3")
  39. 39. Deferrables> d = EM::DefaultDeferrable.new=> #<BubbleWrap::Reactor::DefaultDeferrable:0x6d859a0>> d.callback { |what| puts "Great #{what}!" }=> [#<Proc:0x6d8a1e0>]> d.succeed "justice"Great justice!=> nil
  40. 40. Events> o = Class.new { include EM::Eventable }.new=> #<#<Class:0x6dc1310>:0x6dc2ec0>> o.on(:november_5_1955) { puts "Ow!" }=> [#<Proc:0x6dc6300>]> o.on(:november_5_1955) { puts "Flux capacitor!" }=> [#<Proc:0x6dc6300>, #<Proc:0x6dc1ba0>]> o.trigger(:november_5_1955)Ow!Flux capacitor!=> [nil, nil]
  41. 41. More...✦ Localization ✦ Location✦ Color ✦ Gestures✦ UUID Generator ✦ RSS Parser✦ NSNotificationCenter ✦ Reactor✦ Persistence ✦ Timers✦ Observers✦ String (underscore, camelize, etc...)
  42. 42. Pros & Cons
  43. 43. The Pros
  44. 44. The Pros✦ Ruby!!
  45. 45. The Pros✦ Ruby!!✦ IDE Agnostic
  46. 46. The Pros✦ Ruby!!✦ IDE Agnostic✦ “Wrapper” Gems
  47. 47. The Pros✦ Ruby!!✦ IDE Agnostic✦ “Wrapper” Gems✦ Fast
  48. 48. The Pros✦ Ruby!!✦ IDE Agnostic✦ “Wrapper” Gems✦ Fast✦ IRB
  49. 49. The Pros✦ Ruby!! ✦ Easy to test✦ IDE Agnostic✦ “Wrapper” Gems✦ Fast✦ IRB
  50. 50. The Pros✦ Ruby!! ✦ Easy to test✦ IDE Agnostic ✦ Growing community✦ “Wrapper” Gems✦ Fast✦ IRB
  51. 51. The Pros✦ Ruby!! ✦ Easy to test✦ IDE Agnostic ✦ Growing community✦ “Wrapper” Gems ✦ Frequent updates✦ Fast✦ IRB
  52. 52. The Cons
  53. 53. The Cons✦ Cost - $199
  54. 54. The Cons✦ Cost - $199✦ Existing tutorials in Objective-C
  55. 55. The Cons✦ Cost - $199✦ Existing tutorials in Objective-C✦ Maintainability?
  56. 56. The Cons✦ Cost - $199✦ Existing tutorials in Objective-C✦ Maintainability?✦ No Debugger (Yet)
  57. 57. The Cons✦ Cost - $199✦ Existing tutorials in Objective-C✦ Maintainability?✦ No Debugger (Yet)✦ Difficult to work with Interface Builder
  58. 58. The Verdict
  59. 59. Resources✦ http://www.rubymotion.com ✦ http://rubymotionapps.com/projects✦ http://rubymotion-tutorial.com ✦ http://pragmaticstudio.com/screencasts/ rubymotion✦ https://github.com/IconoclastLabs/ rubymotion_cookbook✦ https://github.com/railsfactory/ rubymotion-cookbook✦ https://twitter.com/RubyMotion✦ http://rubymotionweekly.com

×