Download pdf - Fun with Ruby and Cocoa

Transcript
Page 1: Fun with Ruby and Cocoa

Ruby and CocoaFacilitate development on OSX

Page 2: Fun with Ruby and Cocoa

About me

Page 3: Fun with Ruby and Cocoa

About me

Page 4: Fun with Ruby and Cocoa

Rapperswil

Page 6: Fun with Ruby and Cocoa

huesler informatik

Page 7: Fun with Ruby and Cocoa

huesler informatik

upstream agile

Page 8: Fun with Ruby and Cocoa

huesler informatik

upstream agile

co-up.de

Page 9: Fun with Ruby and Cocoa

Ruby and Cocoa

Page 10: Fun with Ruby and Cocoa

Ruby

Page 11: Fun with Ruby and Cocoa

passionatehttp://www.flickr.com/photos/gi/378823/sizes/o/

Page 12: Fun with Ruby and Cocoa

Apple OSX

Page 13: Fun with Ruby and Cocoa
Page 14: Fun with Ruby and Cocoa

passionate

http://www.flickr.com/photos/gi/378823/sizes/o/

Page 15: Fun with Ruby and Cocoa

Landscape

http://www.flickr.com/photos/kiumo/4203883504/sizes/o/

Page 16: Fun with Ruby and Cocoa

Cocoa

http://www.flickr.com/photos/luder5/4100921399/sizes/l/

Page 17: Fun with Ruby and Cocoa

Cocoa

Page 18: Fun with Ruby and Cocoa

Cocoa

• Core Foundation

Page 19: Fun with Ruby and Cocoa

Cocoa

• Core Foundation

• Appkit

Page 20: Fun with Ruby and Cocoa

Cocoa

• Core Foundation

• Appkit

• Core * (Audio/Video/Image/Data etc.)

Page 21: Fun with Ruby and Cocoa

Cocoa

• Core Foundation

• Appkit

• Core * (Audio/Video/Image/Data etc.)

• Scripting bridge

Page 22: Fun with Ruby and Cocoa

Cocoa

• Core Foundation

• Appkit

• Core * (Audio/Video/Image/Data etc.)

• Scripting bridge

• others

Page 23: Fun with Ruby and Cocoa

Interface Builder

Page 24: Fun with Ruby and Cocoa

XCode

Page 25: Fun with Ruby and Cocoa

Objective-C

Page 26: Fun with Ruby and Cocoa

NSMutableArray *anArray = [[NSMutableArray alloc] init

];[anArray addObject:@"Element 1"];[anArray addObject:@"Element 2"];[anArray addObject:@"Element 3"];

//Use a for each loop to iterate through the arrayfor (NSString *s in anArray) { NSLog(s);}//Release the array[anArray release]

Page 27: Fun with Ruby and Cocoa
Page 28: Fun with Ruby and Cocoa

Ruby And Cocoa

Page 29: Fun with Ruby and Cocoa
Page 30: Fun with Ruby and Cocoa

Ruby Cocoa

Page 31: Fun with Ruby and Cocoa
Page 32: Fun with Ruby and Cocoa

HotCocoa

picture shamelessly cropped from http://www.slideshare.net/mattetti/macruby-hotcocoa-presentation-by-rich-kilmer

Page 33: Fun with Ruby and Cocoa

Scripting Bridge

http://www.flickr.com/photos/bensonkua/2851908095/sizes/l/

Page 34: Fun with Ruby and Cocoa

Good to know

Page 35: Fun with Ruby and Cocoa

Good to know

• Available commands for each application are in a .sdef file

Page 36: Fun with Ruby and Cocoa

Good to know

• Available commands for each application are in a .sdef file

• Terminal.app/Contents/Resources/Terminal.sdef

Page 37: Fun with Ruby and Cocoa

Good to know

• Available commands for each application are in a .sdef file

• Terminal.app/Contents/Resources/Terminal.sdef

• gem rb-appscript (native extension so not for MacRuby)

Page 38: Fun with Ruby and Cocoa

1 <command name="do script" code="coredosc" 2 description="Runs a UNIX shell script or command."> 3 <cocoa class="TTDoScriptCommand"/> 4 <direct-parameter type="text" 5 description="The command to execute." optional="yes"/> 6 <parameter name="with command" 7 description="Data to be passed to the Terminal..." 8 code="cmnd" optional="yes" hidden="yes"> 9 <cocoa key="Command" /> 10 <type type="text" /> 11 <type type="any" /> <!-- support null case --> 12 </parameter> 13 <parameter name="in" 14 description="The tab in which to execute the command" 15 code="kfil" optional="yes"> 16 <cocoa key="Target" /> 17 <type type="tab" /> 18 <type type="window" /> 19 <type type="any" /> <!-- support null case --> 20 </parameter> 21 <result type="tab" 22 description="The tab the command was executed in." /> 23 </command> 24

Page 39: Fun with Ruby and Cocoa
Page 40: Fun with Ruby and Cocoa

Control Terminal

Page 41: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require 'rubygems' 3 require 'appscript' 4 include Appscript 5 6 terminal = app('Terminal') 7 current_window = terminal.windows.first 8 current_tab = current_window.tabs.last 9 process = app("System Events").application_processes[ 10 "Terminal.app" 11 ] 12 13 process.keystroke('t', :using => :command_down) 14 terminal.do_script('top', :in => current_tab)

Page 42: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require 'rubygems' 3 require 'appscript' 4 include Appscript 5 6 terminal = app('Terminal') 7 current_window = terminal.windows.first 8 current_tab = current_window.tabs.last 9 process = app("System Events").application_processes[ 10 "Terminal.app" 11 ] 12 13 process.keystroke('t', :using => :command_down) 14 terminal.do_script('top', :in => current_tab)

Page 43: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require 'rubygems' 3 require 'appscript' 4 include Appscript 5 6 terminal = app('Terminal') 7 current_window = terminal.windows.first 8 current_tab = current_window.tabs.last 9 process = app("System Events").application_processes[ 10 "Terminal.app" 11 ] 12 13 process.keystroke('t', :using => :command_down) 14 terminal.do_script('top', :in => current_tab)

Page 44: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require 'rubygems' 3 require 'appscript' 4 include Appscript 5 6 terminal = app('Terminal') 7 current_window = terminal.windows.first 8 current_tab = current_window.tabs.last 9 process = app("System Events").application_processes[ 10 "Terminal.app" 11 ] 12 13 process.keystroke('t', :using => :command_down) 14 terminal.do_script('top', :in => current_tab)

Page 45: Fun with Ruby and Cocoa

Problems with MacRuby

Page 46: Fun with Ruby and Cocoa

Problems with MacRuby

Page 47: Fun with Ruby and Cocoa

Problems with MacRuby

• Some methods don’t seem to be available

Page 48: Fun with Ruby and Cocoa

iTunes

Page 49: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 framework 'ScriptingBridge' 4 5 itunes = SBApplication.applicationWithBundleIdentifier( 6 "com.apple.iTunes" 7 ) 8 library = itunes.sources.objectWithName("Library") 9 10 library.userPlaylists.each do |playlist| 11 puts playlist.name 12 end

Page 50: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 framework 'ScriptingBridge' 4 5 itunes = SBApplication.applicationWithBundleIdentifier( 6 "com.apple.iTunes" 7 ) 8 library = itunes.sources.objectWithName("Library") 9 10 library.userPlaylists.each do |playlist| 11 puts playlist.name 12 end

Page 51: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 framework 'ScriptingBridge' 4 5 itunes = SBApplication.applicationWithBundleIdentifier( 6 "com.apple.iTunes" 7 ) 8 library = itunes.sources.objectWithName("Library") 9 10 library.userPlaylists.each do |playlist| 11 puts playlist.name 12 end

Page 52: Fun with Ruby and Cocoa

Core Location

Page 53: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 framework 'CoreLocation' 3 4 loc = CLLocationManager.alloc.init 5 loc.delegate = self 6 loc.startUpdatingLocation 7 8 # keep the script running 9 NSRunLoop.currentRunLoop.runUntilDate( 10 NSDate.distantFuture 11 )

Page 54: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 framework 'CoreLocation' 3 4 loc = CLLocationManager.alloc.init 5 loc.delegate = self 6 loc.startUpdatingLocation 7 8 # keep the script running 9 NSRunLoop.currentRunLoop.runUntilDate( 10 NSDate.distantFuture 11 )

Page 55: Fun with Ruby and Cocoa

1 def locationManager( 2 manager, 3 didUpdateToLocation: new_location, 4 fromLocation: old_location 5 ) 6 7 puts "loc: #{new_location.description}" 8 end

Page 56: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 framework 'CoreLocation' 3 4 loc = CLLocationManager.alloc.init 5 loc.delegate = self 6 loc.startUpdatingLocation 7 8 # keep the script running 9 NSRunLoop.currentRunLoop.runUntilDate( 10 NSDate.distantFuture 11 )

Page 57: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 framework 'CoreLocation' 3 4 def locationManager(manager, 5 didUpdateToLocation: new_location, 6 fromLocation: old_location 7 ) 8 puts "location: #{new_location.description}" 9 end 10 11 loc = CLLocationManager.alloc.init 12 loc.delegate = self 13 loc.startUpdatingLocation 14 15 # keep the script running 16 NSRunLoop.currentRunLoop.runUntilDate( 17 NSDate.distantFuture 18 )

Page 58: Fun with Ruby and Cocoa

Grand Central Dispatch

Page 59: Fun with Ruby and Cocoa

Grand Central Dispatch

Page 60: Fun with Ruby and Cocoa

Grand Central Dispatch

• MacRuby only

Page 61: Fun with Ruby and Cocoa

Grand Central Dispatch

• MacRuby only

• Synchronous

Page 62: Fun with Ruby and Cocoa

Grand Central Dispatch

• MacRuby only

• Synchronous

• Asynchronous

Page 63: Fun with Ruby and Cocoa

Grand Central Dispatch

• MacRuby only

• Synchronous

• Asynchronous

• Parallel

Page 64: Fun with Ruby and Cocoa

Grand Central Dispatch

• MacRuby only

• Synchronous

• Asynchronous

• Parallel

• Synchronization

Page 65: Fun with Ruby and Cocoa

Asynchronous

Page 66: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 7 queue.async do 8 puts 'Starting asyn. NONE BLOCKING!' 9 sleep 2.00 10 puts "Finished asyn" 11 end 12 puts "code not being blocked" 13 14 NSRunLoop.currentRunLoop.runUntilDate( 15 NSDate.distantFuture 16 ) 17

Page 67: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 7 queue.async do 8 puts 'Starting asyn. NONE BLOCKING!' 9 sleep 2.00 10 puts "Finished asyn" 11 end 12 puts "code not being blocked" 13 14 NSRunLoop.currentRunLoop.runUntilDate( 15 NSDate.distantFuture 16 ) 17

Page 68: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 7 queue.async do 8 puts 'Starting asyn. NONE BLOCKING!' 9 sleep 2.00 10 puts "Finished asyn" 11 end 12 puts "code not being blocked" 13 14 NSRunLoop.currentRunLoop.runUntilDate( 15 NSDate.distantFuture 16 ) 17

Page 69: Fun with Ruby and Cocoa

Synchronous

Page 70: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 7 queue.sync do 8 puts 'Starting sync. BLOCKING!' 9 sleep 3.0 10 puts 'Finished sync' 11 end 12 puts "code being blocked" 13 14 NSRunLoop.currentRunLoop.runUntilDate( 15 NSDate.distantFuture 16 ) 17

Page 71: Fun with Ruby and Cocoa

Synchronized

Page 72: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 worker_queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 group = Dispatch::Group.new 7 8 0.upto(10) do |i| 9 puts "Dispatch #{i} to GCD" 10 worker_queue.async(group) do 11 puts "working on #{i}" 12 end 13 end 14 puts "waiting for gcd" 15 group.wait 16 puts "done" 17

Page 73: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 worker_queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 group = Dispatch::Group.new 7 8 0.upto(10) do |i| 9 puts "Dispatch #{i} to GCD" 10 worker_queue.async(group) do 11 puts "working on #{i}" 12 end 13 end 14 puts "waiting for gcd" 15 group.wait 16 puts "done" 17

Page 74: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 worker_queue = Dispatch::Queue.new( 4 'ch.huesler-informatik.scotrubyconf.gcd' 5 ) 6 group = Dispatch::Group.new 7 8 0.upto(10) do |i| 9 puts "Dispatch #{i} to GCD" 10 worker_queue.async(group) do 11 puts "working on #{i}" 12 end 13 end 14 puts "waiting for gcd" 15 group.wait 16 puts "done" 17

Page 75: Fun with Ruby and Cocoa

Concurrent

Page 76: Fun with Ruby and Cocoa

1 #!/usr/bin/env macruby 2 3 group = Dispatch::Group.new 4 result = [] 5 1.upto(10).each do |i| 6 Dispatch::Queue.concurrent.async(group) do 7 sleep 2 8 result << i 9 end 10 end 11 group.wait 12 puts result.inspect

Page 77: Fun with Ruby and Cocoa

.plist files

Page 78: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require "osx/cocoa" 3 include OSX 4 5 file_name = 'Info.plist' 6 plist = NSDictionary.dictionaryWithContentsOfFile( 7 file_name 8 ) 9 10 plist['CFBundleVersion'] = '2.0.1' 11 12 plist.writeToFile_atomically( 13 file_name, 14 true 15 )

Page 79: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require "osx/cocoa" 3 include OSX 4 5 file_name = 'Info.plist' 6 plist = NSDictionary.dictionaryWithContentsOfFile( 7 file_name 8 ) 9 10 plist['CFBundleVersion'] = '2.0.1' 11 12 plist.writeToFile_atomically( 13 file_name, 14 true 15 )

Page 80: Fun with Ruby and Cocoa

1 #!/usr/bin/env ruby 2 require "osx/cocoa" 3 include OSX 4 5 file_name = 'Info.plist' 6 plist = NSDictionary.dictionaryWithContentsOfFile( 7 file_name 8 ) 9 10 plist['CFBundleVersion'] = '2.0.1' 11 12 plist.writeToFile_atomically( 13 file_name, 14 true 15 )

Page 81: Fun with Ruby and Cocoa

Keychain Access

Page 82: Fun with Ruby and Cocoa

Details

Page 83: Fun with Ruby and Cocoa

Details

• MacRuby has issues with void pointer (patch pending)

Page 84: Fun with Ruby and Cocoa

Details

• MacRuby has issues with void pointer (patch pending)

• Use objective c wrapper instead (dynlib or bundle)

Page 85: Fun with Ruby and Cocoa

Details

• MacRuby has issues with void pointer (patch pending)

• Use objective c wrapper instead (dynlib or bundle)

• Generate metadata to make it work

Page 86: Fun with Ruby and Cocoa

Details

• MacRuby has issues with void pointer (patch pending)

• Use objective c wrapper instead (dynlib or bundle)

• Generate metadata to make it work

Page 87: Fun with Ruby and Cocoa

1 export FILE_PATH = ~/Library/BridgeSupport 2 export FRAMEWORK_PATH = ~/Library/BridgeSupport/Security.bridgesupport 3 mkdir $FILE_PATH 4 gen_bridge_metadata -f Security -o $FRAMEWORK_PATH

Page 88: Fun with Ruby and Cocoa

1 require 'osx/cocoa' 2 include OSX 3 require_framework 'Security' 4 5 # Set up some relevant variables 6 7 service = "ch.huesler-informatik.scotrubyconf.keychain" 8 account = "Highlander" 9 original_password = "Rrrueby" 10 11 # Add password 12 SecKeychainAddGenericPassword( 13 nil, 14 service.length, 15 service, 16 account.length, 17 account, 18 original_password.length, 19 original_password, 20 nil 21 )

Page 89: Fun with Ruby and Cocoa

1 require 'osx/cocoa' 2 include OSX 3 require_framework 'Security' 4 5 # Set up some relevant variables 6 7 service = "ch.huesler-informatik.scotrubyconf.keychain" 8 account = "Highlander" 9 original_password = "Rrrueby" 10 11 # Add password 12 SecKeychainAddGenericPassword( 13 nil, 14 service.length, 15 service, 16 account.length, 17 account, 18 original_password.length, 19 original_password, 20 nil 21 )

Page 90: Fun with Ruby and Cocoa

1 # Add password 2 SecKeychainAddGenericPassword( 3 nil, 4 service.length, 5 service, 6 account.length, 7 account, 8 original_password.length, 9 original_password, 10 nil 11 )

Page 91: Fun with Ruby and Cocoa

1 # Query the keychain 2 status, *password = SecKeychainFindGenericPassword( 3 nil, 4 service.length, 5 service, 6 account.length, 7 account 8 )

Page 92: Fun with Ruby and Cocoa

1 # Password-related data. Shifting pointers 2 length = password.shift 3 data = password.shift 4 plain_password = data.bytestr(length) 5 6 puts "Password: #{plain_password}"

Page 93: Fun with Ruby and Cocoa

That’s all!Questions?


Recommended