From 5056859ea8de7ab2920b628982764d246d81f827 Mon Sep 17 00:00:00 2001 From: TSUYUSATO Kitsune Date: Wed, 4 Apr 2018 02:33:07 +0900 Subject: [PATCH] Pass an unhandled exception to at_exit block as second argument (#5906) * Pass an unhandled exception to at_exit block as second argument Follow up #1921 It is better in some ways: - it does not need a new exception like `SystemExit`. - it does not break compatibility in most cases because block fill up lacking arguments. * Add documentation for at_exit block arguments * Update `at_exit` block arguments description https://github.com/crystal-lang/crystal/pull/5906#discussion_r178840967 Thank you @jhass. --- spec/std/kernel_spec.cr | 16 ++++++++++++++++ src/kernel.cr | 12 +++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/spec/std/kernel_spec.cr b/spec/std/kernel_spec.cr index 04a6aa28d666..95f4eac96692 100644 --- a/spec/std/kernel_spec.cr +++ b/spec/std/kernel_spec.cr @@ -225,4 +225,20 @@ describe "at_exit" do Unhandled exception: Kaboom! OUTPUT end + + it "can get unhandled exception in at_exit handler" do + status, _, error = build_and_run <<-CODE + at_exit do |_, ex| + STDERR.puts ex.try &.message + end + + raise "Kaboom!" + CODE + + status.success?.should be_false + error.should contain <<-OUTPUT + Kaboom! + Unhandled exception: Kaboom! + OUTPUT + end end diff --git a/src/kernel.cr b/src/kernel.cr index 0bdc22637b50..78c0384adb0c 100644 --- a/src/kernel.cr +++ b/src/kernel.cr @@ -127,7 +127,7 @@ module AtExitHandlers class_property exception : Exception? - private class_getter(handlers) { [] of Int32 -> } + private class_getter(handlers) { [] of Int32, Exception? -> } def self.add(handler) raise "Cannot use at_exit from an at_exit handler" if @@running @@ -142,7 +142,7 @@ module AtExitHandlers # Run the registered handlers in reverse order while handler = handlers.pop? begin - handler.call status + handler.call status, exception rescue handler_ex STDERR.puts "Error running at_exit handler: #{handler_ex}" status = 1 if status.zero? @@ -180,7 +180,13 @@ end # ```text # goodbye cruel world # ``` -def at_exit(&handler : Int32 ->) : Nil +# +# The exit status code that will be returned by this program is passed to +# the block as its first argument. In case of any unhandled exception, it is +# passed as the second argument to the block, if the program terminates +# normally or `exit(status)` is called explicitly, then the second argument +# will be nil. +def at_exit(&handler : Int32, Exception? ->) : Nil AtExitHandlers.add(handler) end