Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

New public API to support all of the ios-sim command line options #22

Open
wants to merge 3 commits into from

2 participants

@mgrebenets

Hi.

I really wanted sim_launcher to support more command line options of ios-sim, especially options like :retina, :tall and :env.
I am aware of #16 pull request, but it has too many changes for me to grasp, also deals with things like Frank, Sinatra and so on. And it's been there for quite a while as well, with no progress.

So I tried to come up with minimum changes required to support more ios-sim options.

I also kept the public API unchanged (launch_ios_app) so it's backwards compatible.

The start_simulator, launch_ipad_app, launch_ipad_app_with_name, launch_iphone_app, launch_iphone_app_with_name are backwards compatible as well. They do have new arguments, but these arguments have default values, so it won't break existing code.

The new public API is launch_ios_app_with_options, it's almost same as launch_ios_app with addition of one new argument options. This options hash can be used to pass any command line option that ios-sim supports.
Here are some examples

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

I know that :retina => nil might be a bit confusing, I'd welcome any suggestions on this one.

This is pretty much all the change.

The differences look big because of the comments added to document the code.
You can now run yardoc . and get 100% code documented.

Finally, I was confused by mixed styling in the code.
Some places use spaces around operands, some don't.
Some pieces of code put spaces around ( and ), others don't.
So followed https://github.com/bbatsov/ruby-style-guide and https://github.com/styleguide/ruby to make the code consistent, but after all that's just cosmetic change.

Maksym Grebe... added some commits
Maksym Grebenets Add ios app launcher with options, document code
- Add new method  to launch simulator with options
- Keep  for backwards compatibility
- Modify , ,  and  to support options and app arguments
  - Make update safe for backwards compatibility
- Document all the code to get 100 percent documentation coverage (used yardoc)
a4121c1
Maksym Grebenets Remote test method c8a0743
Maksym Grebenets Minor typo fix b2bc3fa
@mokagio

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 17, 2013
  1. Add ios app launcher with options, document code

    Maksym Grebenets authored
    - Add new method  to launch simulator with options
    - Keep  for backwards compatibility
    - Modify , ,  and  to support options and app arguments
      - Make update safe for backwards compatibility
    - Document all the code to get 100 percent documentation coverage (used yardoc)
Commits on Oct 18, 2013
  1. Remote test method

    Maksym Grebenets authored
  2. Minor typo fix

    Maksym Grebenets authored
This page is out of date. Refresh to see the latest.
View
18 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
View
43 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 )
+ # 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
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"
View
37 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
View
8 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
View
243 lib/sim_launcher/simulator.rb
@@ -1,108 +1,189 @@
+# 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [String] device_family Device family (<i>"iphone"</i>, <i>"ipad"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable
+ # @option options [nil] :retina Retina device, use _nil_ value (<i>:retina => nil</i>)
+ # @option options [nil] :tall Tall retina device (4-inch), use _nil_ value (<i>:tall => nil</i>)
+ # @option options [String] :env Environment variables plist file
+ # @option options [String] :setenv Evnironment varible key-valur pair (<i>:setenv => "DEBUG=1"</i>)
+ # @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<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [String] device_family Device family (<i>"iphone"</i>, <i>"ipad"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [String] device_family Device family (<i>"iphone"</i>, <i>"ipad"</i>)
+ # @param [Array<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array<String>] 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. <i>"6.1"</i>, <i>"7.0"</i>)
+ # @param [Hash] options Addtional options to pass to ios-sim executable (@see start_simulator)
+ # @param [Array<String>] 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<String>] 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<String>] 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
-end
View
2  lib/sim_launcher/version.rb
@@ -1,3 +1,5 @@
+# Simulator Launcher version
module SimLauncher
+ # Simulator Launcher version
VERSION = "0.4.9"
end
View
6 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
+end tell
Something went wrong with that request. Please try again.