From ef6d5f9054fec5264aab5813718b3489def4a592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20=C5=A0im=C3=A1nek?= Date: Sat, 22 Aug 2026 10:14:44 +0200 Subject: [PATCH] Show the startup banner only when stdin is a tty The banner was printed for any `exe/irb` run without a script argument, so piped sessions like `echo '1+1' | irb` got it on stdout. The tip line is picked at random, which also made that output differ between runs. --- lib/irb.rb | 2 +- test/irb/test_startup_message.rb | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/irb.rb b/lib/irb.rb index af65c8a13..86a1b6f6b 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -53,7 +53,7 @@ def start(ap_path = nil) irb = Irb.new # Only display the banner in the irb executable - if @CONF[:SHOW_BANNER] && ap_path&.end_with?("exe/irb") + if @CONF[:SHOW_BANNER] && ap_path&.end_with?("exe/irb") && STDIN.tty? StartupMessage.display end end diff --git a/test/irb/test_startup_message.rb b/test/irb/test_startup_message.rb index 6b7cbbf4b..8fff7b1ac 100644 --- a/test/irb/test_startup_message.rb +++ b/test/irb/test_startup_message.rb @@ -67,5 +67,59 @@ def test_banner_does_not_appear_on_binding_irb assert_not_match(/v#{Regexp.escape(IRB::VERSION)}/, output) end + + def test_banner_appears_when_stdin_is_a_tty + output = run_irb_with_tty + + assert_match(/v#{Regexp.escape(IRB::VERSION)}/, output) + end + + def test_banner_does_not_appear_when_stdin_is_not_a_tty + output = run_irb_without_tty + + assert_not_match(/v#{Regexp.escape(IRB::VERSION)}/, output) + end + + private + + def irb_command + [EnvUtil.rubybin, "-I", LIB, File.expand_path("../../exe/irb", __dir__), "-f"] + end + + def irb_envs(tmp_dir) + { "TERM" => "dumb", "HOME" => tmp_dir, "XDG_CONFIG_HOME" => tmp_dir, "IRBRC" => nil } + end + + def run_irb_with_tty + lines = [] + + Dir.mktmpdir do |tmp_dir| + PTY.spawn(irb_envs(tmp_dir), *irb_command) do |read, write, pid| + write.puts "exit" + + Timeout.timeout(TIMEOUT_SEC) do + while line = safe_gets(read) + lines << line + end + end + ensure + read.close + write.close + kill_safely(pid) + end + end + + lines.join + end + + def run_irb_without_tty + Dir.mktmpdir do |tmp_dir| + IO.popen(irb_envs(tmp_dir), irb_command, "r+", err: [:child, :out]) do |io| + io.puts "exit" + io.close_write + io.read + end + end + end end end