mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Move BasicObject#method_missing to Kernel#method_missing; ref #3417
More compatibility to CRuby. Updated tests that assume old mruby behavior.
This commit is contained in:
-72
@@ -1486,77 +1486,6 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv)
|
||||
return mrb_bool_value(!mrb_test(cv));
|
||||
}
|
||||
|
||||
void
|
||||
mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
|
||||
{
|
||||
mrb_sym inspect;
|
||||
mrb_value repr;
|
||||
|
||||
inspect = mrb_intern_lit(mrb, "inspect");
|
||||
if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
|
||||
/* method missing in inspect; avoid recursion */
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
|
||||
repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
|
||||
if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
}
|
||||
else {
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
|
||||
mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
|
||||
mrb_sym2str(mrb, name), repr);
|
||||
}
|
||||
|
||||
/* 15.3.1.3.30 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.method_missing(symbol [, *args] ) -> result
|
||||
*
|
||||
* Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
|
||||
* <i>symbol</i> is the symbol for the method called, and <i>args</i>
|
||||
* are any arguments that were passed to it. By default, the interpreter
|
||||
* raises an error when this method is called. However, it is possible
|
||||
* to override the method to provide more dynamic behavior.
|
||||
* If it is decided that a particular method should not be handled, then
|
||||
* <i>super</i> should be called, so that ancestors can pick up the
|
||||
* missing method.
|
||||
* The example below creates
|
||||
* a class <code>Roman</code>, which responds to methods with names
|
||||
* consisting of roman numerals, returning the corresponding integer
|
||||
* values.
|
||||
*
|
||||
* class Roman
|
||||
* def romanToInt(str)
|
||||
* # ...
|
||||
* end
|
||||
* def method_missing(methId)
|
||||
* str = methId.id2name
|
||||
* romanToInt(str)
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* r = Roman.new
|
||||
* r.iv #=> 4
|
||||
* r.xxiii #=> 23
|
||||
* r.mm #=> 2000
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_bob_missing(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_sym name;
|
||||
mrb_value *a;
|
||||
mrb_int alen;
|
||||
|
||||
mrb_get_args(mrb, "n*", &name, &a, &alen);
|
||||
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
|
||||
/* not reached */
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
MRB_API mrb_bool
|
||||
mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid)
|
||||
{
|
||||
@@ -2306,7 +2235,6 @@ mrb_init_class(mrb_state *mrb)
|
||||
MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS);
|
||||
mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
|
||||
|
||||
mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1));
|
||||
mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */
|
||||
|
||||
@@ -963,6 +963,77 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
|
||||
{
|
||||
mrb_sym inspect;
|
||||
mrb_value repr;
|
||||
|
||||
inspect = mrb_intern_lit(mrb, "inspect");
|
||||
if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
|
||||
/* method missing in inspect; avoid recursion */
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) {
|
||||
repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
|
||||
if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
}
|
||||
else {
|
||||
repr = mrb_any_to_s(mrb, self);
|
||||
}
|
||||
|
||||
mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
|
||||
mrb_sym2str(mrb, name), repr);
|
||||
}
|
||||
|
||||
/* 15.3.1.3.30 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.method_missing(symbol [, *args] ) -> result
|
||||
*
|
||||
* Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
|
||||
* <i>symbol</i> is the symbol for the method called, and <i>args</i>
|
||||
* are any arguments that were passed to it. By default, the interpreter
|
||||
* raises an error when this method is called. However, it is possible
|
||||
* to override the method to provide more dynamic behavior.
|
||||
* If it is decided that a particular method should not be handled, then
|
||||
* <i>super</i> should be called, so that ancestors can pick up the
|
||||
* missing method.
|
||||
* The example below creates
|
||||
* a class <code>Roman</code>, which responds to methods with names
|
||||
* consisting of roman numerals, returning the corresponding integer
|
||||
* values.
|
||||
*
|
||||
* class Roman
|
||||
* def romanToInt(str)
|
||||
* # ...
|
||||
* end
|
||||
* def method_missing(methId)
|
||||
* str = methId.id2name
|
||||
* romanToInt(str)
|
||||
* end
|
||||
* end
|
||||
*
|
||||
* r = Roman.new
|
||||
* r.iv #=> 4
|
||||
* r.xxiii #=> 23
|
||||
* r.mm #=> 2000
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_obj_missing(mrb_state *mrb, mrb_value mod)
|
||||
{
|
||||
mrb_sym name;
|
||||
mrb_value *a;
|
||||
mrb_int alen;
|
||||
|
||||
mrb_get_args(mrb, "n*", &name, &a, &alen);
|
||||
mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a));
|
||||
/* not reached */
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static inline mrb_bool
|
||||
basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub)
|
||||
{
|
||||
@@ -1199,6 +1270,7 @@ mrb_init_kernel(mrb_state *mrb)
|
||||
mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */
|
||||
mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */
|
||||
mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */
|
||||
mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */
|
||||
mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */
|
||||
mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */
|
||||
mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */
|
||||
|
||||
+10
-10
@@ -21,20 +21,20 @@ assert('NoMethodError#args', '15.2.32.2.1') do
|
||||
end
|
||||
end
|
||||
|
||||
assert('Can still raise when BasicObject#method_missing is removed') do
|
||||
assert('Can still raise when Kernel#method_missing is removed') do
|
||||
assert_raise(NoMethodError) do
|
||||
begin
|
||||
BasicObject.alias_method(:old_method_missing, :method_missing)
|
||||
BasicObject.remove_method(:method_missing)
|
||||
Kernel.alias_method(:old_method_missing, :method_missing)
|
||||
Kernel.remove_method(:method_missing)
|
||||
1.__send__(:foo)
|
||||
ensure
|
||||
BasicObject.alias_method(:method_missing, :old_method_missing)
|
||||
BasicObject.remove_method(:old_method_missing)
|
||||
Kernel.alias_method(:method_missing, :old_method_missing)
|
||||
Kernel.remove_method(:old_method_missing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert('Can still call super when BasicObject#method_missing is removed') do
|
||||
assert('Can still call super when Kernel#method_missing is removed') do
|
||||
assert_raise(NoMethodError) do
|
||||
class A
|
||||
def foo
|
||||
@@ -42,12 +42,12 @@ assert('Can still call super when BasicObject#method_missing is removed') do
|
||||
end
|
||||
end
|
||||
begin
|
||||
BasicObject.alias_method(:old_method_missing, :method_missing)
|
||||
BasicObject.remove_method(:method_missing)
|
||||
Kernel.alias_method(:old_method_missing, :method_missing)
|
||||
Kernel.remove_method(:method_missing)
|
||||
A.new.foo
|
||||
ensure
|
||||
BasicObject.alias_method(:method_missing, :old_method_missing)
|
||||
BasicObject.remove_method(:old_method_missing)
|
||||
Kernel.alias_method(:method_missing, :old_method_missing)
|
||||
Kernel.remove_method(:old_method_missing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user