2

編集:この質問を読まないでください。削除できません。これは壊れたコードに基づいており、ここで学ぶことは (ほとんど) ありません。

Ruby プログラムでコンソール出力をリダイレクトしていますが、完全に動作しますが、気になる点が 1 つあります。

これが私のコードです

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

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を使用しています

4

3 に答える 3

1

この質問は の値の変更を見落とした結果でしたが$stdout、Ruby には、少なくとも C API では、フックされた変数を使用して、この方法でグローバル変数への割り当てをオーバーライドする機能があります。

$stdout実際にはこれを利用して、新しい値が適切かどうかをチェックし (新しい値が に応答するかどうか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 

もちろん、これは単純dupな Ruby で実行できる値を格納するクラスでセッター メソッドを作成することと非常によく似ています。

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

グローバル変数を使用することは一般的に悪い設計であるため、Ruby でグローバル変数を使用することはできないのが妥当と思われます。

于 2013-10-31T12:46:07.437 に答える
1

他の操作$stdoutcaptureその間に起こっていることはありませんか?

私にとって、出力は異なって見えます。captureとはどちらも$stdout同じオブジェクトであり、その後string同じ応答で応答します (ruby 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'
于 2013-10-31T11:25:11.173 に答える