4

I am doing iOS testing using Frank. It is a ruby gem that uses Cucumber as well. I have a "Given" step that checks whether the app is running or if it has crashed. If my step finds that it has crashed I would like to launch the app again. I launch the app using a shell script which is stored somewhere near the cucumber .feature files.

How can I call a script from that step definition?

SirRupertIII
  • 12,324
  • 20
  • 72
  • 121

4 Answers4

4

You can do this a few different ways

Kernel.system "command"
%x[command]
`command`
Oliver Atkinson
  • 7,970
  • 32
  • 43
  • By the way, you don't need the `Kernel.`; that module is already included into Object by default. Or something like that. – Jwosty Jul 29 '13 at 19:27
  • 2
    Yes, unless you have a local method with the same name, the `Kernel` prefix is redundant, however it's relevant for looking up documentation. Those magical methods that show up everywhere are usually in Kernel. – tadman Jul 29 '13 at 19:51
  • It's always good to namespace, for the exact reason @tadman stated. – Oliver Atkinson Jul 29 '13 at 19:53
2

As other answers suggested, there are many ways of executing shell scripts from Ruby, but they're all not created equal. I'll try to explain all methods i know in more detail.

Backticks

`command arg1 arg2`
%x(command arg1 arg2)

Runs the command in a subshell and returns the output of the command. The command and its arguments are provided as a string delimited by backticks. An alternative syntax is %x(...) which serves to avoid escaping issues, e.g. when you want to execute a command that contains backticks itself. The parentheses can be replaced by other delimiters such as [], {}, !!, … in order to be able to work around just about any escaping issue.

Stderr is printed as normal, Stdout is suppressed. Returns the stdout output of the command. This means you can use the backtick notation to get the output of a command into a variable for further processing.

Kernel.exec

exec("command arg1 arg2")
exec("command", "arg1", "arg2")

Replaces the current process by running the command. The command and its arguments are provided as a normal string or as a comma delimited list of strings. Can be useful if you already have a list of arguments as an array. Output is left as is, i.e. will be printed to the console as if the command was run directly.

Kernel.system

system("command arg1 arg2")
system("command","arg1 arg2")

Like Kernel.exec but runs in a subshell again. Returns true if the process exited correctly (status 0), false otherwise. This works great inside if-statements.

Kernel.spawn

pid = spawn("command")
# do other stuff
Process.wait(pid)

Similar to Kernel.system but will spawn a child process to run the specified command. The parent process will thus not wait for the command to finish executing unless Process.wait is used. The return value is the PID of the spawned process.

IO.popen

io = IO.popen("command")
IO.popen("command") {|io| ... }

Runs the command in a child process again but allows for greater control over the IO. The child processes' stdout and stdin are connected to an IO object that is either accessible as the return value or a block parameter. If obtained via return value, the IO object should be closed after using it with io.close.

Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
1

Open3

For use-cases more advanced than system or IO.popen, you can use Open3 from the Ruby standard library. Its popen3 method lets you manually interact with the stdin, stdout, and stderr of the child process. Open3’s popen2 method is the same except it doesn’t give you stderr. An example of using popen2:

require 'open3'

Open3.popen2("wc -c") do |stdin, stdout, status_thread|
  stdin.print "answer to life the universe and everything"
  stdin.close
  p stdout.gets #=> "42\n"
end
Community
  • 1
  • 1
Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
-1

Here are some nice ways. Backticks are probably the least intrusive. But beware: as pointed out by tadman, exec terminates the calling process, which can be averted by creating a child process or using system.

Jwosty
  • 3,497
  • 2
  • 22
  • 50
  • Great link! you Goggled.. :) – Arup Rakshit Jul 29 '13 at 19:25
  • Remember that [`exec`](http://www.ruby-doc.org/core-2.0/Kernel.html#method-i-exec) effectively terminates the calling process so you'll never get a response, so it's probably last in that list. Why is it the most "readable"? – tadman Jul 29 '13 at 19:50
  • I didn't realize that it does that... As for readability, someone not familiar with Ruby would probably figure out what it does pretty quickly, as opposed to the backticks. – Jwosty Jul 29 '13 at 20:27
  • What they won't figure out is that it'll terminate your process and never return anything, so it should really be avoided. Backticks are something that Ruby has in common with Perl, so it's not entirely unexpected. – tadman Jul 29 '13 at 20:49
  • Alright, I've updated the answer to reflect this information. Thanks for your input! :) – Jwosty Jul 29 '13 at 20:58