On 04.11.2009 00:26, Hal Fulton wrote: > [Note: parts of this message were removed to make it a legal post.] > >> >> This will be difficult to do because then StringIO would somehow have >>>> to change its type. Of course you could achieve that with some kind >>>> of proxy pattern but I doubt that this would be a good idea; we all >>>> would always pay the price of the overhead (1 more object per IO / >>>> StringIO) for a feature which seems rarely wanted (I cannot recall >>>> having seen a request like this in years). >>>> >> Well, reopen also can take a string, I believe. So it already takes >>> more than one type. But the overhead argument is valid. >>> >> The string is interpreted as a file name. With changing type I meant that >> a StringIO after #reopen (either with number, IO object or string as file >> name) must behave like an IO or File object which is a different type. I >> was not talking about the argument types to method #reopen but the type of >> the object itself. >> > Yes - but what I meant was, reopen already checks its argument and > behaves differently based on what is passed in, so it *could* of course > check for a StringIO as well. Oh, that wasn't clear to me from your posting. I thought you were referring to the receiver being a StringIO object. Actually, when rereading your original posting both interpretations seem valid... > Yes, this obviously works, but it is irrelevant to what I am trying > to do. Well, _now_ I know. :-) >> How would I, for example, capture all that went to standard error >>> in a StringIO object? >>> >> You can try to do >> >> $stderr = StringIO.new >> >> but this works only within the same process, i.e. not for sub processes. >> There is no way I am aware of to redirect a file descriptor to an in memory >> structure. If you want the redirection to work for a child process and get >> the data in the parent you need to use one of the popen family of methods. > > > I am not interested in subprocesses actually. > > The problem with what you do here is that it changes the variable $stderr > to a different object (leaving the original object of course unaffected). > > So it depends, I think, on code referencing $stderr rather than STDERR. (The > code whose stderr I am catching is not necessarily my own.) > > Maybe I could also do const_set(STDERR, my_io) before any requires. That is > > something I have not tried. > > Another ugly trick, of course, would be something like doing a popen, a > reopen, > then read from the pipe periodically. Or perhaps even redirect stderr to a > file > and do a File::Tail on that... > > Ah, well. It is not something that will come up often. So you are trying to catch output of Ruby code run within the same process and of which you are not sure that it actually always references $stderr during write operations. You suspect it might store $stderr in some local variable and thus be unaffected by your change to the global variable. I'd say the risk is rather low since it does not really make sense to replace $stderr with something else (unless someone is a lazy typer). The problem remains the same: StringIO and IO / File are two different things and I believe there is no reasonable way to add functionality to them that they can mutate. The safest seems indeed to redirect the IO to a pipe, have a background thread read from the pipe and store data in a String or StringIO and then execute the code whose output you want to catch. As a nice side effect that would also work for subprocesses. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/