Skip to content

Commit 899d10a

Browse files
authored
Polish the exit! command and its tests (#867)
* Remove IRB.irb_exit! method It's not necessary to introduce a new method just for the exit! command at this moment. * Rename ExitForcedAction to ForceExit * Move force exit tests to a dedicated file * Fix nested history saving with exit! command Because we switched to use `Kernel#exit` instead of `exit!`, the outer session's ensure block in `Irb#run` will be run, which will save the history. This means the separate check to save history when force exiting is no longer necessary. * execute_lines helper should also capture IRB setup's output This prevents setup warnings from being printed to test output while allowing those output to be tested. * Update readme
1 parent c0a5f31 commit 899d10a

File tree

8 files changed

+112
-70
lines changed

8 files changed

+112
-70
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ The following commands are available on IRB. You can get the same output from th
112112
```txt
113113
IRB
114114
exit Exit the current irb session.
115+
exit! Exit the current process.
115116
irb_load Load a Ruby file.
116117
irb_require Require a Ruby file.
117118
source Loads a given file in the current session.

lib/irb.rb

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -889,10 +889,6 @@ def IRB.irb_exit(*)
889889
throw :IRB_EXIT, false
890890
end
891891

892-
def IRB.irb_exit!(*)
893-
throw :IRB_EXIT, true
894-
end
895-
896892
# Aborts then interrupts irb.
897893
#
898894
# Will raise an Abort exception, or the given +exception+.
@@ -972,8 +968,7 @@ def run(conf = IRB.conf)
972968
conf[:IRB_RC].call(context) if conf[:IRB_RC]
973969
conf[:MAIN_CONTEXT] = context
974970

975-
supports_history_saving = conf[:SAVE_HISTORY] && context.io.support_history_saving?
976-
save_history = !in_nested_session && supports_history_saving
971+
save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
977972

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

996-
if forced_exit
997-
context.io.save_history if supports_history_saving
998-
Kernel.exit(0)
999-
else
1000-
context.io.save_history if save_history
1001-
end
991+
context.io.save_history if save_history
992+
Kernel.exit(0) if forced_exit
1002993
end
1003994
end
1004995

lib/irb/cmd/exit_forced_action.rb renamed to lib/irb/cmd/force_exit.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ module IRB
66
# :stopdoc:
77

88
module ExtendCommand
9-
class ExitForcedAction < Nop
9+
class ForceExit < Nop
1010
category "IRB"
1111
description "Exit the current process."
1212

1313
def execute(*)
14-
IRB.irb_exit!
14+
throw :IRB_EXIT, true
1515
rescue UncaughtThrowError
1616
Kernel.exit(0)
1717
end

lib/irb/extend-command.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def irb_context
3737
[:irb_quit, OVERRIDE_PRIVATE_ONLY],
3838
],
3939
[
40-
:irb_exit!, :ExitForcedAction, "cmd/exit_forced_action",
40+
:irb_exit!, :ForceExit, "cmd/force_exit",
4141
[:exit!, OVERRIDE_PRIVATE_ONLY],
4242
],
4343

test/irb/cmd/test_force_exit.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: false
2+
require 'irb'
3+
4+
require_relative "../helper"
5+
6+
module TestIRB
7+
class ForceExitTest < IntegrationTestCase
8+
def test_forced_exit_finishes_process_immediately
9+
write_ruby <<~'ruby'
10+
puts "First line"
11+
puts "Second line"
12+
binding.irb
13+
puts "Third line"
14+
binding.irb
15+
puts "Fourth line"
16+
ruby
17+
18+
output = run_ruby_file do
19+
type "123"
20+
type "456"
21+
type "exit!"
22+
end
23+
24+
assert_match(/First line\r\n/, output)
25+
assert_match(/Second line\r\n/, output)
26+
assert_match(/irb\(main\):001> 123/, output)
27+
assert_match(/irb\(main\):002> 456/, output)
28+
refute_match(/Third line\r\n/, output)
29+
refute_match(/Fourth line\r\n/, output)
30+
end
31+
32+
def test_forced_exit_in_nested_sessions
33+
write_ruby <<~'ruby'
34+
def foo
35+
binding.irb
36+
end
37+
38+
binding.irb
39+
binding.irb
40+
ruby
41+
42+
output = run_ruby_file do
43+
type "123"
44+
type "foo"
45+
type "exit!"
46+
end
47+
48+
assert_match(/irb\(main\):001> 123/, output)
49+
end
50+
end
51+
end

test/irb/test_cmd.rb

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ def teardown
3434
end
3535

3636
def execute_lines(*lines, conf: {}, main: self, irb_path: nil)
37-
IRB.init_config(nil)
38-
IRB.conf[:VERBOSE] = false
39-
IRB.conf[:PROMPT_MODE] = :SIMPLE
40-
IRB.conf[:USE_PAGER] = false
41-
IRB.conf.merge!(conf)
42-
input = TestInputMethod.new(lines)
43-
irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
44-
irb.context.return_format = "=> %s\n"
45-
irb.context.irb_path = irb_path if irb_path
46-
IRB.conf[:MAIN_CONTEXT] = irb.context
4737
capture_output do
38+
IRB.init_config(nil)
39+
IRB.conf[:VERBOSE] = false
40+
IRB.conf[:PROMPT_MODE] = :SIMPLE
41+
IRB.conf[:USE_PAGER] = false
42+
IRB.conf.merge!(conf)
43+
input = TestInputMethod.new(lines)
44+
irb = IRB::Irb.new(IRB::WorkSpace.new(main), input)
45+
irb.context.return_format = "=> %s\n"
46+
irb.context.irb_path = irb_path if irb_path
47+
IRB.conf[:MAIN_CONTEXT] = irb.context
4848
irb.eval_input
4949
end
5050
end
@@ -58,7 +58,9 @@ def test_calling_command_on_a_frozen_main
5858
"irb_info",
5959
main: main
6060
)
61-
assert_empty err
61+
# Because the main object is frozen, IRB would wrap a delegator around it
62+
# Which's exit! method can't be overridden and would raise a warning
63+
assert_match(/delegator does not forward private method #exit\!/, err)
6264
assert_match(/RUBY_PLATFORM/, out)
6365
end
6466
end

test/irb/test_debug_cmd.rb

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -255,47 +255,6 @@ def test_exit
255255
assert_match(/irb\(main\):001> next/, output)
256256
end
257257

258-
def test_forced_exit_finishes_process_when_nested_sessions
259-
write_ruby <<~'ruby'
260-
puts "First line"
261-
puts "Second line"
262-
binding.irb
263-
puts "Third line"
264-
binding.irb
265-
puts "Fourth line"
266-
ruby
267-
268-
output = run_ruby_file do
269-
type "123"
270-
type "456"
271-
type "exit!"
272-
end
273-
274-
assert_match(/First line\r\n/, output)
275-
assert_match(/Second line\r\n/, output)
276-
assert_match(/irb\(main\):001> 123/, output)
277-
assert_match(/irb\(main\):002> 456/, output)
278-
refute_match(/Third line\r\n/, output)
279-
refute_match(/Fourth line\r\n/, output)
280-
end
281-
282-
def test_forced_exit
283-
write_ruby <<~'ruby'
284-
puts "Hello"
285-
binding.irb
286-
ruby
287-
288-
output = run_ruby_file do
289-
type "123"
290-
type "456"
291-
type "exit!"
292-
end
293-
294-
assert_match(/Hello\r\n/, output)
295-
assert_match(/irb\(main\):001> 123/, output)
296-
assert_match(/irb\(main\):002> 456/, output)
297-
end
298-
299258
def test_quit
300259
write_ruby <<~'RUBY'
301260
binding.irb

test/irb/test_history.rb

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,20 +379,58 @@ def foo
379379
HISTORY
380380
end
381381

382-
def test_history_saving_with_exit!
382+
def test_nested_history_saving_from_inner_session_with_exit!
383383
write_history ""
384384

385385
write_ruby <<~'RUBY'
386+
def foo
387+
binding.irb
388+
end
389+
386390
binding.irb
387391
RUBY
388392

389393
run_ruby_file do
390-
type "'starting session'"
394+
type "'outer session'"
395+
type "foo"
396+
type "'inner session'"
391397
type "exit!"
392398
end
393399

394400
assert_equal <<~HISTORY, @history_file.open.read
395-
'starting session'
401+
'outer session'
402+
foo
403+
'inner session'
404+
exit!
405+
HISTORY
406+
end
407+
408+
def test_nested_history_saving_from_outer_session_with_exit!
409+
write_history ""
410+
411+
write_ruby <<~'RUBY'
412+
def foo
413+
binding.irb
414+
end
415+
416+
binding.irb
417+
RUBY
418+
419+
run_ruby_file do
420+
type "'outer session'"
421+
type "foo"
422+
type "'inner session'"
423+
type "exit"
424+
type "'outer session again'"
425+
type "exit!"
426+
end
427+
428+
assert_equal <<~HISTORY, @history_file.open.read
429+
'outer session'
430+
foo
431+
'inner session'
432+
exit
433+
'outer session again'
396434
exit!
397435
HISTORY
398436
end

0 commit comments

Comments
 (0)