diff options
author | Yusuke Endoh <mame@ruby-lang.org> | 2022-02-01 17:59:31 +0900 |
---|---|---|
committer | Yusuke Endoh <mame@ruby-lang.org> | 2022-02-22 11:55:40 +0900 |
commit | 35ff545bb689f5af93ac603ea1f512705e0dc249 (patch) | |
tree | 35807db18378f7f2111ba9f983d3a071895d8d1e | |
parent | 3af316fa8c48e33c03159e3b0b3bef329e41dee8 (diff) | |
download | ruby-35ff545bb689f5af93ac603ea1f512705e0dc249.tar.gz |
Exception#detailed_message is added
Also, the default error printer and Exception#full_message use the
method instead of `Exception#message` to get the message string.
`Exception#detailed_message` calls `Exception#message`, decorates and
returns the result. It adds some escape sequences to highlight, and the
class name of the exception to the end of the first line of the message.
[Feature #18370]
-rw-r--r-- | error.c | 57 | ||||
-rw-r--r-- | eval_error.c | 27 |
2 files changed, 67 insertions, 17 deletions
@@ -1122,7 +1122,7 @@ static VALUE rb_eNOERROR; ID ruby_static_id_cause; #define id_cause ruby_static_id_cause -static ID id_message, id_backtrace; +static ID id_message, id_detailed_message, id_backtrace; static ID id_key, id_matchee, id_args, id_Errno, id_errno, id_i_path; static ID id_receiver, id_recv, id_iseq, id_local_variables; static ID id_private_call_p, id_top, id_bottom; @@ -1224,7 +1224,7 @@ exc_to_s(VALUE exc) } /* FIXME: Include eval_error.c */ -void rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse); +void rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse); VALUE rb_get_message(VALUE exc) @@ -1235,6 +1235,21 @@ rb_get_message(VALUE exc) return e; } +VALUE +rb_get_detailed_message(VALUE exc, VALUE opt) +{ + VALUE e; + if (NIL_P(opt)) { + e = rb_check_funcall(exc, id_detailed_message, 0, 0); + } + else { + e = rb_check_funcall_kw(exc, id_detailed_message, 1, &opt, 1); + } + if (e == Qundef) return Qnil; + if (!RB_TYPE_P(e, T_STRING)) e = rb_check_string_type(e); + return e; +} + /* * call-seq: * Exception.to_tty? -> true or false @@ -1332,9 +1347,9 @@ exc_full_message(int argc, VALUE *argv, VALUE exc) str = rb_str_new2(""); errat = rb_get_backtrace(exc); - emesg = rb_get_message(exc); + emesg = rb_get_detailed_message(exc, opt); - rb_error_write(exc, emesg, errat, str, highlight, order); + rb_error_write(exc, emesg, errat, str, opt, highlight, order); return str; } @@ -1354,6 +1369,38 @@ exc_message(VALUE exc) /* * call-seq: + * exception.detailed_message(highlight: bool, **opt) -> string + * + * Processes a string returned by #message. + * + * It may add the class name of the exception to the end of the first line. + * Also, when +highlight+ keyword is true, it adds ANSI escape sequences to + * make the message bold. + * + * If you override this method, it must be tolerant for unknown keyword + * arguments. All keyword arguments passed to #full_message are delegated + * to this method. + * + * This method is overridden by did_you_mean and error_highlight to add + * their information. + */ + +static VALUE +exc_detailed_message(int argc, VALUE *argv, VALUE exc) +{ + VALUE opt; + + rb_scan_args(argc, argv, "0:", &opt); + + VALUE highlight = check_highlight_keyword(opt); + + extern VALUE rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight); + + return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), highlight); +} + +/* + * call-seq: * exception.inspect -> string * * Return this exception's class name and message. @@ -2908,6 +2955,7 @@ Init_Exception(void) rb_define_method(rb_eException, "==", exc_equal, 1); rb_define_method(rb_eException, "to_s", exc_to_s, 0); rb_define_method(rb_eException, "message", exc_message, 0); + rb_define_method(rb_eException, "detailed_message", exc_detailed_message, -1); rb_define_method(rb_eException, "full_message", exc_full_message, -1); rb_define_method(rb_eException, "inspect", exc_inspect, 0); rb_define_method(rb_eException, "backtrace", exc_backtrace, 0); @@ -2995,6 +3043,7 @@ Init_Exception(void) id_cause = rb_intern_const("cause"); id_message = rb_intern_const("message"); + id_detailed_message = rb_intern_const("detailed_message"); id_backtrace = rb_intern_const("backtrace"); id_key = rb_intern_const("key"); id_matchee = rb_intern_const("matchee"); diff --git a/eval_error.c b/eval_error.c index 7486f2777f..f69243e21d 100644 --- a/eval_error.c +++ b/eval_error.c @@ -261,7 +261,7 @@ print_backtrace(const VALUE eclass, const VALUE errat, const VALUE str, int reve } } -VALUE rb_get_message(VALUE exc); +VALUE rb_get_detailed_message(VALUE exc, VALUE opt); static int shown_cause_p(VALUE cause, VALUE *shown_causes) @@ -276,30 +276,29 @@ shown_cause_p(VALUE cause, VALUE *shown_causes) } static void -show_cause(VALUE errinfo, VALUE str, VALUE highlight, VALUE reverse, long backtrace_limit, VALUE *shown_causes) +show_cause(VALUE errinfo, VALUE str, VALUE opt, VALUE highlight, VALUE reverse, long backtrace_limit, VALUE *shown_causes) { VALUE cause = rb_attr_get(errinfo, id_cause); if (!NIL_P(cause) && rb_obj_is_kind_of(cause, rb_eException) && !shown_cause_p(cause, shown_causes)) { volatile VALUE eclass = CLASS_OF(cause); VALUE errat = rb_get_backtrace(cause); - VALUE emesg = rb_get_message(cause); - emesg = rb_decorate_message(eclass, emesg, RTEST(highlight)); + VALUE emesg = rb_get_detailed_message(cause, opt); if (reverse) { - show_cause(cause, str, highlight, reverse, backtrace_limit, shown_causes); + show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes); print_backtrace(eclass, errat, str, TRUE, backtrace_limit); print_errinfo(eclass, errat, emesg, str, RTEST(highlight)); } else { print_errinfo(eclass, errat, emesg, str, RTEST(highlight)); print_backtrace(eclass, errat, str, FALSE, backtrace_limit); - show_cause(cause, str, highlight, reverse, backtrace_limit, shown_causes); + show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes); } } } void -rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse) +rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse) { volatile VALUE eclass; VALUE shown_causes = 0; @@ -312,7 +311,6 @@ rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlig errat = Qnil; } eclass = CLASS_OF(errinfo); - emesg = rb_decorate_message(eclass, emesg, RTEST(highlight)); if (reverse) { static const char traceback[] = "Traceback " "(most recent call last):\n"; @@ -330,14 +328,14 @@ rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlig len = p - (msg = buff); } write_warn2(str, msg, len); - show_cause(errinfo, str, highlight, reverse, backtrace_limit, &shown_causes); + show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes); print_backtrace(eclass, errat, str, TRUE, backtrace_limit); print_errinfo(eclass, errat, emesg, str, RTEST(highlight)); } else { print_errinfo(eclass, errat, emesg, str, RTEST(highlight)); print_backtrace(eclass, errat, str, FALSE, backtrace_limit); - show_cause(errinfo, str, highlight, reverse, backtrace_limit, &shown_causes); + show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes); } } @@ -349,6 +347,10 @@ rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo) volatile VALUE emesg = Qundef; volatile bool written = false; + VALUE opt = rb_hash_new(); + VALUE highlight = rb_stderr_tty_p() ? Qtrue : Qfalse; + rb_hash_aset(opt, ID2SYM(rb_intern_const("highlight")), highlight); + if (NIL_P(errinfo)) return; rb_ec_raised_clear(ec); @@ -359,13 +361,12 @@ rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo) } if (emesg == Qundef) { emesg = Qnil; - emesg = rb_get_message(errinfo); + emesg = rb_get_detailed_message(errinfo, opt); } if (!written) { written = true; - VALUE highlight = rb_stderr_tty_p() ? Qtrue : Qfalse; - rb_error_write(errinfo, emesg, errat, Qnil, highlight, Qfalse); + rb_error_write(errinfo, emesg, errat, Qnil, opt, highlight, Qfalse); } EC_POP_TAG(); |