void rb_alias(VALUE klass, ID name, ID def) { VALUE target_klass = klass; rb_method_entry_t *orig_me; rb_method_flag_t flag = NOEX_UNDEF; if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class to make alias"); } rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } again: orig_me = search_method(klass, def); if (UNDEFINED_METHOD_ENTRY_P(orig_me)) { if ((!RB_TYPE_P(klass, T_MODULE)) || (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) { rb_print_undef(klass, def, 0); } } if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) { klass = RCLASS_SUPER(klass); def = orig_me->def->original_id; flag = orig_me->flag; goto again; } if (flag == NOEX_UNDEF) flag = orig_me->flag; rb_method_entry_set(target_klass, name, orig_me, flag); }
static void rb_export_method(VALUE klass, ID name, rb_method_flag_t noex) { rb_method_entry_t *me; VALUE defined_class; me = search_method(klass, name, &defined_class); if (!me && RB_TYPE_P(klass, T_MODULE)) { me = search_method(rb_cObject, name, &defined_class); } if (UNDEFINED_METHOD_ENTRY_P(me) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_print_undef(klass, name, 0); } if (me->flag != noex) { rb_vm_check_redefinition_opt_method(me, klass); if (klass == defined_class || RCLASS_ORIGIN(klass) == defined_class) { me->flag = noex; if (me->def->type == VM_METHOD_TYPE_REFINED) { me->def->body.orig_me->flag = noex; } rb_clear_method_cache_by_class(klass); } else { rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex); } } }
static void rb_export_method(VALUE klass, ID name, rb_method_flag_t noex) { rb_method_entry_t *me; if (klass == rb_cObject) { rb_secure(4); } me = search_method(klass, name); if (!me && RB_TYPE_P(klass, T_MODULE)) { me = search_method(rb_cObject, name); } if (UNDEFINED_METHOD_ENTRY_P(me)) { rb_print_undef(klass, name, 0); } if (me->flag != noex) { rb_vm_check_redefinition_opt_method(me, klass); if (klass == me->klass) { me->flag = noex; } else { rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex); } } }
/* * search method entry without the method cache. * * if you need method entry with method cache (normal case), use * rb_method_entry() simply. */ rb_method_entry_t * rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr) { VALUE defined_class; rb_method_entry_t *me = search_method(klass, id, &defined_class); if (me && me->klass) { switch (BUILTIN_TYPE(me->klass)) { case T_CLASS: if (RBASIC(klass)->flags & FL_SINGLETON) break; /* fall through */ case T_ICLASS: defined_class = me->klass; } } if (ruby_running) { if (OPT_GLOBAL_METHOD_CACHE) { struct cache_entry *ent; ent = GLOBAL_METHOD_CACHE(klass, id); ent->class_serial = RCLASS_SERIAL(klass); ent->method_state = GET_GLOBAL_METHOD_STATE(); ent->defined_class = defined_class; ent->mid = id; if (UNDEFINED_METHOD_ENTRY_P(me)) { ent->me = 0; me = 0; } else { ent->me = me; } } else if (UNDEFINED_METHOD_ENTRY_P(me)) { me = 0; } } if (defined_class_ptr) *defined_class_ptr = defined_class; return me; }
static int add_method_if_undefined(ID method_name, rb_method_entry_t *me, VALUE *names) { #ifdef ID_ALLOCATOR /* The allocator can be undefined with rb_undef_alloc_func, e.g. Struct. */ if (method_name == ID_ALLOCATOR) return ST_CONTINUE; #endif if (UNDEFINED_METHOD_ENTRY_P(me)) rb_ary_push(*names, ID2SYM(method_name)); return ST_CONTINUE; }
void rb_alias(VALUE klass, ID name, ID def) { rb_method_entry_t *orig_me; rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } orig_me = search_method(klass, def); if (UNDEFINED_METHOD_ENTRY_P(orig_me)) { if ((TYPE(klass) != T_MODULE) || (orig_me = search_method(rb_cObject, def), UNDEFINED_METHOD_ENTRY_P(orig_me))) { rb_print_undef(klass, def, 0); } } rb_add_method_me(klass, name, orig_me, orig_me->flag); }
static int add_method_if_matching(ID method_name, rb_method_entry_t *me, add_method_if_matching_arg_t *arg) { if (method_name == ID_ALLOCATOR) return ST_CONTINUE; if (UNDEFINED_METHOD_ENTRY_P(me)) return ST_CONTINUE; if ((me->flag & NOEX_MASK) == arg->visibility) rb_ary_push(arg->names, ID2SYM(method_name)); return ST_CONTINUE; }
void rb_alias(VALUE klass, ID name, ID def) { VALUE target_klass = klass; VALUE defined_class; rb_method_entry_t *orig_me; rb_method_flag_t flag = NOEX_UNDEF; if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class to make alias"); } rb_frozen_class_p(klass); again: orig_me = search_method(klass, def, &defined_class); if (UNDEFINED_METHOD_ENTRY_P(orig_me) || UNDEFINED_REFINED_METHOD_P(orig_me->def)) { if ((!RB_TYPE_P(klass, T_MODULE)) || (orig_me = search_method(rb_cObject, def, 0), UNDEFINED_METHOD_ENTRY_P(orig_me))) { rb_print_undef(klass, def, 0); } } if (orig_me->def->type == VM_METHOD_TYPE_ZSUPER) { klass = RCLASS_SUPER(klass); def = orig_me->def->original_id; flag = orig_me->flag; goto again; } if (RB_TYPE_P(defined_class, T_ICLASS)) { VALUE real_class = RBASIC_CLASS(defined_class); if (real_class && RCLASS_ORIGIN(real_class) == defined_class) defined_class = real_class; } if (flag == NOEX_UNDEF) flag = orig_me->flag; method_entry_set(target_klass, name, orig_me, flag, defined_class); }
void rb_undef(VALUE klass, ID id) { rb_method_entry_t *me; if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class to undef method"); } if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) { rb_secure(4); } if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id)); } rb_frozen_class_p(klass); if (id == object_id || id == id__send__ || id == idInitialize) { rb_warn("undefining `%s' may cause serious problems", rb_id2name(id)); } me = search_method(klass, id); if (UNDEFINED_METHOD_ENTRY_P(me)) { const char *s0 = " class"; VALUE c = klass; if (FL_TEST(c, FL_SINGLETON)) { VALUE obj = rb_ivar_get(klass, attached); switch (TYPE(obj)) { case T_MODULE: case T_CLASS: c = obj; s0 = ""; } } else if (RB_TYPE_P(c, T_MODULE)) { s0 = " module"; } rb_name_error(id, "undefined method `%s' for%s `%s'", rb_id2name(id), s0, rb_class2name(c)); } rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); CALL_METHOD_HOOK(klass, undefined, id); }
static int method_entry_i(st_data_t key, st_data_t value, st_data_t data) { const rb_method_entry_t *me = (const rb_method_entry_t *)value; st_table *list = (st_table *)data; long type; if (!st_lookup(list, key, 0)) { if (UNDEFINED_METHOD_ENTRY_P(me)) { type = -1; /* none */ } else { type = VISI(me->flag); } st_add_direct(list, key, type); } return ST_CONTINUE; }
rb_method_entry_t * rb_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr) { VALUE defined_class; rb_method_entry_t *me = rb_method_entry(klass, id, &defined_class); if (me && me->def->type == VM_METHOD_TYPE_REFINED) { me = rb_resolve_refined_method(Qnil, me, &defined_class); } if (defined_class_ptr) *defined_class_ptr = defined_class; if (UNDEFINED_METHOD_ENTRY_P(me)) { return 0; } else { return me; } }
static VALUE rb_mod_modfunc(int argc, VALUE *argv, VALUE module) { int i; ID id; const rb_method_entry_t *me; if (!RB_TYPE_P(module, T_MODULE)) { rb_raise(rb_eTypeError, "module_function must be called for modules"); } secure_visibility(module); if (argc == 0) { SCOPE_SET(NOEX_MODFUNC); return module; } set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (i = 0; i < argc; i++) { VALUE m = module; id = rb_to_id(argv[i]); for (;;) { me = search_method(m, id); if (me == 0) { me = search_method(rb_cObject, id); } if (UNDEFINED_METHOD_ENTRY_P(me)) { rb_print_undef(module, id, 0); } if (me->def->type != VM_METHOD_TYPE_ZSUPER) { break; /* normal case: need not to follow 'super' link */ } m = RCLASS_SUPER(m); if (!m) break; } rb_method_entry_set(rb_singleton_class(module), id, me, NOEX_PUBLIC); } return module; }
static int method_entry(ID key, const rb_method_entry_t *me, st_table *list) { long type; if (key == ID_ALLOCATOR) { return ST_CONTINUE; } if (!st_lookup(list, key, 0)) { if (UNDEFINED_METHOD_ENTRY_P(me)) { type = -1; /* none */ } else { type = VISI(me->flag); } st_add_direct(list, key, type); } return ST_CONTINUE; }
static int method_entry_i(st_data_t key, st_data_t value, st_data_t data) { const rb_method_entry_t *me = (const rb_method_entry_t *)value; st_table *list = (st_table *)data; long type; if (me && me->def->type == VM_METHOD_TYPE_REFINED) { me = rb_resolve_refined_method(Qnil, me, NULL); if (!me) return ST_CONTINUE; } if (!st_lookup(list, key, 0)) { if (UNDEFINED_METHOD_ENTRY_P(me)) { type = -1; /* none */ } else { type = VISI(me->flag); } st_add_direct(list, key, type); } return ST_CONTINUE; }
void rb_undef(VALUE klass, ID id) { rb_method_entry_t *me; if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class to undef method"); } rb_frozen_class_p(klass); if (id == object_id || id == id__send__ || id == idInitialize) { rb_warn("undefining `%s' may cause serious problems", rb_id2name(id)); } me = search_method(klass, id, 0); if (UNDEFINED_METHOD_ENTRY_P(me) || UNDEFINED_REFINED_METHOD_P(me->def)) { const char *s0 = " class"; VALUE c = klass; if (FL_TEST(c, FL_SINGLETON)) { VALUE obj = rb_ivar_get(klass, attached); if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) { c = obj; s0 = ""; } } else if (RB_TYPE_P(c, T_MODULE)) { s0 = " module"; } rb_name_error(id, "undefined method `%"PRIsVALUE"' for%s `%"PRIsVALUE"'", QUOTE_ID(id), s0, rb_class_name(c)); } rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); CALL_METHOD_HOOK(klass, undefined, id); }
/* * search method entry without method cache. * * if you need method entry with method cache, use * rb_method_entry() */ rb_method_entry_t * rb_get_method_entry(VALUE klass, ID id) { rb_method_entry_t *me = search_method(klass, id); if (ruby_running) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->klass = klass; if (UNDEFINED_METHOD_ENTRY_P(me)) { ent->mid = id; ent->me = 0; me = 0; } else { ent->mid = id; ent->me = me; } } return me; }
/* * search method entry without the method cache. * * if you need method entry with method cache (normal case), use * rb_method_entry() simply. */ rb_method_entry_t * rb_method_entry_get_without_cache(VALUE klass, ID id) { rb_method_entry_t *me = search_method(klass, id); if (ruby_running) { struct cache_entry *ent; ent = cache + EXPR1(klass, id); ent->filled_version = GET_VM_STATE_VERSION(); ent->klass = klass; if (UNDEFINED_METHOD_ENTRY_P(me)) { ent->mid = id; ent->me = 0; me = 0; } else { ent->mid = id; ent->me = me; } } return me; }
static int add_method_if_undefined(ID method_name, rb_method_entry_t *me, VALUE *names) { if (UNDEFINED_METHOD_ENTRY_P(me)) rb_ary_push(*names, ID2SYM(method_name)); return ST_CONTINUE; }