diff --git a/lib/sim_launcher.rb b/lib/sim_launcher.rb
index faa123c..75a809a 100644
--- a/lib/sim_launcher.rb
+++ b/lib/sim_launcher.rb
@@ -3,18 +3,24 @@
require 'sim_launcher/simulator'
require 'sim_launcher/sdk_detector'
+# Simulator Launcher
module SimLauncher
+ # Default derived data path
DERIVED_DATA = File.expand_path("~/Library/Developer/Xcode/DerivedData")
+ # Default derived data info plist
DEFAULT_DERIVED_DATA_INFO = File.expand_path("#{DERIVED_DATA}/*/info.plist")
- def self.check_app_path( app_path )
- unless File.exists?( app_path )
+ # Check app path
+ # @param [String] app_path app path to check
+ # @return [String] Error message or _nil_ on success
+ def self.check_app_path(app_path)
+ unless File.exists?(app_path)
return "The specified app path doesn't seem to exist: #{app_path}"
end
unless File.directory? app_path
- file_appears_to_be_a_binary = !!( `file "#{app_path}"` =~ /Mach-O executable/ )
+ file_appears_to_be_a_binary = !!(`file "#{app_path}"` =~ /Mach-O executable/)
if file_appears_to_be_a_binary
return <<-EOS
The specified app path is a binary executable, rather than a directory. You need to provide the path to the app *bundle*, not the app executable itself.
@@ -29,6 +35,9 @@ def self.check_app_path( app_path )
nil
end
+ # Get derived data directory for the project
+ # @param [String] project_name Name of the project
+ # @return [String] Derived data directory path
def self.derived_data_dir_for_project_name(project_name)
build_dirs = Dir.glob("#{DERIVED_DATA}/*").find_all do |xc_proj|
@@ -65,6 +74,9 @@ def self.derived_data_dir_for_project_name(project_name)
end
end
+ # Get app bundle for path or raise an exception
+ # @param [String] path Path
+ # @return [String] App bundle path
def self.app_bundle_or_raise(path)
bundle_path = nil
diff --git a/lib/sim_launcher/client.rb b/lib/sim_launcher/client.rb
index d2c4833..404e4c1 100644
--- a/lib/sim_launcher/client.rb
+++ b/lib/sim_launcher/client.rb
@@ -2,30 +2,49 @@
require 'cgi'
require 'net/http'
+# Simulator Launcher
module SimLauncher
+ # Client
class Client
+ # Default server URI
DEFAULT_SERVER_URI = "http://localhost:8881"
- def initialize( app_path, sdk, family )
- @app_path = File.expand_path( app_path )
+ # Initialized
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @param [String] family Device family
+ def initialize(app_path, sdk, family)
+ @app_path = File.expand_path(app_path)
@sdk = sdk
@family = family
self.server_uri = DEFAULT_SERVER_URI
end
- def self.for_ipad_app( app_path, sdk = nil )
- self.new( app_path, sdk, 'ipad' )
+ # Client for iPad app
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @return [Client] Client object for iPad app
+ def self.for_ipad_app(app_path, sdk = nil)
+ self.new(app_path, sdk, 'ipad')
end
- def self.for_iphone_app( app_path, sdk = nil )
- self.new( app_path, sdk, 'iphone' )
+ # Client for iPhone app
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @return [Client] Client object for iPhone app
+ def self.for_iphone_app(app_path, sdk = nil)
+ self.new(app_path, sdk, 'iphone')
end
+ # Set server URI
+ # @param [URI] uri Server URI
def server_uri=(uri)
@server_uri = URI.parse( uri.to_s )
end
- def launch(restart=false)
+ # Launch
+ # @param [Boolean] restart Restart if this flag is _true_
+ def launch(restart = false)
begin
full_request_uri = launch_uri(restart)
puts "requesting #{full_request_uri}" if $DEBUG
@@ -38,14 +57,15 @@ def launch(restart=false)
end
end
+ # Relaunch
def relaunch
launch(true)
end
- # check that there appears to be a server ready for us to send commands to
+ # Check that there appears to be a server ready for us to send commands to
def ping
# our good-enough solution is just request the list of available iOS sdks and
- # check that we get a 200 response
+ # check that we get a 200 response
begin
uri = list_sdks_uri
Net::HTTP.start( uri.host, uri.port) do |http|
@@ -59,6 +79,9 @@ def ping
private
+ # Lauch with URI
+ # @param [Boolean] requesting_restart Restart request flag
+ # @return [URI] Full request URI
def launch_uri(requesting_restart)
full_request_uri = @server_uri.dup
full_request_uri.path = "/launch_#{@family}_app"
@@ -68,6 +91,8 @@ def launch_uri(requesting_restart)
full_request_uri
end
+ # List SDKs URI
+ # @param [URI] SDKs URI
def list_sdks_uri
full_request_uri = @server_uri.dup
full_request_uri.path = "/showsdks"
diff --git a/lib/sim_launcher/direct_client.rb b/lib/sim_launcher/direct_client.rb
index ba1397f..645f0a9 100644
--- a/lib/sim_launcher/direct_client.rb
+++ b/lib/sim_launcher/direct_client.rb
@@ -1,35 +1,52 @@
+# Simulator Launcher
module SimLauncher
+ # Direct Client
class DirectClient
- def initialize( app_path, sdk, family )
- @app_path = File.expand_path( app_path )
+
+ # Initialize
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @param [String] family Device family
+ def initialize(app_path, sdk, family)
+ @app_path = File.expand_path(app_path)
@sdk = sdk
@family = family
end
- def self.for_ipad_app( app_path, sdk = nil )
- self.new( app_path, sdk, 'ipad' )
+ # Direct client for iPad app
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @return [DirectClient] Direct client object for iPad app
+ def self.for_ipad_app(app_path, sdk = nil)
+ self.new(app_path, sdk, 'ipad')
end
- def self.for_iphone_app( app_path, sdk = nil )
- self.new( app_path, sdk, 'iphone' )
+ # Direct client for iPhone app
+ # @param [String] app_path App path
+ # @param [String] sdk SDK
+ # @return [DirectClient] Direct client object for iPhone app
+ def self.for_iphone_app(app_path, sdk = nil)
+ self.new(app_path, sdk, 'iphone')
end
+ # Launch
def launch
- SimLauncher::Simulator.new.launch_ios_app( @app_path, @sdk, @family )
+ SimLauncher::Simulator.new.launch_ios_app(@app_path, @sdk, @family)
end
+ # Rotate left
def rotate_left
simulator = SimLauncher::Simulator.new
simulator.rotate_left
end
-
+
+ # Rotate right
def rotate_right
simulator = SimLauncher::Simulator.new
simulator.rotate_right
end
-
-
+ # Relaunch
def relaunch
simulator = SimLauncher::Simulator.new
simulator.quit_simulator
diff --git a/lib/sim_launcher/sdk_detector.rb b/lib/sim_launcher/sdk_detector.rb
index 684c61e..c0c0c00 100644
--- a/lib/sim_launcher/sdk_detector.rb
+++ b/lib/sim_launcher/sdk_detector.rb
@@ -1,16 +1,24 @@
+# Simulator Launcher
module SimLauncher
+ # SDK Detector
class SdkDetector
+ # Initialize
+ # @param [Simulator] simulator Simulator to initialize with
def initialize(simulator = Simulator.new)
@simulator = simulator
end
+ # Get available SDK versions
+ # @return [String] SDK versions
def available_sdk_versions
@simulator.showsdks.split("\n").map { |sdk_line|
sdk_line[/\(([\d.]+)\)$/,1] # grab any "(x.x)" part at the end of the line
}.compact
end
+ # Get latest SDK version
+ # @return [String] Latest SDK version
def latest_sdk_version
available_sdk_versions.sort.last
end
diff --git a/lib/sim_launcher/simulator.rb b/lib/sim_launcher/simulator.rb
index f157861..896513e 100644
--- a/lib/sim_launcher/simulator.rb
+++ b/lib/sim_launcher/simulator.rb
@@ -1,108 +1,205 @@
+# Simulator Launcher
module SimLauncher
-class Simulator
+ # Simulator
+ class Simulator
- def initialize( iphonesim_path_external = nil )
- @iphonesim_path = iphonesim_path_external || iphonesim_path(xcode_version)
- end
+ # Initialize
+ # @param [Stirng] iphonesim_path_external External iphone simulator path
+ def initialize(iphonesim_path_external = nil)
+ @iphonesim_path = iphonesim_path_external || iphonesim_path(xcode_version)
+ end
- def showsdks
- run_synchronous_command( 'showsdks' )
- end
+ # Display available SKDs
+ def showsdks
+ run_synchronous_command('showsdks')
+ end
- def start_simulator(sdk_version=nil, device_family="iphone")
- sdk_version ||= SdkDetector.new(self).latest_sdk_version
- run_synchronous_command( :start, '--sdk', sdk_version, '--family', device_family, '--exit' )
- end
+ # Start simulator
+ # @param [String] sdk_version SKD version (e.g. "6.1", "7.0")
+ # @param [String] device_family Device family ("iphone", "ipad")
+ # @param [Hash] options Addtional options to pass to ios-sim executable
+ # @option options [nil] :retina Retina device, use _nil_ value (:retina => nil)
+ # @option options [nil] :tall Tall retina device (4-inch), use _nil_ value (:tall => nil)
+ # @option options [String] :env Environment variables plist file
+ # @option options [String] :setenv Evnironment varible key-valur pair (:setenv => "DEBUG=1")
+ # @example
+ # s = SimLauncher::Simulator.new
+ # # iPad retina, SDK 6.1, load environment variables from env.plist
+ # options = { :retina => nil, :env => "env.plist" }
+ # s.start_simulator("6.1", "ipad", options)
+ # # iPhone tall retina (4-inch), SDK 7.0, set environment variables 'dev' and 'reset' to true
+ # options = { :retina => nil, :tall => nil, :setenv => "dev=true", :setenv => "reset=true" }
+ # s.start_simulator("7.0", "iphone", options)
+ # # Start with no options (backwards compatibility)
+ # s.start_simulator("7.0", "iphone")
+ def start_simulator(sdk_version = nil, device_family = "iphone", options = {})
+ sdk_version ||= SdkDetector.new(self).latest_sdk_version
+ options = options.map { |k, v| ["--#{k.to_s}"] + (v.nil? ? [] : ["#{v}"]) }.flatten
+ run_synchronous_command( :start, '--sdk', sdk_version, '--family', device_family, '--exit', *options)
+ end
+ # Rotate simulator left
+ def rotate_left
+ script_dir = File.join(File.dirname(__FILE__), "..", "..", "scripts")
+ rotate_script = File.expand_path("#{script_dir}/rotate_simulator_left.applescript")
+ system("osascript #{rotate_script}")
+ end
- def rotate_left
- script_dir = File.join(File.dirname(__FILE__),"..","..","scripts")
- rotate_script = File.expand_path("#{script_dir}/rotate_simulator_left.applescript")
- system("osascript #{rotate_script}")
- end
+ # Rotate simulator right
+ def rotate_right
+ script_dir = File.join(File.dirname(__FILE__), "..", "..", "scripts")
+ rotate_script = File.expand_path("#{script_dir}/rotate_simulator_right.applescript")
+ system("osascript #{rotate_script}")
+ end
- def rotate_right
- script_dir = File.join(File.dirname(__FILE__),"..","..","scripts")
- rotate_script = File.expand_path("#{script_dir}/rotate_simulator_right.applescript")
- system("osascript #{rotate_script}")
- end
+ # Reset simulator
+ # @param [Array] sdks Array of SDKs to reset simulator for
+ def reset(sdks = nil)
+ script_dir = File.join(File.dirname(__FILE__), "..", "..", "scripts")
+ reset_script = File.expand_path("#{script_dir}/reset_simulator.applescript")
+
+ sdks ||= SimLauncher::SdkDetector.new(self).available_sdk_versions
- def reset(sdks=nil)
- script_dir = File.join(File.dirname(__FILE__),"..","..","scripts")
- reset_script = File.expand_path("#{script_dir}/reset_simulator.applescript")
+ sdks.each do |sdk_path_str|
+ start_simulator(sdk_path_str, "iphone")
+ system("osascript #{reset_script}")
+ start_simulator(sdk_path_str, "ipad")
+ system("osascript #{reset_script}")
+ end
- sdks ||= SimLauncher::SdkDetector.new(self).available_sdk_versions
+ quit_simulator
- sdks.each do |sdk_path_str|
- start_simulator(sdk_path_str,"iphone")
- system("osascript #{reset_script}")
- start_simulator(sdk_path_str,"ipad")
- system("osascript #{reset_script}")
end
- quit_simulator
+ # Launch iOS app with options and arguments
+ # @param [String] app_path Application bundle path
+ # @param [String] sdk_version SDK version (e.g. "6.1", "7.0")
+ # @param [String] device_family Device family ("iphone", "ipad")
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array] app_args Application arguments
+ def launch_ios_app_with_options(app_path, sdk_version, device_family, options = {}, app_args = nil)
+ if problem = SimLauncher.check_app_path(app_path)
+ bangs = '!'*80
+ raise "\n#{bangs}\nENCOUNTERED A PROBLEM WITH THE SPECIFIED APP PATH:\n\n#{problem}\n#{bangs}"
+ end
+ sdk_version ||= SdkDetector.new(self).latest_sdk_version
+ options = options.map { |k, v| ["--#{k.to_s}"] + (v.nil? ? [] : ["#{v}"]) }.flatten
+ args = ["--args"] + app_args.flatten if app_args
+ run_synchronous_command(:launch, app_path, '--sdk', sdk_version, '--family', device_family, '--exit', *options, *args)
+ end
- end
+ # Launch iOS app with arguments
+ # @param [String] app_path Application bundle path
+ # @param [String] sdk_version SDK version (e.g. "6.1", "7.0")
+ # @param [String] device_family Device family ("iphone", "ipad")
+ # @param [Array] app_args Application arguments
+ def launch_ios_app(app_path, sdk_version, device_family, app_args = nil)
+ launch_ios_app_with_options(app_path, sdk_version, device_family, {}, app_args)
+ end
- def launch_ios_app(app_path, sdk_version, device_family, app_args = nil)
- if problem = SimLauncher.check_app_path( app_path )
- bangs = '!'*80
- raise "\n#{bangs}\nENCOUNTERED A PROBLEM WITH THE SPECIFIED APP PATH:\n\n#{problem}\n#{bangs}"
+ # Launch iPad app using app bundle
+ # @param [String] app_path Application bundle path
+ # @param [String] sdk SDK version (e.g. "6.1", "7.0")
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array] app_args Application arguments
+ def launch_ipad_app(app_path, sdk, options = {}, app_args = nil)
+ launch_ios_app_with_options(app_path, sdk, 'ipad', options, app_args)
end
- sdk_version ||= SdkDetector.new(self).latest_sdk_version
- args = ["--args"] + app_args.flatten if app_args
- run_synchronous_command( :launch, app_path, '--sdk', sdk_version, '--family', device_family, '--exit', *args )
- end
- def launch_ipad_app( app_path, sdk )
- launch_ios_app( app_path, sdk, 'ipad' )
- end
+ # Launch iPad app using app name
+ # @param [String] app_name Application name
+ # @param [String] sdk SDK version (e.g. "6.1", "7.0")
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array] app_args Application arguments
+ def launch_ipad_app_with_name(app_name, sdk, options = {}, app_args = nil)
+ app_path = SimLauncher.app_bundle_or_raise(app_name)
+ launch_ios_app_with_options(app_path, sdk, 'iphone', options, app_args)
+ end
- def launch_ipad_app_with_name( app_name, sdk )
- app_path = SimLauncher.app_bundle_or_raise(app_name)
- launch_ios_app( app_path, sdk, 'iphone' )
- end
+ # Launch iPhone app using app bundle
+ # @param [String] app_path Application bundle path
+ # @param [String] sdk SDK version (e.g. "6.1", "7.0")
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array] app_args Application arguments
+ def launch_iphone_app(app_path, sdk, options = {}, app_args = nil)
+ launch_ios_app_with_options(app_path, sdk, 'iphone', options, app_args)
+ end
- def launch_iphone_app( app_path, sdk )
- launch_ios_app( app_path, sdk, 'iphone' )
- end
+ # Launch iPhone app using app name
+ # @param [String] app_name Application name
+ # @param [String] sdk SDK version (e.g. "6.1", "7.0")
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array] app_args Application arguments
+ def launch_iphone_app_with_name(app_name, sdk, options = {}, app_args = nil)
+ app_path = SimLauncher.app_bundle_or_raise(app_name)
+ launch_ios_app_with_options(app_path, sdk, 'iphone', options, app_args)
+ end
- def launch_iphone_app_with_name( app_name, sdk )
- app_path = SimLauncher.app_bundle_or_raise(app_name)
- launch_ios_app( app_path, sdk, 'iphone' )
- end
+ # Quit simulator
+ def quit_simulator
+ `echo 'application "iPhone Simulator" quit' | osascript`
+ end
- def quit_simulator
- `echo 'application "iPhone Simulator" quit' | osascript`
- end
+ # Run synchronous shell command
+ # @param [Array] args Command line arguments
+ def run_synchronous_command(*args)
+ args.compact!
+ cmd = cmd_line_with_args(args)
+ puts "executing #{cmd}" if $DEBUG
+ `#{cmd}`
+ end
- def run_synchronous_command( *args )
- args.compact!
- cmd = cmd_line_with_args( args )
- puts "executing #{cmd}" if $DEBUG
- `#{cmd}`
- end
+ # Return shell command string with given arguments
+ # @param [Array] args Command line arguments
+ # @return [String] Shell command string
+ def cmd_line_with_args(args)
+ cmd_sections = [@iphonesim_path] + args.map { |x| "\"#{x.to_s}\"" } << '2>&1'
+ cmd_sections.join(' ')
+ end
- def cmd_line_with_args( args )
- cmd_sections = [@iphonesim_path] + args.map{ |x| "\"#{x.to_s}\"" } << '2>&1'
- cmd_sections.join(' ')
- end
-
- def xcode_version
- version = `xcodebuild -version`
- raise "xcodebuild not found" unless $? == 0
- version[/([0-9]\.[0-9])/, 1].to_f
- end
-
- def iphonesim_path(version)
- installed = `which ios-sim`
- if installed =~ /(.*ios-sim)/
- puts "Using installed ios-sim at #{$1}"
- return $1
+ # Get current Xcode version
+ # @return [String] Xcode version string
+ def xcode_version
+ version = `xcodebuild -version`
+ raise "xcodebuild not found" unless $? == 0
+ version[/([0-9]\.[0-9])/, 1].to_f
+ end
+
+ # Get ios-sim version
+ # @return [String] ios-sim version string
+ def iphonesim_version
+ `ios-sim --version`
+ end
+
+ # Get ios-sim executable path
+ # @param [String] version Xcode version
+ # @return [String] ios-sim executable path
+ def iphonesim_path(version)
+ installed = `which ios-sim`
+ if installed =~ /(.*ios-sim)/
+ puts "Using installed ios-sim at #{$1}"
+ return $1
+ end
+
+ File.join(File.dirname(__FILE__), '..', '..', 'native', 'ios-sim')
end
- File.join( File.dirname(__FILE__), '..', '..', 'native', 'ios-sim' )
end
end
+
+# Test
+def test(mode=1)
+ $DEBUG = 1
+ s = SimLauncher::Simulator.new
+ puts s.iphonesim_version
+
+ opts0 = { :retina => nil }
+ opts1 = { :retina => nil, :env => "env.plist" }
+ opts2 = { :retina => nil, :setenv => "dev=true" }
+ opts3 = {}
+
+ opts_all = [opts0, opts1, opts2, opts3]
+ s.start_simulator("6.1", "ipad", opts_all[mode])
+ s.launch_ios_app_with_options("build/TheAustralian.app", "6.1", "ipad", opts_all[mode])
end
diff --git a/lib/sim_launcher/version.rb b/lib/sim_launcher/version.rb
index 85333ee..6da835c 100644
--- a/lib/sim_launcher/version.rb
+++ b/lib/sim_launcher/version.rb
@@ -1,3 +1,5 @@
+# Simulator Launcher version
module SimLauncher
+ # Simulator Launcher version
VERSION = "0.4.9"
end
diff --git a/scripts/reset_simulator.applescript b/scripts/reset_simulator.applescript
index 11b0632..e67a009 100644
--- a/scripts/reset_simulator.applescript
+++ b/scripts/reset_simulator.applescript
@@ -1,7 +1,7 @@
tell application "System Events"
-
+
tell process "iPhone Simulator"
-
+
tell menu bar 1
tell menu bar item "iOs Simulator"
tell menu "iOs Simulator"
@@ -15,4 +15,4 @@ tell application "System Events"
click button "Reset"
end tell
end tell
-end tell
\ No newline at end of file
+end tell