From 94a74b9b6a16be65c5973a63972a026119896f81 Mon Sep 17 00:00:00 2001 From: joe-sharp Date: Mon, 2 Nov 2026 13:09:06 -0600 Subject: [PATCH] Preserve an existing `_` local when creating a WorkSpace WorkSpace#initialize unconditionally ran `local_variable_set(:_, nil)`. When the binding already had a `_` local, Binding#local_variable_set overwrote the program's variable, so `_ = :mine; binding.irb` showed nil. The debugger's IRB console mode creates a new WorkSpace at every prompt, so the value was reset each time. Only set `_` to nil when the binding does not already define it. Refs #891 Co-Authored-By: Claude Haiku 5.5 --- lib/irb/workspace.rb | 2 +- test/irb/test_debugger_integration.rb | 16 ++++++++++++++++ test/irb/test_workspace.rb | 12 ++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb index 9fef8f86a..b384bb7b6 100644 --- a/lib/irb/workspace.rb +++ b/lib/irb/workspace.rb @@ -87,7 +87,7 @@ def initialize(*main) end end - @binding.local_variable_set(:_, nil) + @binding.local_variable_set(:_, nil) unless @binding.local_variable_defined?(:_) end # The Binding of this workspace diff --git a/test/irb/test_debugger_integration.rb b/test/irb/test_debugger_integration.rb index 9c71fb1eb..cfd71d863 100644 --- a/test/irb/test_debugger_integration.rb +++ b/test/irb/test_debugger_integration.rb @@ -426,6 +426,22 @@ def test_irb_command_can_check_local_variables assert_include(output, '"FooBar"') end + def test_irb_console_mode_keeps_program_defined_underscore + @envs.merge!("RUBY_DEBUG_IRB_CONSOLE" => "true") + write_ruby <<~'ruby' + _ = :mine + binding.irb + ruby + + output = run_ruby_file do + type "debug" + type "_" + type "continue" + end + assert_match(/^:mine\r?$/, output) + assert_no_match(/^nil\r?$/, output) + end + def test_help_command_is_delegated_to_the_debugger write_ruby <<~'ruby' binding.irb diff --git a/test/irb/test_workspace.rb b/test/irb/test_workspace.rb index 99ade80f6..15c46f1a3 100644 --- a/test/irb/test_workspace.rb +++ b/test/irb/test_workspace.rb @@ -38,6 +38,18 @@ def test_code_around_binding IRB.conf.delete(:USE_COLORIZE) end + def test_workspace_keeps_existing_underscore + _ = :mine + IRB::WorkSpace.new(binding) + assert_equal(:mine, _) + end + + def test_workspace_defines_underscore_as_nil_when_absent + workspace = IRB::WorkSpace.new(binding) + assert_equal(true, workspace.binding.local_variable_defined?(:_)) + assert_nil(workspace.binding.local_variable_get(:_)) + end + def test_code_around_binding_with_existing_unreadable_file pend 'chmod cannot make file unreadable on windows' if windows? pend 'skipped in root privilege' if Process.uid == 0