[ruby/optparse] Make the result of tty? obtainable with flexible stdout

In mock testing for stdout, `StringIO.new` is sometimes used to redirect the output.
In such cases, the assignment is done with `$stdout = StringIO.new`, not the constant `STDOUT`.
e.g., https://github.com/rubocop/rubocop/blob/v1.71.1/lib/rubocop/rspec/shared_contexts.rb#L154-L164

After assigning `StringIO.new`, `$stdout.tty?` returns `false`,
allowing the standard output destination to be switched during test execution.

```ruby
STDOUT.tty?       # => true
StringIO.new.tty? # => false
```

However, since `STDOUT.tty?` returns `true`, a failure occurred in environments
where the environment variables `RUBY_PAGER` or `PAGER` are set.
e.g., https://github.com/rubocop/rubocop/pull/13784

To address this, `STDOUT` has been updated to `$stdout` so that the result of `tty?` can be flexibly overridden.

A potential concern is that `$stdout`, unlike `STDOUT`,
does not always represent the standard output at the time the Ruby process started.
However, no concrete examples of issues related to this have been identified.

`STDOUT.tty?` is the logic of optparse introduced in https://github.com/ruby/optparse/pull/70.

This PR replaces `STDOUT` with `$stdout` throughout, based on the assumption
that `$stdout` is sufficient for use with optparse.

https://github.com/ruby/optparse/commit/262cf6f9ac
This commit is contained in:
Koichi ITO 2025-02-02 16:17:37 +09:00 committed by git
parent 45e8dc1e85
commit f4c16c57aa
2 changed files with 5 additions and 6 deletions

View File

@ -1056,7 +1056,7 @@ XXX
end end
def help_exit def help_exit
if STDOUT.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?}) if $stdout.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
less = ENV["LESS"] less = ENV["LESS"]
args = [{"LESS" => "#{!less || less.empty? ? '-' : less}Fe"}, pager, "w"] args = [{"LESS" => "#{!less || less.empty? ? '-' : less}Fe"}, pager, "w"]
print = proc do |f| print = proc do |f|
@ -1065,7 +1065,7 @@ XXX
# pager terminated # pager terminated
end end
if Process.respond_to?(:fork) and false if Process.respond_to?(:fork) and false
IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call(STDOUT)} IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call($stdout)}
# unreachable # unreachable
end end
IO.popen(*args, &print) IO.popen(*args, &print)
@ -1107,7 +1107,7 @@ XXX
# #
Officious['*-completion-zsh'] = proc do |parser| Officious['*-completion-zsh'] = proc do |parser|
Switch::OptionalArgument.new do |arg| Switch::OptionalArgument.new do |arg|
parser.compsys(STDOUT, arg) parser.compsys($stdout, arg)
exit exit
end end
end end

View File

@ -184,10 +184,9 @@ class TestOptionParser < Test::Unit::TestCase
File.open(File.join(dir, "options.rb"), "w") do |f| File.open(File.join(dir, "options.rb"), "w") do |f|
f.puts "#{<<~"begin;"}\n#{<<~'end;'}" f.puts "#{<<~"begin;"}\n#{<<~'end;'}"
begin; begin;
stdout = STDOUT.dup stdout = $stdout.dup
def stdout.tty?; true; end def stdout.tty?; true; end
Object.__send__(:remove_const, :STDOUT) $stdout = stdout
STDOUT = stdout
ARGV.options do |opt| ARGV.options do |opt|
end; end;
100.times {|i| f.puts " opt.on('--opt-#{i}') {}"} 100.times {|i| f.puts " opt.on('--opt-#{i}') {}"}