8

我正在为 Rails 开发编写一个基于 Web 的开发控制台。在我的一个控制器操作中,我调用了 Rake,但我无法捕获 Rake 生成的任何输出。例如,这里有一些来自控制器的示例代码:

require 'rake'
require 'rake/rdoctask'
require 'rake/testtask'
require 'tasks/rails'
require 'stringio'

...

def show_routes

  @results = capture_stdout { Rake.tasks['routes'].invoke }

  # @results is nil -- the capture_stdout doesn't catpure anything that Rake generates

end

def capture_stdout
  s = StringIO.new
  $stdout = s
  yield
  s.string
ensure
  $stdout = STDOUT
end

有人知道为什么我无法捕获 Rake 输出吗?我试过通过 Rake 源,我看不到它在哪里触发一个新进程或任何东西,所以我认为我应该能够做到这一点。

非常感谢!阿德里安


从那以后,我发现了从 Ruby 内部调用 Rake 的正确方法,效果更好:

Rake.application['db:migrate:redo'].reenable
Rake.application['db:migrate:redo'].invoke

奇怪的是,有些 rake 任务现在可以完美运行(路由),有些在第一次运行时捕获输出,之后总是空白(db:migrate:redo),有些似乎从未捕获输出(测试)。奇怪的。

4

4 回答 4

4

虽然这是某种 hack(因为 Rack 是用 ruby​​ 编写的),但您可以使用 open3 的popen3方法并像从命令行一样调用 rake 任务。

在你的情况下,你会这样使用它

require 'open3'

buffer = []
Open3::popen3("rake db:migrate:redo") do |stdin,stdout,stderr|
  begin
    while line = stdout.readline
      buffer << line
    end
  rescue
  end
end

所以你最终会得到所有 rake 返回到 stdout in 的行buffer。也许这更可靠,但我建议调查您描述的奇怪行为的来源。

于 2009-11-25T23:21:22.163 回答
2

好吧,我知道 ZenTest 能够通过“until_capture”捕获“puts”语句,我什至发现有人通过扩展 Kernel 模块并将 $stdout 重定向到 StringIO 的实例来编写自定义实现。

希望有帮助:
http ://thinkingdigitally.com/archive/capturing-output-from-puts-in-ruby/

您可能还想查看 Matthias Hennemeyer 的 OutputCatcher:http:
//github.com/mhennemeyer/output_catcher

于 2009-09-17T19:17:45.543 回答
1

gems/rake-0.8.7/lib/rake.rb 的第 1174 行:

  # Send the message to the default rake output (which is $stderr).
  def rake_output_message(message)
    $stderr.puts(message)
  end
  private :rake_output_message

也许尝试捕获 STDERR 以及 STDOUT?

我并不是说所有的输出都是通过 完成的$stderr,但是 rake 本身似乎已经建立了这个约定,也许有人让某些 rake 任务覆盖 put to direct to $stderr

我没有测试过这个想法。

于 2010-04-12T02:35:30.223 回答
1

这对我有用:

$stdout.reopen("my.log", "w")
$stdout.sync = true

# do your thing

$stdout = STDOUT

见于:https ://stackoverflow.com/a/2480439/21217

于 2012-12-13T14:07:28.477 回答