summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--error.c86
-rw-r--r--include/ruby/internal/error.h2
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb34
-rw-r--r--spec/ruby/core/warning/warn_spec.rb43
-rw-r--r--warning.rb4
5 files changed, 135 insertions, 34 deletions
diff --git a/error.c b/error.c
index e064eef4bc..fff9b4a5e1 100644
--- a/error.c
+++ b/error.c
@@ -73,6 +73,8 @@ static VALUE rb_cWarningBuffer;
static ID id_warn;
static ID id_category;
+static VALUE sym_category;
+static VALUE warning_categories;
extern const char ruby_description[];
@@ -276,6 +278,34 @@ rb_warning_warn(VALUE mod, VALUE str)
return rb_funcallv(mod, id_warn, 1, &str);
}
+
+static int
+rb_warning_warn_arity(void) {
+ return rb_method_entry_arity(rb_method_entry(rb_singleton_class(rb_mWarning), id_warn));
+}
+
+static VALUE
+rb_warn_category(VALUE str, VALUE category)
+{
+ if (category != Qnil) {
+ category = rb_to_symbol_type(category);
+ if (rb_hash_aref(warning_categories, category) != Qtrue) {
+ rb_raise(rb_eArgError, "invalid warning category used: %s", rb_id2name(SYM2ID(category)));
+ }
+ }
+
+ if (rb_warning_warn_arity() == 1) {
+ return rb_warning_warn(rb_mWarning, str);
+ }
+ else {
+ VALUE args[2];
+ args[0] = str;
+ args[1] = rb_hash_new();
+ rb_hash_aset(args[1], sym_category, category);
+ return rb_funcallv_kw(rb_mWarning, id_warn, 2, args, RB_PASS_KEYWORDS);
+ }
+}
+
static void
rb_write_warning_str(VALUE str)
{
@@ -345,6 +375,16 @@ rb_warn(const char *fmt, ...)
}
void
+rb_category_warn(const char *category, const char *fmt, ...)
+{
+ if (!NIL_P(ruby_verbose)) {
+ with_warning_string(mesg, 0, fmt) {
+ rb_warn_category(mesg, ID2SYM(rb_intern(category)));
+ }
+ }
+}
+
+void
rb_enc_warn(rb_encoding *enc, const char *fmt, ...)
{
if (!NIL_P(ruby_verbose)) {
@@ -365,6 +405,17 @@ rb_warning(const char *fmt, ...)
}
}
+/* rb_category_warning() reports only in verbose mode */
+void
+rb_category_warning(const char *category, const char *fmt, ...)
+{
+ if (RTEST(ruby_verbose)) {
+ with_warning_string(mesg, 0, fmt) {
+ rb_warn_category(mesg, ID2SYM(rb_intern(category)));
+ }
+ }
+}
+
VALUE
rb_warning_string(const char *fmt, ...)
{
@@ -385,8 +436,6 @@ rb_enc_warning(rb_encoding *enc, const char *fmt, ...)
}
#endif
-static void warn_deprecated(VALUE mesg);
-
void
rb_warn_deprecated(const char *fmt, const char *suggest, ...)
{
@@ -400,7 +449,7 @@ rb_warn_deprecated(const char *fmt, const char *suggest, ...)
rb_str_cat_cstr(mesg, " is deprecated");
if (suggest) rb_str_catf(mesg, "; use %s instead", suggest);
rb_str_cat_cstr(mesg, "\n");
- warn_deprecated(mesg);
+ rb_warn_category(mesg, ID2SYM(rb_intern("deprecated")));
}
void
@@ -414,24 +463,7 @@ rb_warn_deprecated_to_remove(const char *fmt, const char *removal, ...)
va_end(args);
rb_str_set_len(mesg, RSTRING_LEN(mesg) - 1);
rb_str_catf(mesg, " is deprecated and will be removed in Ruby %s\n", removal);
- warn_deprecated(mesg);
-}
-
-static void
-warn_deprecated(VALUE mesg)
-{
- VALUE warn_args[2] = {mesg};
- int kwd = 0;
- const rb_method_entry_t *me = rb_method_entry(rb_singleton_class(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;
- kwd = 1;
- }
-
- rb_funcallv_kw(rb_mWarning, id_warn, 1 + kwd, warn_args, kwd);
+ rb_warn_category(mesg, ID2SYM(rb_intern("deprecated")));
}
static inline int
@@ -453,7 +485,7 @@ warning_write(int argc, VALUE *argv, VALUE buf)
VALUE rb_ec_backtrace_location_ary(rb_execution_context_t *ec, long lev, long n);
static VALUE
-rb_warn_m(rb_execution_context_t *ec, VALUE exc, VALUE msgs, VALUE uplevel)
+rb_warn_m(rb_execution_context_t *ec, VALUE exc, VALUE msgs, VALUE uplevel, VALUE category)
{
VALUE location = Qnil;
int argc = RARRAY_LENINT(msgs);
@@ -489,12 +521,13 @@ rb_warn_m(rb_execution_context_t *ec, VALUE exc, VALUE msgs, VALUE uplevel)
rb_io_puts(argc, argv, str);
RBASIC_SET_CLASS(str, rb_cString);
}
+
if (exc == rb_mWarning) {
rb_must_asciicompat(str);
rb_write_error_str(str);
}
else {
- rb_write_warning_str(str);
+ rb_warn_category(str, category);
}
}
return Qnil;
@@ -2758,6 +2791,13 @@ Init_Exception(void)
id_bottom = rb_intern_const("bottom");
id_iseq = rb_make_internal_id();
id_recv = rb_make_internal_id();
+
+ sym_category = ID2SYM(id_category);
+
+ warning_categories = rb_hash_new();
+ rb_gc_register_mark_object(warning_categories);
+ rb_hash_aset(warning_categories, ID2SYM(rb_intern("deprecated")), Qtrue);
+ rb_obj_freeze(warning_categories);
}
void
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index 98f016d995..dc842cc6f6 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -63,10 +63,12 @@ VALUE *rb_ruby_debug_ptr(void);
/* reports if `-W' specified */
PRINTF_ARGS(void rb_warning(const char*, ...), 1, 2);
+PRINTF_ARGS(void rb_category_warning(const char*, const char*, ...), 2, 3);
PRINTF_ARGS(void rb_compile_warning(const char *, int, const char*, ...), 3, 4);
PRINTF_ARGS(void rb_sys_warning(const char*, ...), 1, 2);
/* reports always */
COLDFUNC PRINTF_ARGS(void rb_warn(const char*, ...), 1, 2);
+COLDFUNC PRINTF_ARGS(void rb_category_warn(const char *, const char*, ...), 2, 3);
PRINTF_ARGS(void rb_compile_warn(const char *, int, const char*, ...), 3, 4);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 79e78dd4a3..de08cd8cff 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -17,7 +17,7 @@ describe "Kernel#warn" do
Kernel.should have_private_instance_method(:warn)
end
- it "requires multiple arguments" do
+ it "accepts multiple arguments" do
Kernel.method(:warn).arity.should < 0
end
@@ -114,6 +114,38 @@ describe "Kernel#warn" do
end
end
+ ruby_version_is "3.0" do
+ it "accepts :category keyword with a symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: :deprecated)
+ }.should output(nil, "message\n")
+ end
+
+ it "accepts :category keyword with nil" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: nil)
+ }.should output(nil, "message\n")
+ end
+
+ it "accepts :category keyword with object convertible to symbol" do
+ o = Object.new
+ def o.to_sym; :deprecated; end
+ -> {
+ $VERBOSE = true
+ warn("message", category: o)
+ }.should output(nil, "message\n")
+ end
+
+ it "raises if :category keyword is not nil and not convertible to symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: Object.new)
+ }.should raise_error(TypeError)
+ end
+ end
+
it "converts first arg using to_s" do
w = KernelSpecs::WarnInNestedCall.new
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 21424c6c76..2ded6a109d 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -51,14 +51,41 @@ describe "Warning.warn" do
end
end
- it "is called by Kernel.warn" do
- Warning.should_receive(:warn).with("Chunky bacon!\n")
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
+
+ ruby_version_is '3.0' do
+ it "is called by Kernel.warn with nil category keyword" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ it "is called by Kernel.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: 'deprecated')
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "is called by Kernel.warn" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n")
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
end
end
end
diff --git a/warning.rb b/warning.rb
index f81ad77629..22acd3424e 100644
--- a/warning.rb
+++ b/warning.rb
@@ -39,7 +39,7 @@ module Kernel
#
# baz.rb:6: warning: invalid call to foo
#
- def warn(*msgs, uplevel: nil)
- Primitive.rb_warn_m(msgs, uplevel)
+ def warn(*msgs, uplevel: nil, category: nil)
+ Primitive.rb_warn_m(msgs, uplevel, category)
end
end