2013-10-31 63 views
2

编辑:不要打扰读这个问题,我只是不能删除它。它基于破碎的代码,这里几乎没有什么可学的。

我重定向控制台输出在我的Ruby程序,虽然它完美的作品有一两件事我很好奇:

这里是我的代码

capture = StringIO.new 
$stdout = capture 
puts "Hello World" 

看起来即使我m将capture对象分配给$stdout,$stdout在赋值后包含一个新的不同对象,但至少该类型是正确的。

换句话说:

$stdout.to_s    # => #<IO:0x2584b30> 

capture = StringIO.new 
$stdout = capture 

$stdout.to_s    # => #<StringIO:0x4fda948> 
capture.to_s    # => #<StringIO:0x4e3b220> 

随后$stdout.string包含"Hello World",但capture.string是空的。

在幕后发生了什么或者我在这里错过了什么吗?

编辑:这可能只针对某些版本。我在Windows 8.1上使用Ruby 2.0.0-p247

+0

也许它是重复? –

+0

是你的实际代码吗? – Stefan

+0

对不起,Felix和falsetru是正确的,'$ stdout'的值随后发生了变化。我没有注意到,因为'Hello World'这行代码实际上是一个代码的占位符,我从别人那里继承过来,而且我没有非常彻底地检查它。 - 那太浪费时间了,但是谢谢你帮助我! –

回答

1

你确定没有其他操作$stdoutcapture之间发生?

对我来说,输出看起来不一样。无论capture$stdout是同一个对象,并随后回答string具有相同的响应(红宝石1.9.2):

require 'stringio'                                
$stdout.to_s    # => #<IO:0x2584b30>                         

capture = StringIO.new                               
$stdout = capture                                

puts $stdout.to_s    # => #<StringIO:0x89a38c0>                      
puts capture.to_s    # => #<StringIO:0x89a38c0>                      
puts "redirected" 

$stderr.puts $stdout.string # => '#<StringIO:0x89a38c0>\n#<StringIO:0x89a38c0>\nredirected'                   
$stderr.puts capture.string # => '#<StringIO:0x89a38c0>\n#<StringIO:0x89a38c0>\nredirected' 
+0

我担心你可能是对的...现在检查。 –

2

它按预期工作。

>> capture = StringIO.new 
=> #<StringIO:0x00000001ea8c00> 
>> $stdout = capture 
>> $stdout.to_s 
>> capture.to_s 

上面两行不打印任何内容,因为$stdout现在已与终端断开连接。

所以我用$stderr.puts在以下行(也可以使用STDOUT.puts作为斯特凡评论):

>> $stderr.puts $stdout.to_s 
#<StringIO:0x00000001ea8c00> 
>> $stderr.puts capture.to_s 
#<StringIO:0x00000001ea8c00> 

$stdout.to_scapture.to_s给我同样的结果。

我用红宝石1.9.3。 (相同2.0.0)

+3

您可以使用'STDOUT.puts'来代替。 – Stefan

+0

@斯特凡,啊,你说得对。 – falsetru

+0

当然,我通过其他方式得到了'to_s'值:)正如我所说的,这里没有问题,我只是对发生的事情感到好奇。 –

1

虽然这个问题是俯瞰变化的$stdout值的结果,红宝石确实有以这种方式覆盖分配给全局变量的能力,至少在C api中,使用hooked variables

$stdout actually does make use of this检查新值是否是合适的(它检查whether the new value responds to write),如果它不抛出一个异常。

如果你真的想(你不这样做),你可以创建它由被称为dup定义了一个全局变量,自动存储不同的对象不是分配价值,也许是推广和使用,而不是:

#include "ruby.h" 

VALUE foo; 

static void foo_setter(VALUE val, ID id, VALUE *var){ 
    VALUE dup_val = rb_funcall(val, rb_intern("dup"), 0); 
    *var = dup_val; 
} 

void Init_hooked() { 
    rb_define_hooked_variable("$foo", &foo, 0, foo_setter); 
} 

然后,您可以使用它像:

2.0.0-p247 :001 > require './ext/hooked' 
=> true 
2.0.0-p247 :002 > s = Object.new 
=> #<Object:0x00000100b20560> 
2.0.0-p247 :003 > $foo = s 
=> #<Object:0x00000100b20560> 
2.0.0-p247 :004 > s.to_s 
=> "#<Object:0x00000100b20560>" 
2.0.0-p247 :005 > $foo.to_s 
=> "#<Object:0x00000100b3bea0>" 
2.0.0-p247 :006 > s == $foo 
=> false 

当然,这是非常相似,简单地创建一个类的setter方法是dup S中的淡水河谷并存储,您可以在纯Ruby的事:

def foo=(new_foo) 
    @foo = new_foo.dup 
end 

由于使用全局变量通常是糟糕的设计,所以对于全局变量来说这在Ruby中是不可能的。

相关问题