Skip to content

Commit

Permalink
[WIP] Implement exit_program (!!!) command
Browse files Browse the repository at this point in the history
Pry includes an `exit-program` command, also aliased as `quit-program`
and `!!!` which calls `Kernel.exit`. This is useful when `binding.pry`
has been used in a loop.

This implements a similar `exit_program` command, also aliased as
`quit_program` and `!!!`.
  • Loading branch information
sambostock committed Dec 25, 2023
1 parent a14fc6c commit 330baa6
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 2 deletions.
16 changes: 16 additions & 0 deletions lib/irb/cmd/exit_program.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

require_relative "nop"

module IRB
module ExtendCommand
class ExitProgram < Nop
category "Misc"
description "End the current program, optionally with a status to give to `Kernel.exit`"

def execute(arg = true)
Kernel.exit(arg)
end
end
end
end
6 changes: 6 additions & 0 deletions lib/irb/extend-command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ def irb_context
:irb_history, :History, "cmd/history",
[:history, NO_OVERRIDE],
[:hist, NO_OVERRIDE],
],

[
:irb_exit_program, :ExitProgram, 'cmd/exit_program',
[:exit_program, NO_OVERRIDE],
[:quit_program, NO_OVERRIDE],
]
]

Expand Down
5 changes: 3 additions & 2 deletions lib/irb/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,9 @@ def IRB.init_config(ap_path)

@CONF[:COMMAND_ALIASES] = {
# Symbol aliases
:'$' => :show_source,
:'@' => :whereami,
:'$' => :show_source,
:'@' => :whereami,
:'!!!' => :exit_program,
}
end

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

require_relative "../helper"

module TestIRB
class ExitProgramTest < IntegrationTestCase
def test_irb_exit_program
assert_exits_program(with_status: 0) do
type "irb_exit_program"
end
end

def test_exit_program
assert_exits_program(with_status: 0) do
type "exit_program"
end
end

def test_quit_program
assert_exits_program(with_status: 0) do
type "quit_program"
end
end

def test_triple_bang
assert_exits_program(with_status: 0) do
type "!!!"
end
end

def test_exit_code_zero
assert_exits_program(with_status: 0) do
type "!!! 0"
end
end

def test_exit_code_one
assert_exits_program(with_status: 1) do
type "!!! 1"
end
end

def test_exit_code_expression
assert_exits_program(with_status: 2) do
type "n = 1"
type "!!! n + 1"
end
end

def test_exit_code_expression
assert_exits_program(with_status: 2) do
type "n = 1"
type "!!! n + 1"
end
end

private

def assert_exits_program(with_status:, &block)
write_ruby <<~'RUBY'
begin
binding.irb
puts "Did not raise #{SystemExit}!" # Interpolate so we don't match whereami context
rescue SystemExit => e
puts "Raised SystemExit with status #{e.status.inspect}"
end
RUBY

output = run_ruby_file(&block)

refute_includes(output, "Did not raise SystemExit!", "AN ERROR MESSAGE")
matching_status = output[/(?<=Raised SystemExit with status )(\d+)/]
refute_nil matching_status, "Did not find exit status in output: \n#{output}"
assert_equal with_status, matching_status.to_i, "Exited with wrong status code"
end
end
end

0 comments on commit 330baa6

Please sign in to comment.