From f4c16c57aad9138f236f4fa966893b21d5a64cbf Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 2 Feb 2025 16:17:37 +0900 Subject: [PATCH] [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 --- lib/optparse.rb | 6 +++--- test/optparse/test_optparse.rb | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 731d9bdb72..f849a9cc97 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -1056,7 +1056,7 @@ XXX end 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"] args = [{"LESS" => "#{!less || less.empty? ? '-' : less}Fe"}, pager, "w"] print = proc do |f| @@ -1065,7 +1065,7 @@ XXX # pager terminated end 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 end IO.popen(*args, &print) @@ -1107,7 +1107,7 @@ XXX # Officious['*-completion-zsh'] = proc do |parser| Switch::OptionalArgument.new do |arg| - parser.compsys(STDOUT, arg) + parser.compsys($stdout, arg) exit end end diff --git a/test/optparse/test_optparse.rb b/test/optparse/test_optparse.rb index 7f35cb4a8a..d50203bb63 100644 --- a/test/optparse/test_optparse.rb +++ b/test/optparse/test_optparse.rb @@ -184,10 +184,9 @@ class TestOptionParser < Test::Unit::TestCase File.open(File.join(dir, "options.rb"), "w") do |f| f.puts "#{<<~"begin;"}\n#{<<~'end;'}" begin; - stdout = STDOUT.dup + stdout = $stdout.dup def stdout.tty?; true; end - Object.__send__(:remove_const, :STDOUT) - STDOUT = stdout + $stdout = stdout ARGV.options do |opt| end; 100.times {|i| f.puts " opt.on('--opt-#{i}') {}"}