ruby-changes:38465
From: nagachika <ko1@a...>
Date: Wed, 20 May 2015 02:59:53 +0900 (JST)
Subject: [ruby-changes:38465] nagachika:r50546 (ruby_2_2): merge revision(s) 50038: [Backport #10985]
nagachika 2015-05-20 02:59:39 +0900 (Wed, 20 May 2015) New Revision: 50546 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=50546 Log: merge revision(s) 50038: [Backport #10985] * proc.c (respond_to_missing_p): check if the receiver responds to the given method by respond_to_missing?. * proc.c (mnew_missing): create Method object for method_missing. [ruby-core:68564] [Bug #10985] Modified directories: branches/ruby_2_2/ Modified files: branches/ruby_2_2/ChangeLog branches/ruby_2_2/proc.c branches/ruby_2_2/test/-ext-/symbol/test_inadvertent_creation.rb branches/ruby_2_2/version.h Index: ruby_2_2/ChangeLog =================================================================== --- ruby_2_2/ChangeLog (revision 50545) +++ ruby_2_2/ChangeLog (revision 50546) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_2/ChangeLog#L1 +Wed May 20 02:49:49 2015 Nobuyoshi Nakada <nobu@r...> + + * proc.c (respond_to_missing_p): check if the receiver responds to + the given method by respond_to_missing?. + + * proc.c (mnew_missing): create Method object for method_missing. + [ruby-core:68564] [Bug #10985] + Wed May 20 02:16:05 2015 NAKAMURA Usaku <usa@r...> * dir.c (replace_real_basename): need to check the return value of Index: ruby_2_2/proc.c =================================================================== --- ruby_2_2/proc.c (revision 50545) +++ ruby_2_2/proc.c (revision 50546) @@ -1131,29 +1131,68 @@ rb_obj_is_method(VALUE m) https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1131 } } +static int +respond_to_missing_p(VALUE klass, VALUE obj, VALUE sym, int scope) +{ + /* TODO: merge with obj_respond_to() */ + ID rmiss = idRespond_to_missing; + + if (obj == Qundef) return 0; + if (rb_method_basic_definition_p(klass, rmiss)) return 0; + return RTEST(rb_funcall(obj, rmiss, 2, sym, scope ? Qfalse : Qtrue)); +} + + +static VALUE +mnew_missing(VALUE rclass, VALUE klass, VALUE obj, ID id, ID rid, VALUE mclass) +{ + struct METHOD *data; + VALUE method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); + rb_method_entry_t *me; + rb_method_definition_t *def; + + data->recv = obj; + data->rclass = rclass; + data->defined_class = klass; + data->id = rid; + + me = ALLOC(rb_method_entry_t); + data->me = me; + me->flag = 0; + me->mark = 0; + me->called_id = id; + me->klass = klass; + me->def = 0; + + def = ALLOC(rb_method_definition_t); + me->def = def; + def->type = VM_METHOD_TYPE_MISSING; + def->original_id = id; + def->alias_count = 0; + + data->ume = ALLOC(struct unlinked_method_entry_list_entry); + data->me->def->alias_count++; + + OBJ_INFECT(method, klass); + + return method; +} + static VALUE mnew_internal(rb_method_entry_t *me, VALUE defined_class, VALUE klass, VALUE obj, ID id, VALUE mclass, int scope, int error) { - VALUE method; + struct METHOD *data; VALUE rclass = klass; + VALUE method; ID rid = id; - struct METHOD *data; rb_method_definition_t *def = 0; rb_method_flag_t flag = NOEX_UNDEF; again: if (UNDEFINED_METHOD_ENTRY_P(me)) { - ID rmiss = idRespond_to_missing; - VALUE sym = ID2SYM(id); - - if (obj != Qundef && !rb_method_basic_definition_p(klass, rmiss)) { - if (RTEST(rb_funcall(obj, rmiss, 2, sym, scope ? Qfalse : Qtrue))) { - me = 0; - defined_class = klass; - - goto gen_method; - } + if (respond_to_missing_p(klass, obj, ID2SYM(id), scope)) { + return mnew_missing(rclass, klass, obj, id, rid, mclass); } if (!error) return Qnil; rb_print_undef(klass, id, 0); @@ -1180,7 +1219,6 @@ mnew_internal(rb_method_entry_t *me, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1219 rclass = RCLASS_SUPER(rclass); } - gen_method: method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data); data->recv = obj; @@ -1188,25 +1226,7 @@ mnew_internal(rb_method_entry_t *me, VAL https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1226 data->defined_class = defined_class; data->id = rid; data->me = ALLOC(rb_method_entry_t); - if (me) { - *data->me = *me; - } - else { - me = data->me; - me->flag = 0; - me->mark = 0; - me->called_id = id; - me->klass = klass; - me->def = 0; - - def = ALLOC(rb_method_definition_t); - me->def = def; - - def->type = VM_METHOD_TYPE_MISSING; - def->original_id = id; - def->alias_count = 0; - - } + *data->me = *me; data->ume = ALLOC(struct unlinked_method_entry_list_entry); data->me->def->alias_count++; @@ -1438,6 +1458,23 @@ rb_method_name_error(VALUE klass, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1458 QUOTE(str), s0, rb_class_name(c)); } +static VALUE +obj_method(VALUE obj, VALUE vid, int scope) +{ + ID id = rb_check_id(&vid); + const VALUE klass = CLASS_OF(obj); + const VALUE mclass = rb_cMethod; + + if (!id) { + if (respond_to_missing_p(klass, obj, vid, scope)) { + id = rb_intern_str(vid); + return mnew_missing(klass, klass, obj, id, id, mclass); + } + rb_method_name_error(klass, vid); + } + return mnew(klass, obj, id, mclass, scope); +} + /* * call-seq: * obj.method(sym) -> method @@ -1469,11 +1506,7 @@ rb_method_name_error(VALUE klass, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1506 VALUE rb_obj_method(VALUE obj, VALUE vid) { - ID id = rb_check_id(&vid); - if (!id) { - rb_method_name_error(CLASS_OF(obj), vid); - } - return mnew(CLASS_OF(obj), obj, id, rb_cMethod, FALSE); + return obj_method(obj, vid, FALSE); } /* @@ -1486,11 +1519,7 @@ rb_obj_method(VALUE obj, VALUE vid) https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1519 VALUE rb_obj_public_method(VALUE obj, VALUE vid) { - ID id = rb_check_id(&vid); - if (!id) { - rb_method_name_error(CLASS_OF(obj), vid); - } - return mnew(CLASS_OF(obj), obj, id, rb_cMethod, TRUE); + return obj_method(obj, vid, TRUE); } /* @@ -1524,6 +1553,11 @@ rb_obj_singleton_method(VALUE obj, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_2/proc.c#L1553 VALUE klass; ID id = rb_check_id(&vid); if (!id) { + if (!NIL_P(klass = rb_singleton_class_get(obj)) && + respond_to_missing_p(klass, obj, vid, FALSE)) { + id = rb_intern_str(vid); + return mnew_missing(klass, klass, obj, id, id, rb_cMethod); + } rb_name_error_str(vid, "undefined singleton method `%"PRIsVALUE"' for `%"PRIsVALUE"'", QUOTE(vid), obj); } Index: ruby_2_2/version.h =================================================================== --- ruby_2_2/version.h (revision 50545) +++ ruby_2_2/version.h (revision 50546) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_2/version.h#L1 #define RUBY_VERSION "2.2.3" #define RUBY_RELEASE_DATE "2015-05-20" -#define RUBY_PATCHLEVEL 105 +#define RUBY_PATCHLEVEL 106 #define RUBY_RELEASE_YEAR 2015 #define RUBY_RELEASE_MONTH 5 Index: ruby_2_2/test/-ext-/symbol/test_inadvertent_creation.rb =================================================================== --- ruby_2_2/test/-ext-/symbol/test_inadvertent_creation.rb (revision 50545) +++ ruby_2_2/test/-ext-/symbol/test_inadvertent_creation.rb (revision 50546) @@ -82,6 +82,28 @@ module Test_Symbol https://github.com/ruby/ruby/blob/trunk/ruby_2_2/test/-ext-/symbol/test_inadvertent_creation.rb#L82 assert_not_interned_false(c, :class_variable_defined?, noninterned_name("@@"), feature5072) end + def test_missing_method + bug10985 = '[ruby-core:68564] [Bug #10985]' + m = nil + c = Class.new do + def self.respond_to_missing?(*) + true + end + end + + s = noninterned_name + assert_nothing_raised(NameError, bug10985) {m = c.method(s)} + assert_raise_with_message(NoMethodError, /#{s}/) {m.call} + + s = noninterned_name + assert_nothing_raised(NameError, bug10985) {m = c.public_method(s.to_sym)} + assert_raise_with_message(NoMethodError, /#{s}/) {m.call} + + s = noninterned_name + assert_nothing_raised(NameError, bug10985) {m = c.singleton_method(s.to_sym)} + assert_raise_with_message(NoMethodError, /#{s}/) {m.call} + end + Feature5079 = '[ruby-core:38404]' def test_undefined_instance_variable Property changes on: ruby_2_2 ___________________________________________________________________ Modified: svn:mergeinfo Merged /trunk:r50038 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/