Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish the exit! command and its tests #867

Merged
merged 6 commits into from
Feb 11, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ The following commands are available on IRB. You can get the same output from th
```txt
IRB
exit Exit the current irb session.
exit! Exit the current process.
irb_load Load a Ruby file.
irb_require Require a Ruby file.
source Loads a given file in the current session.
Expand Down
15 changes: 3 additions & 12 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -889,10 +889,6 @@ def IRB.irb_exit(*)
throw :IRB_EXIT, false
end

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

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

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

if save_history
context.io.load_history
Expand All @@ -993,12 +988,8 @@ def run(conf = IRB.conf)
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend exit or exit(true) instead of exit(0).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Address it in #868

end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ module IRB
# :stopdoc:

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

def execute(*)
IRB.irb_exit!
throw :IRB_EXIT, true
rescue UncaughtThrowError
Kernel.exit(0)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/irb/extend-command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def irb_context
[:irb_quit, OVERRIDE_PRIVATE_ONLY],
],
[
:irb_exit!, :ExitForcedAction, "cmd/exit_forced_action",
:irb_exit!, :ForceExit, "cmd/force_exit",
[:exit!, OVERRIDE_PRIVATE_ONLY],
],

Expand Down
51 changes: 51 additions & 0 deletions test/irb/cmd/test_force_exit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: false
require 'irb'

require_relative "../helper"

module TestIRB
class ForceExitTest < IntegrationTestCase
def test_forced_exit_finishes_process_immediately
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_in_nested_sessions
write_ruby <<~'ruby'
def foo
binding.irb
end

binding.irb
binding.irb
ruby

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

assert_match(/irb\(main\):001> 123/, output)
end
end
end
24 changes: 13 additions & 11 deletions test/irb/test_cmd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ def teardown
end

def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
IRB.init_config(nil)
IRB.conf[:VERBOSE] = false
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:USE_PAGER] = false
IRB.conf.merge!(conf)
input = TestInputMethod.new(lines)
irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
irb.context.return_format = "=> %s\n"
irb.context.irb_path = irb_path if irb_path
IRB.conf[:MAIN_CONTEXT] = irb.context
capture_output do
IRB.init_config(nil)
IRB.conf[:VERBOSE] = false
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:USE_PAGER] = false
IRB.conf.merge!(conf)
input = TestInputMethod.new(lines)
irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
irb.context.return_format = "=> %s\n"
irb.context.irb_path = irb_path if irb_path
IRB.conf[:MAIN_CONTEXT] = irb.context
irb.eval_input
end
end
Expand All @@ -58,7 +58,9 @@ def test_calling_command_on_a_frozen_main
"irb_info",
main: main
)
assert_empty err
# Because the main object is frozen, IRB would wrap a delegator around it
# Which's exit! method can't be overridden and would raise a warning
assert_match(/delegator does not forward private method #exit\!/, err)
assert_match(/RUBY_PLATFORM/, out)
end
end
Expand Down
41 changes: 0 additions & 41 deletions test/irb/test_debug_cmd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,47 +255,6 @@ 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
44 changes: 41 additions & 3 deletions test/irb/test_history.rb
Original file line number Diff line number Diff line change
Expand Up @@ -379,20 +379,58 @@ def foo
HISTORY
end

def test_history_saving_with_exit!
def test_nested_history_saving_from_inner_session_with_exit!
write_history ""

write_ruby <<~'RUBY'
def foo
binding.irb
end

binding.irb
RUBY

run_ruby_file do
type "'starting session'"
type "'outer session'"
type "foo"
type "'inner session'"
type "exit!"
end

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

def test_nested_history_saving_from_outer_session_with_exit!
write_history ""

write_ruby <<~'RUBY'
def foo
binding.irb
end

binding.irb
RUBY

run_ruby_file do
type "'outer session'"
type "foo"
type "'inner session'"
type "exit"
type "'outer session again'"
type "exit!"
end

assert_equal <<~HISTORY, @history_file.open.read
'outer session'
foo
'inner session'
exit
'outer session again'
exit!
HISTORY
end
Expand Down