From d40ec25228e581ada37957c1dc3bb894bc642366 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 9 Aug 2016 08:33:14 -0700 Subject: [PATCH] Add Warning module for customized warning handling This makes all warnings raised call Warning.warn, which by default does the same thing it does currently (rb_write_error_str). You can override Warning.warn to change the behavior. --- error.c | 37 +++++++++++++++++++++++++++++-------- test/ruby/test_exception.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/error.c b/error.c index 27ca7db..198e399 100644 --- a/error.c +++ b/error.c @@ -42,6 +42,9 @@ VALUE rb_iseqw_new(const rb_iseq_t *); VALUE rb_eEAGAIN; VALUE rb_eEWOULDBLOCK; VALUE rb_eEINPROGRESS; +VALUE rb_mWarning; + +static ID id_warn; extern const char ruby_description[]; @@ -147,6 +150,19 @@ ruby_only_for_internal_use(const char *func) } static VALUE +rb_warning_s_warn(VALUE mod, VALUE str) +{ + rb_write_error_str(str); + return Qnil; +} + +static void +rb_write_warning_str(VALUE str) +{ + rb_funcall(rb_mWarning, id_warn, 1, str); +} + +static VALUE warn_vsprintf(rb_encoding *enc, const char *file, int line, const char *fmt, va_list args) { VALUE str = rb_enc_str_new(0, 0, enc); @@ -166,7 +182,7 @@ rb_compile_warn(const char *file, int line, const char *fmt, ...) va_start(args, fmt); str = warn_vsprintf(NULL, file, line, fmt, args); va_end(args); - rb_write_error_str(str); + rb_write_warning_str(str); } /* rb_compile_warning() reports only in verbose mode */ @@ -181,7 +197,7 @@ rb_compile_warning(const char *file, int line, const char *fmt, ...) va_start(args, fmt); str = warn_vsprintf(NULL, file, line, fmt, args); va_end(args); - rb_write_error_str(str); + rb_write_warning_str(str); } static VALUE @@ -206,7 +222,7 @@ rb_warn(const char *fmt, ...) va_start(args, fmt); mesg = warning_string(0, fmt, args); va_end(args); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); } void @@ -220,7 +236,7 @@ rb_enc_warn(rb_encoding *enc, const char *fmt, ...) va_start(args, fmt); mesg = warning_string(enc, fmt, args); va_end(args); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); } /* rb_warning() reports only in verbose mode */ @@ -235,7 +251,7 @@ rb_warning(const char *fmt, ...) va_start(args, fmt); mesg = warning_string(0, fmt, args); va_end(args); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); } #if 0 @@ -250,7 +266,7 @@ rb_enc_warning(rb_encoding *enc, const char *fmt, ...) va_start(args, fmt); mesg = warning_string(enc, fmt, args); va_end(args); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); } #endif @@ -2052,6 +2068,10 @@ Init_Exception(void) rb_mErrno = rb_define_module("Errno"); + rb_mWarning = rb_define_module("Warning"); + rb_define_method(rb_mWarning, "warn", rb_warning_s_warn, 1); + rb_extend_object(rb_mWarning, rb_mWarning); + rb_define_global_function("warn", rb_warn_m, -1); id_new = rb_intern_const("new"); @@ -2066,6 +2086,7 @@ Init_Exception(void) id_Errno = rb_intern_const("Errno"); id_errno = rb_intern_const("errno"); id_i_path = rb_intern_const("@path"); + id_warn = rb_intern_const("warn"); id_iseq = rb_make_internal_id(); } @@ -2289,7 +2310,7 @@ rb_sys_warning(const char *fmt, ...) va_end(args); rb_str_set_len(mesg, RSTRING_LEN(mesg)-1); rb_str_catf(mesg, ": %s\n", strerror(errno_save)); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); errno = errno_save; } @@ -2309,7 +2330,7 @@ rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...) va_end(args); rb_str_set_len(mesg, RSTRING_LEN(mesg)-1); rb_str_catf(mesg, ": %s\n", strerror(errno_save)); - rb_write_error_str(mesg); + rb_write_warning_str(mesg); errno = errno_save; } diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 5023262..3107b61 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -855,4 +855,31 @@ def test_message_of_name_error end end end + + def test_warning_warn + verbose = $VERBOSE + warning = nil + + ::Warning.class_eval do + alias_method :warn2, :warn + remove_method :warn + + define_method(:warn) do |str| + warning = str + end + end + + $VERBOSE = true + a = @a + + assert_match(/instance variable @a not initialized/, warning) + ensure + $VERBOSE = verbose + + ::Warning.class_eval do + remove_method :warn + alias_method :warn, :warn2 + remove_method :warn2 + end + end end -- 2.9.0