Rake’s sh for example cannot be captured with the normal $stdount = StringIO.new trick, but using some old ActiveSupport code that uses reopen with a Temfile seems to do the trick.
# StringIO does not work with rubies `system` call that `sh` uses under the hood, so using Tempfile + reopen
# https://grosser.it/2018/11/23/ruby-capture-stdout-without-stdout
def capture_stdout
old_stdout = STDOUT.dup
Tempfile.open('tee_stdout') do |capture|
STDOUT.reopen(capture)
STDOUT.sync = true
yield
capture.rewind
capture.read
end
ensure
STDOUT.reopen(old_stdout)
end