Support passing a category to Warning.warn
This change adds a `category` kwarg to make it easier to monkey patch `Warning.warn`. Warnings already have a category, but that warning isn't exposed. This implements a way to get the category so that warnings with a specific category, like deprecated, can be treated differently than other warnings in an application. The change here does an arity check on the method to support backwards compatibility for applications that may already have a warning monkey patch. For our usecase we want to `raise` for deprecation warnings in order to get the behavior for the next Ruby version. For example, now that we fixed all our warnings and deployed Ruby 2.7 to production, we want to be able to have deprecation warnings behave like they would in 3.0: raise an error. For other warnings, like uninialized constants, that behavior won't be removed from Ruby in the next version, so we don't need to raise errors. Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
This commit is contained in:
parent
de10a1f358
commit
6e8ec9ab6d
Notes:
git
2020-09-02 08:16:38 +09:00
8
NEWS.md
8
NEWS.md
@ -165,6 +165,13 @@ Outstanding ones only.
|
|||||||
* Symbol#to_proc now returns a lambda Proc.
|
* Symbol#to_proc now returns a lambda Proc.
|
||||||
[[Feature #16260]]
|
[[Feature #16260]]
|
||||||
|
|
||||||
|
* Warning
|
||||||
|
|
||||||
|
* Modified method
|
||||||
|
|
||||||
|
* Warning#warn now supports a category kwarg.
|
||||||
|
[[Feature #17122]]
|
||||||
|
|
||||||
## Stdlib updates
|
## Stdlib updates
|
||||||
|
|
||||||
Outstanding ones only.
|
Outstanding ones only.
|
||||||
@ -342,3 +349,4 @@ Excluding feature bug fixes.
|
|||||||
[Feature #16686]: https://bugs.ruby-lang.org/issues/16686
|
[Feature #16686]: https://bugs.ruby-lang.org/issues/16686
|
||||||
[Misc #16961]: https://bugs.ruby-lang.org/issues/16961
|
[Misc #16961]: https://bugs.ruby-lang.org/issues/16961
|
||||||
[Bug #8446]: https://bugs.ruby-lang.org/issues/8446
|
[Bug #8446]: https://bugs.ruby-lang.org/issues/8446
|
||||||
|
[Feature #17122]: https://bugs.ruby-lang.org/issues/17122
|
||||||
|
30
error.c
30
error.c
@ -229,15 +229,20 @@ rb_warning_s_aset(VALUE mod, VALUE category, VALUE flag)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* warn(msg) -> nil
|
* warn(msg, **kw) -> nil
|
||||||
*
|
*
|
||||||
* Writes warning message +msg+ to $stderr. This method is called by
|
* Writes warning message +msg+ to $stderr. This method is called by
|
||||||
* Ruby for all emitted warnings.
|
* Ruby for all emitted warnings. A +category+ may be included with
|
||||||
|
* the warning.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_warning_s_warn(VALUE mod, VALUE str)
|
rb_warning_s_warn(int argc, VALUE *argv, VALUE mod)
|
||||||
{
|
{
|
||||||
|
VALUE str;
|
||||||
|
VALUE opt;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "1:", &str, &opt);
|
||||||
Check_Type(str, T_STRING);
|
Check_Type(str, T_STRING);
|
||||||
rb_must_asciicompat(str);
|
rb_must_asciicompat(str);
|
||||||
rb_write_error_str(str);
|
rb_write_error_str(str);
|
||||||
@ -401,7 +406,22 @@ rb_warn_deprecated_to_remove(const char *fmt, const char *removal, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
rb_str_set_len(mesg, RSTRING_LEN(mesg) - 1);
|
rb_str_set_len(mesg, RSTRING_LEN(mesg) - 1);
|
||||||
rb_str_catf(mesg, " is deprecated and will be removed in Ruby %s\n", removal);
|
rb_str_catf(mesg, " is deprecated and will be removed in Ruby %s\n", removal);
|
||||||
rb_write_warning_str(mesg);
|
|
||||||
|
VALUE warn_args[2];
|
||||||
|
warn_args[0] = mesg;
|
||||||
|
|
||||||
|
const rb_method_entry_t * me;
|
||||||
|
me = rb_method_entry(rb_mWarning, id_warn);
|
||||||
|
|
||||||
|
if (rb_method_entry_arity(me) != 1) {
|
||||||
|
VALUE kwargs = rb_hash_new();
|
||||||
|
rb_hash_aset(kwargs, ID2SYM(rb_intern("category")), ID2SYM(rb_intern("deprecated")));
|
||||||
|
warn_args[1] = kwargs;
|
||||||
|
|
||||||
|
rb_funcallv_kw(rb_mWarning, id_warn, 2, warn_args, RB_PASS_KEYWORDS);
|
||||||
|
} else {
|
||||||
|
rb_funcall(rb_mWarning, id_warn, 1, mesg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
@ -2658,7 +2678,7 @@ Init_Exception(void)
|
|||||||
rb_mWarning = rb_define_module("Warning");
|
rb_mWarning = rb_define_module("Warning");
|
||||||
rb_define_singleton_method(rb_mWarning, "[]", rb_warning_s_aref, 1);
|
rb_define_singleton_method(rb_mWarning, "[]", rb_warning_s_aref, 1);
|
||||||
rb_define_singleton_method(rb_mWarning, "[]=", rb_warning_s_aset, 2);
|
rb_define_singleton_method(rb_mWarning, "[]=", rb_warning_s_aset, 2);
|
||||||
rb_define_method(rb_mWarning, "warn", rb_warning_s_warn, 1);
|
rb_define_method(rb_mWarning, "warn", rb_warning_s_warn, -1);
|
||||||
rb_extend_object(rb_mWarning, rb_mWarning);
|
rb_extend_object(rb_mWarning, rb_mWarning);
|
||||||
|
|
||||||
/* :nodoc: */
|
/* :nodoc: */
|
||||||
|
@ -915,7 +915,7 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def capture_warning_warn
|
def capture_warning_warn(category: false)
|
||||||
verbose = $VERBOSE
|
verbose = $VERBOSE
|
||||||
deprecated = Warning[:deprecated]
|
deprecated = Warning[:deprecated]
|
||||||
warning = []
|
warning = []
|
||||||
@ -924,8 +924,14 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||||||
alias_method :warn2, :warn
|
alias_method :warn2, :warn
|
||||||
remove_method :warn
|
remove_method :warn
|
||||||
|
|
||||||
define_method(:warn) do |str|
|
if category
|
||||||
warning << str
|
define_method(:warn) do |str, **kw|
|
||||||
|
warning << [str, kw[:category]]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
define_method(:warn) do |str|
|
||||||
|
warning << str
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -954,6 +960,18 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||||||
assert_equal(["\n"], capture_warning_warn {warn ""})
|
assert_equal(["\n"], capture_warning_warn {warn ""})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_warn_backwards_compatibility
|
||||||
|
warning = capture_warning_warn { Object.new.tainted? }
|
||||||
|
|
||||||
|
assert_match(/deprecated/, warning[0])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_warn_category
|
||||||
|
warning = capture_warning_warn(category: true) { Object.new.tainted? }
|
||||||
|
|
||||||
|
assert_equal :deprecated, warning[0][1]
|
||||||
|
end
|
||||||
|
|
||||||
def test_kernel_warn_uplevel
|
def test_kernel_warn_uplevel
|
||||||
warning = capture_warning_warn {warn("test warning", uplevel: 0)}
|
warning = capture_warning_warn {warn("test warning", uplevel: 0)}
|
||||||
assert_equal("#{__FILE__}:#{__LINE__-1}: warning: test warning\n", warning[0])
|
assert_equal("#{__FILE__}:#{__LINE__-1}: warning: test warning\n", warning[0])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user