2

I'm using a helper script to execute rspec tests.

command = "rake spec #{path} #{scope}"
output = `#{command}`
puts output

This works fine, except that I lose all the colors from the rake rspec output. The appropriate ANSI codes do not appear to be contained within the output string.

How can I execute a process so that it returns output which includes the text color?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Craig Walker
  • 49,871
  • 54
  • 152
  • 212
  • Possible duplicate of [Ruby popen3 and ANSI colour](https://stackoverflow.com/questions/5526842/ruby-popen3-and-ansi-colour) – thisismydesign Nov 26 '17 at 18:56

4 Answers4

2

Kernel.exec() gets me the solution I want (colored rspec output), but it does so by replacing my ruby script process with the rspec process. That means I can't do anything with the output or run anything after the rspec call.

That's acceptable in my particular situation, but less than ideal as a general solution. So I'd like a better answer if available.

Craig Walker
  • 49,871
  • 54
  • 152
  • 212
1

RSpec will disable colour if it is not writing to a tty (i.e. the console).

In case of RSpec you can force colouring by rspec --tty or via rake by rake spec SPEC_OPTS=' --tty'.

See also Ruby popen3 and ANSI colour

However this solution is still specific to Rspec. I'd be interested to hear a general one.

thisismydesign
  • 21,553
  • 9
  • 123
  • 126
1

Turns out it's possible to run commands in a pseudo terminal via the PTY module in order to preserve a user facing terminal-like behaviour. Credits go to the creator of the tty-command gem (see this issue) who implemented this behaviour in his gem:

require 'tty-command'
cmd = TTY::Command.new(pty: true)
cmd.run('rake', 'rspec')

Keep in mind that using a pseudo terminal may have unwanted side effects, such as certain git commands using a pager which will essentially cause commands to hang. So introducing the functionality might be a breaking change.

thisismydesign
  • 21,553
  • 9
  • 123
  • 126
0

If you don't want to replace your ruby process with that command, use Kernel.system() or Kernel.spawn() instead of a Kernel.exec(). Both of them execute your command in a subshell, system waits for the subprocess to finish, spawn returns its pid and you have to wait by yourself using Process.wait pid.

command = "rake spec #{path} #{scope}"
system(command)

or

command = "rake spec #{path} #{scope}"
pid = spawn(command)
# Some other stuff here
Process.wait pid