From 346ccf376c13bef58e575474a2f717b78dfa583d Mon Sep 17 00:00:00 2001
From: Dmitry Vorotilin <d.vorotilin@gmail.com>
Date: Wed, 26 Sep 2012 13:04:41 +0400
Subject: Kernel#capture replaced by version which can catch output from
 subprocesses

---
 activesupport/CHANGELOG.md                         |  1 +
 .../active_support/core_ext/kernel/reporting.rb    | 37 +++++++++++++++-------
 activesupport/test/core_ext/kernel_test.rb         |  2 ++
 3 files changed, 29 insertions(+), 11 deletions(-)

(limited to 'activesupport')

diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 1c1edc9048..73131128f7 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,4 +1,5 @@
 ## Rails 4.0.0 (unreleased) ##
+*   Kernel#capture can catch output from subprocesses *Dmitry Vorotilin*
 
 *   Make callstack attribute optional in
     ActiveSupport::Deprecation::Reporting methods `warn` and `deprecation_warning`
diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
index bc97da6ef2..7b518821c8 100644
--- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
@@ -1,4 +1,5 @@
 require 'rbconfig'
+require 'tempfile'
 
 module Kernel
   # Sets $VERBOSE to nil for the duration of the block and back to its original
@@ -66,19 +67,33 @@ module Kernel
 
   # Captures the given stream and returns it:
   #
-  #   stream = capture(:stdout) { puts 'Cool' }
-  #   stream # => "Cool\n"
+  #   stream = capture(:stdout) { puts 'notice' }
+  #   stream # => "notice\n"
+  #
+  #   stream = capture(:stderr) { warn 'error' }
+  #   stream # => "error\n"
+  #
+  # even for subprocesses:
+  #
+  #   stream = capture(:stdout) { system('echo notice') }
+  #   stream # => "notice\n"
+  #
+  #   stream = capture(:stderr) { system('echo error 1>&2') }
+  #   stream # => "error\n"
   def capture(stream)
-    begin
-      stream = stream.to_s
-      eval "$#{stream} = StringIO.new"
-      yield
-      result = eval("$#{stream}").string
-    ensure
-      eval("$#{stream} = #{stream.upcase}")
-    end
+    stream = stream.to_s
+    captured_stream = Tempfile.new(stream)
+    stream_io = eval("$#{stream}")
+    origin_stream = stream_io.dup
+    stream_io.reopen(captured_stream)
+
+    yield
 
-    result
+    stream_io.rewind
+    return captured_stream.read
+  ensure
+    captured_stream.unlink
+    stream_io.reopen(origin_stream)
   end
   alias :silence :capture
 
diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb
index 439bc87323..1583c1fa32 100644
--- a/activesupport/test/core_ext/kernel_test.rb
+++ b/activesupport/test/core_ext/kernel_test.rb
@@ -51,6 +51,8 @@ class KernelTest < ActiveSupport::TestCase
   def test_capture
     assert_equal 'STDERR', capture(:stderr) { $stderr.print 'STDERR' }
     assert_equal 'STDOUT', capture(:stdout) { print 'STDOUT' }
+    assert_equal "STDERR\n", capture(:stderr) { system('echo STDERR 1>&2') }
+    assert_equal "STDOUT\n", capture(:stdout) { system('echo STDOUT') }
   end
 end
 
-- 
cgit v1.2.3