Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,11 @@ def IRB.start(ap_path = nil)

# Quits irb
def IRB.irb_exit(*)
throw :IRB_EXIT
throw :IRB_EXIT, false
end

def IRB.irb_exit!(*)
throw :IRB_EXIT, true
end

# Aborts then interrupts irb.
Expand Down Expand Up @@ -968,7 +972,8 @@ def run(conf = IRB.conf)
conf[:IRB_RC].call(context) if conf[:IRB_RC]
conf[:MAIN_CONTEXT] = context

save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
supports_history_saving = conf[:SAVE_HISTORY] && context.io.support_history_saving?
save_history = !in_nested_session && supports_history_saving

if save_history
context.io.load_history
Expand All @@ -979,13 +984,21 @@ def run(conf = IRB.conf)
end

begin
catch(:IRB_EXIT) do
forced_exit = false

forced_exit = catch(:IRB_EXIT) do
eval_input
end
ensure
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}
context.io.save_history if save_history

if forced_exit
context.io.save_history if supports_history_saving
Kernel.exit(0)
else
context.io.save_history if save_history
end
end
end

Expand Down
22 changes: 22 additions & 0 deletions lib/irb/cmd/exit_forced_action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require_relative "nop"

module IRB
# :stopdoc:

module ExtendCommand
class ExitForcedAction < Nop
category "IRB"
description "Exit the current process."

def execute(*)
IRB.irb_exit!
rescue UncaughtThrowError
Kernel.exit(0)
end
end
end

# :startdoc:
end
5 changes: 5 additions & 0 deletions lib/irb/extend-command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def irb_context
[:quit, OVERRIDE_PRIVATE_ONLY],
[:irb_quit, OVERRIDE_PRIVATE_ONLY],
],
[
:irb_exit!, :ExitForcedAction, "cmd/exit_forced_action",
[:exit!, OVERRIDE_PRIVATE_ONLY],
],

[
:irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
[:cwws, NO_OVERRIDE],
Expand Down
41 changes: 41 additions & 0 deletions test/irb/test_debug_cmd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,47 @@ def test_exit
assert_match(/irb\(main\):001> next/, output)
end

def test_forced_exit_finishes_process_when_nested_sessions
write_ruby <<~'ruby'
puts "First line"
puts "Second line"
binding.irb
puts "Third line"
binding.irb
puts "Fourth line"
ruby

output = run_ruby_file do
type "123"
type "456"
type "exit!"
end

assert_match(/First line\r\n/, output)
assert_match(/Second line\r\n/, output)
assert_match(/irb\(main\):001> 123/, output)
assert_match(/irb\(main\):002> 456/, output)
refute_match(/Third line\r\n/, output)
refute_match(/Fourth line\r\n/, output)
end

def test_forced_exit
write_ruby <<~'ruby'
puts "Hello"
binding.irb
ruby

output = run_ruby_file do
type "123"
type "456"
type "exit!"
end

assert_match(/Hello\r\n/, output)
assert_match(/irb\(main\):001> 123/, output)
assert_match(/irb\(main\):002> 456/, output)
end

def test_quit
write_ruby <<~'RUBY'
binding.irb
Expand Down
18 changes: 18 additions & 0 deletions test/irb/test_history.rb
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,24 @@ def foo
HISTORY
end

def test_history_saving_with_exit!
write_history ""

write_ruby <<~'RUBY'
binding.irb
RUBY

run_ruby_file do
type "'starting session'"
type "exit!"
end

assert_equal <<~HISTORY, @history_file.open.read
'starting session'
exit!
HISTORY
end

def test_history_saving_with_nested_sessions_and_prior_history
write_history <<~HISTORY
old_history_1
Expand Down