Customization
Let's look at what the @exception
macro returns. In a slightly simplistic way, it looks like this:
@doc $(docstring)
mutable struct $(exception_name) <: Exception
$(args...)
end
Base.showerror(io::IO, e::$(exception_name)) =
print(io, $(error_message_bits...))
All of that gets put in a quote, and variables / expressions with a dollar symbol get interpolated.
What are these values equal? Well, args
is the second and all the following arguments passed to the main macro; exception_name
, docstring
, and error_message_bits
are arguments of an auxiliary macro created by the main macro.
Let's check it out:
using Exceptions
@exception m
@m MyException "Docstring" "ErrorMessage"
try
throw(MyException())
catch e
showerror(stdout, e)
end
Main.ex-context.MyException: ErrorMessage
What is that headline, you might ask? For an answer, let's look a little further behind the scenes:
args = $(args)
error_header = "$(__module__).$(exception_name):"
error_message_bits = ("\n\n$(error_header)\n", error_message_bits..., '\n')
$(context)
return esc(
quote
@doc $(docstring)
mutable struct $(exception_name) <: Exception
$(args...)
end
Base.showerror(io::IO, e::$(exception_name)) =
print(io, $(error_message_bits...))
end
)
As you can see, error_message_bits
get intentionally modified before the interpolation. That's what might be called the default context. The module in which the macro is invoked and the exception name get specified in the row before the error message. This piece of information gets separated by newlines on both sides.
This strange module name appears because these outputs get generated with the documentation. If you run the snippet above in the REPL, the module name will be equal to Main
.
What's not mentioned about this snippet yet? Ah, yes, the most important thing. See the $(context)
interpolation at the top level? That's your ticket to almost unlimited customization. Any variables mentioned may be modified to obtain the desired result.
All one has to do is to pass the context
keyword with a block of code when using the main macro. Like this:
@exception m context = begin
error_message_bits = error_message_bits[2:end-1]
end
@m (macro with 1 method)
With this snippet, we canceled the default changes for the error message. This gives us the following:
@m MyException2 "Docstring" "What can I say except you're welcome"
try
throw(MyException2())
catch e
showerror(stdout, e)
end
What can I say except you're welcome
Note that it is the code block (begin end
) that should be passed as the context, not the quote (quote end
) or the expression (:()
).
Further, it all depends only on your goals and imagination. See also the macro's documentation string (@exception
) for a full picture of what's going on behind the scenes and what you can influence. You can also see the real use of this macro in the code of the PDFHighlights.jl package.