2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
class.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
$Date$
|
|
|
|
created at: Tue Aug 10 15:05:44 JST 1993
|
|
|
|
|
2003-01-16 10:34:03 +03:00
|
|
|
Copyright (C) 1993-2003 Yukihiro Matsumoto
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
**********************************************************************/
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
#include "ruby.h"
|
2000-07-27 13:49:34 +04:00
|
|
|
#include "rubysig.h"
|
1998-01-16 15:13:05 +03:00
|
|
|
#include "node.h"
|
|
|
|
#include "st.h"
|
1999-01-20 07:59:39 +03:00
|
|
|
#include <ctype.h>
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
extern st_table *rb_class_tbl;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
VALUE
|
2001-07-18 09:56:05 +04:00
|
|
|
rb_class_boot(super)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE super;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
NEWOBJ(klass, struct RClass);
|
1999-01-20 07:59:39 +03:00
|
|
|
OBJSETUP(klass, rb_cClass, T_CLASS);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
klass->super = super;
|
|
|
|
klass->iv_tbl = 0;
|
|
|
|
klass->m_tbl = 0; /* safe GC */
|
1999-01-20 07:59:39 +03:00
|
|
|
klass->m_tbl = st_init_numtable();
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-08-14 12:13:31 +04:00
|
|
|
OBJ_INFECT(klass, super);
|
1998-01-16 15:19:22 +03:00
|
|
|
return (VALUE)klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2004-11-16 07:55:14 +03:00
|
|
|
void
|
|
|
|
rb_check_inheritable(super)
|
|
|
|
VALUE super;
|
|
|
|
{
|
|
|
|
if (TYPE(super) != T_CLASS) {
|
|
|
|
rb_raise(rb_eTypeError, "superclass must be a Class (%s given)",
|
|
|
|
rb_obj_classname(super));
|
|
|
|
}
|
|
|
|
if (RBASIC(super)->flags & FL_SINGLETON) {
|
|
|
|
rb_raise(rb_eTypeError, "can't make subclass of singleton class");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-07-18 09:56:05 +04:00
|
|
|
VALUE
|
|
|
|
rb_class_new(super)
|
|
|
|
VALUE super;
|
|
|
|
{
|
|
|
|
Check_Type(super, T_CLASS);
|
2004-11-16 07:55:14 +03:00
|
|
|
rb_check_inheritable(super);
|
2001-07-18 09:56:05 +04:00
|
|
|
if (super == rb_cClass) {
|
|
|
|
rb_raise(rb_eTypeError, "can't make subclass of Class");
|
|
|
|
}
|
|
|
|
return rb_class_boot(super);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static int
|
|
|
|
clone_method(mid, body, tbl)
|
|
|
|
ID mid;
|
|
|
|
NODE *body;
|
|
|
|
st_table *tbl;
|
|
|
|
{
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex));
|
1998-01-16 15:13:05 +03:00
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2004-01-18 17:16:47 +03:00
|
|
|
/* :nodoc: */
|
2001-05-02 08:22:21 +04:00
|
|
|
VALUE
|
2003-08-07 01:50:06 +04:00
|
|
|
rb_mod_init_copy(clone, orig)
|
|
|
|
VALUE clone, orig;
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2003-08-07 01:50:06 +04:00
|
|
|
rb_obj_init_copy(clone, orig);
|
2003-12-22 15:15:34 +03:00
|
|
|
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
|
|
|
|
RBASIC(clone)->klass = rb_singleton_class_clone(orig);
|
|
|
|
}
|
2003-08-07 01:50:06 +04:00
|
|
|
RCLASS(clone)->super = RCLASS(orig)->super;
|
|
|
|
if (RCLASS(orig)->iv_tbl) {
|
2001-10-22 10:48:18 +04:00
|
|
|
ID id;
|
|
|
|
|
2003-08-07 01:50:06 +04:00
|
|
|
RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl);
|
2001-10-22 10:48:18 +04:00
|
|
|
id = rb_intern("__classpath__");
|
2003-07-25 09:36:55 +04:00
|
|
|
st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
|
2001-10-22 10:48:18 +04:00
|
|
|
id = rb_intern("__classid__");
|
2003-07-25 09:36:55 +04:00
|
|
|
st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2003-08-07 01:50:06 +04:00
|
|
|
if (RCLASS(orig)->m_tbl) {
|
2001-10-03 11:19:19 +04:00
|
|
|
RCLASS(clone)->m_tbl = st_init_numtable();
|
2003-08-07 01:50:06 +04:00
|
|
|
st_foreach(RCLASS(orig)->m_tbl, clone_method,
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
(st_data_t)RCLASS(clone)->m_tbl);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
2003-08-07 01:50:06 +04:00
|
|
|
return clone;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
2004-01-18 17:16:47 +03:00
|
|
|
/* :nodoc: */
|
2001-05-02 08:22:21 +04:00
|
|
|
VALUE
|
2003-08-07 01:50:06 +04:00
|
|
|
rb_class_init_copy(clone, orig)
|
|
|
|
VALUE clone, orig;
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2003-08-07 01:50:06 +04:00
|
|
|
if (RCLASS(clone)->super != 0) {
|
|
|
|
rb_raise(rb_eTypeError, "already initialized class");
|
|
|
|
}
|
|
|
|
return rb_mod_init_copy(clone, orig);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2002-09-03 09:20:14 +04:00
|
|
|
rb_singleton_class_clone(obj)
|
|
|
|
VALUE obj;
|
2001-05-02 08:22:21 +04:00
|
|
|
{
|
2002-09-03 09:20:14 +04:00
|
|
|
VALUE klass = RBASIC(obj)->klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
if (!FL_TEST(klass, FL_SINGLETON))
|
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
else {
|
|
|
|
/* copy singleton(unnamed) class */
|
|
|
|
NEWOBJ(clone, struct RClass);
|
2002-09-03 09:20:14 +04:00
|
|
|
OBJSETUP(clone, 0, RBASIC(klass)->flags);
|
|
|
|
|
|
|
|
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
|
|
|
RBASIC(clone)->klass = (VALUE)clone;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RBASIC(clone)->klass = rb_singleton_class_clone(klass);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
clone->super = RCLASS(klass)->super;
|
1998-01-16 15:13:05 +03:00
|
|
|
clone->iv_tbl = 0;
|
|
|
|
clone->m_tbl = 0;
|
2001-03-28 12:43:25 +04:00
|
|
|
if (RCLASS(klass)->iv_tbl) {
|
|
|
|
clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
clone->m_tbl = st_init_numtable();
|
* st.h, st.c: Introduce new conventional typedef's, st_data_t,
st_compare_func_t, st_hash_func_t and st_each_func_t.
* st.h, st.c: Do explicit function declarations and do not rely on
implicit declarations. On such platforms as IA64, int argument
values are NOT automatically promoted to long (64bit) values, so
explicit declarations are mandatory for those functions that
take long values or pointers. This fixes miniruby's coredump on
FreeBSD/IA64.
* class.c, eval.c, gc.c, hash.c, marshal.c, parse.y, variable.c:
Add proper casts to avoid warnings.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3303 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2003-01-06 18:55:43 +03:00
|
|
|
st_foreach(RCLASS(klass)->m_tbl, clone_method,
|
|
|
|
(st_data_t)clone->m_tbl);
|
2002-09-03 09:20:14 +04:00
|
|
|
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
|
1998-01-16 15:13:05 +03:00
|
|
|
FL_SET(clone, FL_SINGLETON);
|
|
|
|
return (VALUE)clone;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_singleton_class_attached(klass, obj)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass, obj;
|
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
|
|
|
if (!RCLASS(klass)->iv_tbl) {
|
|
|
|
RCLASS(klass)->iv_tbl = st_init_numtable();
|
|
|
|
}
|
|
|
|
st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj);
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2002-01-10 23:18:39 +03:00
|
|
|
VALUE
|
2002-09-03 09:20:14 +04:00
|
|
|
rb_make_metaclass(obj, super)
|
|
|
|
VALUE obj, super;
|
2002-01-10 23:18:39 +03:00
|
|
|
{
|
2002-09-03 09:20:14 +04:00
|
|
|
VALUE klass = rb_class_boot(super);
|
|
|
|
FL_SET(klass, FL_SINGLETON);
|
2002-01-10 23:18:39 +03:00
|
|
|
RBASIC(obj)->klass = klass;
|
|
|
|
rb_singleton_class_attached(klass, obj);
|
2002-09-25 11:03:05 +04:00
|
|
|
if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
|
2002-09-03 09:20:14 +04:00
|
|
|
RBASIC(klass)->klass = klass;
|
2002-09-25 11:03:05 +04:00
|
|
|
RCLASS(klass)->super = RBASIC(rb_class_real(RCLASS(obj)->super))->klass;
|
|
|
|
}
|
|
|
|
else {
|
2002-09-28 06:41:05 +04:00
|
|
|
VALUE metasuper = RBASIC(rb_class_real(super))->klass;
|
|
|
|
|
|
|
|
/* metaclass of a superclass may be NULL at boot time */
|
|
|
|
if (metasuper) {
|
2002-10-01 12:14:03 +04:00
|
|
|
RBASIC(klass)->klass = metasuper;
|
2002-09-28 06:41:05 +04:00
|
|
|
}
|
2002-09-03 09:20:14 +04:00
|
|
|
}
|
|
|
|
|
2002-01-10 23:18:39 +03:00
|
|
|
return klass;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_define_class_id(id, super)
|
|
|
|
ID id;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE super;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (!super) super = rb_cObject;
|
|
|
|
klass = rb_class_new(super);
|
2002-01-10 23:18:39 +03:00
|
|
|
rb_make_metaclass(klass, RBASIC(super)->klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2002-01-10 23:18:39 +03:00
|
|
|
VALUE
|
|
|
|
rb_class_inherited(super, klass)
|
|
|
|
VALUE super, klass;
|
|
|
|
{
|
2002-01-16 05:20:25 +03:00
|
|
|
if (!super) super = rb_cObject;
|
2002-01-10 23:18:39 +03:00
|
|
|
return rb_funcall(super, rb_intern("inherited"), 1, klass);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_define_class(name, super)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE super;
|
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
|
|
klass = rb_const_get(rb_cObject, id);
|
2001-12-18 11:47:06 +03:00
|
|
|
if (TYPE(klass) != T_CLASS) {
|
|
|
|
rb_raise(rb_eTypeError, "%s is not a class", name);
|
|
|
|
}
|
|
|
|
if (rb_class_real(RCLASS(klass)->super) != super) {
|
|
|
|
rb_name_error(id, "%s is already defined", name);
|
|
|
|
}
|
|
|
|
return klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-02-17 17:44:14 +03:00
|
|
|
if (!super) {
|
|
|
|
rb_warn("no super class for `%s', Object assumed", name);
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = rb_define_class_id(id, super);
|
|
|
|
st_add_direct(rb_class_tbl, id, klass);
|
2004-01-19 12:19:31 +03:00
|
|
|
rb_name_class(klass, id);
|
2003-07-01 05:36:25 +04:00
|
|
|
rb_const_set(rb_cObject, id, klass);
|
2003-01-07 10:36:40 +03:00
|
|
|
rb_class_inherited(super, klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_class_under(outer, name, super)
|
|
|
|
VALUE outer;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE super;
|
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined_at(outer, id)) {
|
2003-06-20 11:11:44 +04:00
|
|
|
klass = rb_const_get_at(outer, id);
|
2001-12-18 11:47:06 +03:00
|
|
|
if (TYPE(klass) != T_CLASS) {
|
|
|
|
rb_raise(rb_eTypeError, "%s is not a class", name);
|
|
|
|
}
|
|
|
|
if (rb_class_real(RCLASS(klass)->super) != super) {
|
|
|
|
rb_name_error(id, "%s is already defined", name);
|
|
|
|
}
|
|
|
|
return klass;
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-02-17 17:44:14 +03:00
|
|
|
if (!super) {
|
|
|
|
rb_warn("no super class for `%s::%s', Object assumed",
|
|
|
|
rb_class2name(outer), name);
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = rb_define_class_id(id, super);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_set_class_path(klass, outer, name);
|
2002-01-10 23:18:39 +03:00
|
|
|
rb_const_set(outer, id, klass);
|
2003-01-07 10:36:40 +03:00
|
|
|
rb_class_inherited(super, klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_module_new()
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
NEWOBJ(mdl, struct RClass);
|
1999-01-20 07:59:39 +03:00
|
|
|
OBJSETUP(mdl, rb_cModule, T_MODULE);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
mdl->super = 0;
|
|
|
|
mdl->iv_tbl = 0;
|
|
|
|
mdl->m_tbl = 0;
|
1999-01-20 07:59:39 +03:00
|
|
|
mdl->m_tbl = st_init_numtable();
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return (VALUE)mdl;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_define_module_id(id)
|
|
|
|
ID id;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE mdl;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
mdl = rb_module_new();
|
1998-01-16 15:13:05 +03:00
|
|
|
rb_name_class(mdl, id);
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return mdl;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_define_module(name)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE module;
|
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (rb_const_defined(rb_cObject, id)) {
|
|
|
|
module = rb_const_get(rb_cObject, id);
|
|
|
|
if (TYPE(module) == T_MODULE)
|
|
|
|
return module;
|
2003-01-31 07:00:17 +03:00
|
|
|
rb_raise(rb_eTypeError, "%s is not a module", rb_obj_classname(module));
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
module = rb_define_module_id(id);
|
|
|
|
st_add_direct(rb_class_tbl, id, module);
|
2003-07-01 05:36:25 +04:00
|
|
|
rb_const_set(rb_cObject, id, module);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_module_under(outer, name)
|
|
|
|
VALUE outer;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE module;
|
|
|
|
ID id;
|
|
|
|
|
|
|
|
id = rb_intern(name);
|
2002-01-07 08:27:01 +03:00
|
|
|
if (rb_const_defined_at(outer, id)) {
|
2003-06-20 11:11:44 +04:00
|
|
|
module = rb_const_get_at(outer, id);
|
2001-05-02 08:22:21 +04:00
|
|
|
if (TYPE(module) == T_MODULE)
|
|
|
|
return module;
|
|
|
|
rb_raise(rb_eTypeError, "%s::%s is not a module",
|
2003-01-31 07:00:17 +03:00
|
|
|
rb_class2name(outer), rb_obj_classname(module));
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
module = rb_define_module_id(id);
|
1999-12-14 09:50:43 +03:00
|
|
|
rb_const_set(outer, id, module);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_set_class_path(module, outer, name);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static VALUE
|
1998-01-16 15:13:05 +03:00
|
|
|
include_class_new(module, super)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE module, super;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
NEWOBJ(klass, struct RClass);
|
1999-01-20 07:59:39 +03:00
|
|
|
OBJSETUP(klass, rb_cClass, T_ICLASS);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-07-11 12:22:18 +04:00
|
|
|
if (BUILTIN_TYPE(module) == T_ICLASS) {
|
|
|
|
module = RBASIC(module)->klass;
|
|
|
|
}
|
1999-08-13 09:45:20 +04:00
|
|
|
if (!RCLASS(module)->iv_tbl) {
|
|
|
|
RCLASS(module)->iv_tbl = st_init_numtable();
|
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass->iv_tbl = RCLASS(module)->iv_tbl;
|
1999-08-13 09:45:20 +04:00
|
|
|
klass->m_tbl = RCLASS(module)->m_tbl;
|
1998-01-16 15:19:22 +03:00
|
|
|
klass->super = super;
|
1998-01-16 15:13:05 +03:00
|
|
|
if (TYPE(module) == T_ICLASS) {
|
1999-01-20 07:59:39 +03:00
|
|
|
RBASIC(klass)->klass = RBASIC(module)->klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-01-20 07:59:39 +03:00
|
|
|
RBASIC(klass)->klass = module;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2001-08-14 12:13:31 +04:00
|
|
|
OBJ_INFECT(klass, module);
|
|
|
|
OBJ_INFECT(klass, super);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
return (VALUE)klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_include_module(klass, module)
|
|
|
|
VALUE klass, module;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-09-08 18:17:53 +04:00
|
|
|
VALUE p, c;
|
2001-03-28 12:43:25 +04:00
|
|
|
int changed = 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2001-05-02 08:22:21 +04:00
|
|
|
rb_frozen_class_p(klass);
|
|
|
|
if (!OBJ_TAINTED(klass)) {
|
|
|
|
rb_secure(4);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
if (NIL_P(module)) return;
|
1999-01-20 07:59:39 +03:00
|
|
|
if (klass == module) return;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-12-19 12:20:20 +03:00
|
|
|
if (TYPE(module) != T_MODULE) {
|
1998-01-16 15:13:05 +03:00
|
|
|
Check_Type(module, T_MODULE);
|
|
|
|
}
|
|
|
|
|
2001-08-14 12:13:31 +04:00
|
|
|
OBJ_INFECT(klass, module);
|
2001-09-08 18:17:53 +04:00
|
|
|
c = klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
while (module) {
|
2002-07-11 12:22:18 +04:00
|
|
|
int superclass_seen = Qfalse;
|
|
|
|
|
2002-01-25 11:22:11 +03:00
|
|
|
if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl)
|
|
|
|
rb_raise(rb_eArgError, "cyclic include detected");
|
1998-01-16 15:13:05 +03:00
|
|
|
/* ignore if the module included already in superclasses */
|
1998-01-16 15:19:22 +03:00
|
|
|
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
|
2002-07-11 12:22:18 +04:00
|
|
|
switch (BUILTIN_TYPE(p)) {
|
|
|
|
case T_ICLASS:
|
2002-02-19 10:47:07 +03:00
|
|
|
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
|
2002-07-11 12:22:18 +04:00
|
|
|
if (!superclass_seen) {
|
|
|
|
c = p; /* move insertion point */
|
|
|
|
}
|
2002-01-25 11:22:11 +03:00
|
|
|
goto skip;
|
2002-02-19 10:47:07 +03:00
|
|
|
}
|
2002-07-11 12:22:18 +04:00
|
|
|
break;
|
|
|
|
case T_CLASS:
|
|
|
|
superclass_seen = Qtrue;
|
|
|
|
break;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2002-07-11 12:22:18 +04:00
|
|
|
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
|
2001-03-28 12:43:25 +04:00
|
|
|
changed = 1;
|
2001-09-08 18:17:53 +04:00
|
|
|
skip:
|
|
|
|
module = RCLASS(module)->super;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
2001-03-28 12:43:25 +04:00
|
|
|
if (changed) rb_clear_cache();
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.included_modules -> array
|
|
|
|
*
|
|
|
|
* Returns the list of modules included in <i>mod</i>.
|
|
|
|
*
|
|
|
|
* module Mixin
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* module Outer
|
|
|
|
* include Mixin
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* Mixin.included_modules #=> []
|
|
|
|
* Outer.included_modules #=> [Mixin]
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_mod_included_modules(mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE mod;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE ary = rb_ary_new();
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE p;
|
|
|
|
|
|
|
|
for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
|
|
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, RBASIC(p)->klass);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.include?(module) => true or false
|
|
|
|
*
|
|
|
|
* Returns <code>true</code> if <i>module</i> is included in
|
|
|
|
* <i>mod</i> or one of <i>mod</i>'s ancestors.
|
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* include A
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* end
|
|
|
|
* B.include?(A) #=> true
|
|
|
|
* C.include?(A) #=> true
|
|
|
|
* A.include?(A) #=> false
|
|
|
|
*/
|
|
|
|
|
2001-07-24 13:07:33 +04:00
|
|
|
VALUE
|
|
|
|
rb_mod_include_p(mod, mod2)
|
|
|
|
VALUE mod;
|
|
|
|
VALUE mod2;
|
|
|
|
{
|
|
|
|
VALUE p;
|
|
|
|
|
|
|
|
Check_Type(mod2, T_MODULE);
|
|
|
|
for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) {
|
|
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
|
|
|
if (RBASIC(p)->klass == mod2) return Qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* mod.ancestors -> array
|
|
|
|
*
|
|
|
|
* Returns a list of modules included in <i>mod</i> (including
|
|
|
|
* <i>mod</i> itself).
|
|
|
|
*
|
|
|
|
* module Mod
|
|
|
|
* include Math
|
|
|
|
* include Comparable
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* Mod.ancestors #=> [Mod, Comparable, Math]
|
|
|
|
* Math.ancestors #=> [Math]
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_mod_ancestors(mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE mod;
|
|
|
|
{
|
2003-08-07 01:50:06 +04:00
|
|
|
VALUE p, ary = rb_ary_new();
|
1998-01-16 15:19:22 +03:00
|
|
|
|
|
|
|
for (p = mod; p; p = RCLASS(p)->super) {
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FL_TEST(p, FL_SINGLETON))
|
|
|
|
continue;
|
1998-01-16 15:19:22 +03:00
|
|
|
if (BUILTIN_TYPE(p) == T_ICLASS) {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, RBASIC(p)->klass);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_ary_push(ary, p);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
#define VISI(x) ((x)&NOEX_MASK)
|
|
|
|
#define VISI_CHECK(x,f) (VISI(x) == (f))
|
2002-10-30 11:04:32 +03:00
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
static int
|
2003-05-02 12:24:43 +04:00
|
|
|
ins_methods_push(name, type, ary, visi)
|
|
|
|
ID name;
|
|
|
|
long type;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE ary;
|
2003-05-02 12:24:43 +04:00
|
|
|
long visi;
|
|
|
|
{
|
|
|
|
if (type == -1) return ST_CONTINUE;
|
|
|
|
switch (visi) {
|
|
|
|
case NOEX_PRIVATE:
|
|
|
|
case NOEX_PROTECTED:
|
|
|
|
case NOEX_PUBLIC:
|
|
|
|
visi = (type == visi);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
visi = (type != NOEX_PRIVATE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (visi) {
|
|
|
|
rb_ary_push(ary, rb_str_new2(rb_id2name(name)));
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2003-05-02 12:24:43 +04:00
|
|
|
ins_methods_i(name, type, ary)
|
|
|
|
ID name;
|
|
|
|
long type;
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE ary;
|
|
|
|
{
|
2003-05-02 12:24:43 +04:00
|
|
|
return ins_methods_push(name, type, ary, -1); /* everything but private */
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
static int
|
|
|
|
ins_methods_prot_i(name, type, ary)
|
|
|
|
ID name;
|
|
|
|
long type;
|
|
|
|
VALUE ary;
|
|
|
|
{
|
|
|
|
return ins_methods_push(name, type, ary, NOEX_PROTECTED);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2003-05-02 12:24:43 +04:00
|
|
|
ins_methods_priv_i(name, type, ary)
|
|
|
|
ID name;
|
|
|
|
long type;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE ary;
|
|
|
|
{
|
2003-05-02 12:24:43 +04:00
|
|
|
return ins_methods_push(name, type, ary, NOEX_PRIVATE);
|
|
|
|
}
|
2002-10-30 11:04:32 +03:00
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
static int
|
|
|
|
ins_methods_pub_i(name, type, ary)
|
|
|
|
ID name;
|
|
|
|
long type;
|
|
|
|
VALUE ary;
|
|
|
|
{
|
|
|
|
return ins_methods_push(name, type, ary, NOEX_PUBLIC);
|
2002-10-30 11:04:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2003-05-02 12:24:43 +04:00
|
|
|
method_entry(key, body, list)
|
2002-10-30 11:04:32 +03:00
|
|
|
ID key;
|
|
|
|
NODE *body;
|
2003-05-02 12:24:43 +04:00
|
|
|
st_table *list;
|
2002-10-30 11:04:32 +03:00
|
|
|
{
|
2003-05-02 12:24:43 +04:00
|
|
|
long type;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2003-05-02 12:24:43 +04:00
|
|
|
if (key == ID_ALLOCATOR) return ST_CONTINUE;
|
|
|
|
if (!st_lookup(list, key, 0)) {
|
|
|
|
if (!body->nd_body) type = -1; /* none */
|
|
|
|
else type = VISI(body->nd_noex);
|
|
|
|
st_add_direct(list, key, type);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
return ST_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2003-06-25 11:12:10 +04:00
|
|
|
static VALUE
|
|
|
|
class_instance_method_list(argc, argv, mod, func)
|
1998-01-16 15:19:22 +03:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE mod;
|
2003-06-26 16:34:51 +04:00
|
|
|
int (*func) _((ID, long, VALUE));
|
1998-01-16 15:19:22 +03:00
|
|
|
{
|
2003-06-26 16:34:51 +04:00
|
|
|
VALUE ary;
|
|
|
|
int recur;
|
|
|
|
st_table *list;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2003-05-02 20:11:48 +04:00
|
|
|
if (argc == 0) {
|
|
|
|
recur = Qtrue;
|
|
|
|
}
|
2003-06-26 16:34:51 +04:00
|
|
|
else {
|
|
|
|
VALUE r;
|
|
|
|
rb_scan_args(argc, argv, "01", &r);
|
|
|
|
recur = RTEST(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
list = st_init_numtable();
|
|
|
|
for (; mod; mod = RCLASS(mod)->super) {
|
|
|
|
st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list);
|
2003-08-04 12:31:24 +04:00
|
|
|
if (BUILTIN_TYPE(mod) == T_ICLASS) continue;
|
|
|
|
if (FL_TEST(mod, FL_SINGLETON)) continue;
|
2003-06-26 16:34:51 +04:00
|
|
|
if (!recur) break;
|
|
|
|
}
|
|
|
|
ary = rb_ary_new();
|
|
|
|
st_foreach(list, func, ary);
|
|
|
|
st_free_table(list);
|
|
|
|
|
|
|
|
return ary;
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2004-07-15 15:46:00 +04:00
|
|
|
* mod.instance_methods(include_super=true) => array
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* Returns an array containing the names of public instance methods in
|
|
|
|
* the receiver. For a module, these are the public methods; for a
|
|
|
|
* class, they are the instance (not singleton) methods. With no
|
|
|
|
* argument, or with an argument that is <code>false</code>, the
|
|
|
|
* instance methods in <i>mod</i> are returned, otherwise the methods
|
|
|
|
* in <i>mod</i> and <i>mod</i>'s superclasses are returned.
|
|
|
|
*
|
|
|
|
* module A
|
|
|
|
* def method1() end
|
|
|
|
* end
|
|
|
|
* class B
|
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* class C < B
|
|
|
|
* def method3() end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* A.instance_methods #=> ["method1"]
|
2004-06-16 18:21:34 +04:00
|
|
|
* B.instance_methods(false) #=> ["method2"]
|
|
|
|
* C.instance_methods(false) #=> ["method3"]
|
2003-12-28 09:33:07 +03:00
|
|
|
* C.instance_methods(true).length #=> 43
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
2003-06-25 11:12:10 +04:00
|
|
|
rb_class_instance_methods(argc, argv, mod)
|
1999-01-20 07:59:39 +03:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE mod;
|
|
|
|
{
|
2003-06-25 11:12:10 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, ins_methods_i);
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2004-07-15 15:46:00 +04:00
|
|
|
* mod.protected_instance_methods(include_super=true) => array
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* Returns a list of the protected instance methods defined in
|
|
|
|
* <i>mod</i>. If the optional parameter is not <code>false</code>, the
|
|
|
|
* methods of any ancestors are included.
|
|
|
|
*/
|
|
|
|
|
2003-06-25 11:12:10 +04:00
|
|
|
VALUE
|
|
|
|
rb_class_protected_instance_methods(argc, argv, mod)
|
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE mod;
|
|
|
|
{
|
|
|
|
return class_instance_method_list(argc, argv, mod, ins_methods_prot_i);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2004-07-15 15:46:00 +04:00
|
|
|
* mod.private_instance_methods(include_super=true) => array
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* Returns a list of the private instance methods defined in
|
|
|
|
* <i>mod</i>. If the optional parameter is not <code>false</code>, the
|
|
|
|
* methods of any ancestors are included.
|
|
|
|
*
|
|
|
|
* module Mod
|
|
|
|
* def method1() end
|
|
|
|
* private :method1
|
|
|
|
* def method2() end
|
|
|
|
* end
|
|
|
|
* Mod.instance_methods #=> ["method2"]
|
|
|
|
* Mod.private_instance_methods #=> ["method1"]
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE
|
|
|
|
rb_class_private_instance_methods(argc, argv, mod)
|
1998-01-16 15:19:22 +03:00
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE mod;
|
|
|
|
{
|
2003-06-25 11:12:10 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, ins_methods_priv_i);
|
1998-01-16 15:19:22 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2004-07-15 15:46:00 +04:00
|
|
|
* mod.public_instance_methods(include_super=true) => array
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* Returns a list of the public instance methods defined in <i>mod</i>.
|
|
|
|
* If the optional parameter is not <code>false</code>, the methods of
|
|
|
|
* any ancestors are included.
|
|
|
|
*/
|
|
|
|
|
2002-10-30 11:04:32 +03:00
|
|
|
VALUE
|
|
|
|
rb_class_public_instance_methods(argc, argv, mod)
|
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
|
|
|
VALUE mod;
|
|
|
|
{
|
2003-06-25 11:12:10 +04:00
|
|
|
return class_instance_method_list(argc, argv, mod, ins_methods_pub_i);
|
2002-10-30 11:04:32 +03:00
|
|
|
}
|
|
|
|
|
2003-12-28 09:33:07 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2004-07-15 15:46:00 +04:00
|
|
|
* obj.singleton_methods(all=true) => array
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* Returns an array of the names of singleton methods for <i>obj</i>.
|
|
|
|
* If the optional <i>all</i> parameter is true, the list will include
|
|
|
|
* methods in modules included in <i>obj</i>.
|
|
|
|
*
|
|
|
|
* module Other
|
|
|
|
* def three() end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* class Single
|
|
|
|
* def Single.four() end
|
|
|
|
* end
|
|
|
|
*
|
|
|
|
* a = Single.new
|
|
|
|
*
|
|
|
|
* def a.one()
|
2004-05-12 06:51:54 +04:00
|
|
|
* end
|
2003-12-28 09:33:07 +03:00
|
|
|
*
|
|
|
|
* class << a
|
|
|
|
* include Other
|
|
|
|
* def two()
|
2004-05-12 06:51:54 +04:00
|
|
|
* end
|
2003-12-28 09:33:07 +03:00
|
|
|
* end
|
|
|
|
*
|
|
|
|
* Single.singleton_methods #=> ["four"]
|
2004-06-16 18:21:34 +04:00
|
|
|
* a.singleton_methods(false) #=> ["two", "one"]
|
|
|
|
* a.singleton_methods #=> ["two", "one", "three"]
|
2003-12-28 09:33:07 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE
|
2001-05-30 13:12:34 +04:00
|
|
|
rb_obj_singleton_methods(argc, argv, obj)
|
|
|
|
int argc;
|
|
|
|
VALUE *argv;
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
|
|
|
{
|
2003-05-06 10:51:31 +04:00
|
|
|
VALUE recur, ary, klass;
|
2003-05-02 12:24:43 +04:00
|
|
|
st_table *list;
|
1998-01-16 15:19:22 +03:00
|
|
|
|
2003-05-06 10:51:31 +04:00
|
|
|
rb_scan_args(argc, argv, "01", &recur);
|
2003-05-02 20:11:48 +04:00
|
|
|
if (argc == 0) {
|
2003-05-04 20:03:24 +04:00
|
|
|
recur = Qtrue;
|
2003-05-02 20:11:48 +04:00
|
|
|
}
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = CLASS_OF(obj);
|
2003-05-02 12:24:43 +04:00
|
|
|
list = st_init_numtable();
|
2003-08-02 00:16:53 +04:00
|
|
|
if (klass && FL_TEST(klass, FL_SINGLETON)) {
|
2003-05-02 12:24:43 +04:00
|
|
|
st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list);
|
1998-01-16 15:19:22 +03:00
|
|
|
klass = RCLASS(klass)->super;
|
|
|
|
}
|
2003-05-06 10:51:31 +04:00
|
|
|
if (RTEST(recur)) {
|
2003-08-02 00:16:53 +04:00
|
|
|
while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) {
|
2003-05-02 12:24:43 +04:00
|
|
|
st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list);
|
2001-05-30 13:12:34 +04:00
|
|
|
klass = RCLASS(klass)->super;
|
|
|
|
}
|
|
|
|
}
|
2003-05-02 12:24:43 +04:00
|
|
|
ary = rb_ary_new();
|
|
|
|
st_foreach(list, ins_methods_i, ary);
|
|
|
|
st_free_table(list);
|
1998-01-16 15:19:22 +03:00
|
|
|
|
|
|
|
return ary;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_define_method_id(klass, name, func, argc)
|
|
|
|
VALUE klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
ID name;
|
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
2003-07-16 11:11:30 +04:00
|
|
|
rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_define_method(klass, name, func, argc)
|
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
2004-06-16 18:21:34 +04:00
|
|
|
rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PUBLIC);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_protected_method(klass, name, func, argc)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2003-07-16 11:11:30 +04:00
|
|
|
rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PROTECTED);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_define_private_method(klass, name, func, argc)
|
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
2003-07-16 11:11:30 +04:00
|
|
|
rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_undef_method(klass, name)
|
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2002-04-25 17:57:01 +04:00
|
|
|
#define SPECIAL_SINGLETON(x,c) do {\
|
|
|
|
if (obj == (x)) {\
|
|
|
|
return c;\
|
|
|
|
}\
|
|
|
|
} while (0)
|
2002-03-08 10:03:09 +03:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_singleton_class(obj)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE obj;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-12-14 09:50:43 +03:00
|
|
|
VALUE klass;
|
2000-03-07 11:37:59 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
if (FIXNUM_P(obj) || SYMBOL_P(obj)) {
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_raise(rb_eTypeError, "can't define singleton");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-05-01 13:42:38 +04:00
|
|
|
if (rb_special_const_p(obj)) {
|
|
|
|
SPECIAL_SINGLETON(Qnil, rb_cNilClass);
|
|
|
|
SPECIAL_SINGLETON(Qfalse, rb_cFalseClass);
|
|
|
|
SPECIAL_SINGLETON(Qtrue, rb_cTrueClass);
|
2002-05-28 22:11:07 +04:00
|
|
|
rb_bug("unknown immediate %ld", obj);
|
2000-05-01 13:42:38 +04:00
|
|
|
}
|
|
|
|
|
2000-07-27 13:49:34 +04:00
|
|
|
DEFER_INTS;
|
2002-03-08 10:03:09 +03:00
|
|
|
if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) &&
|
2002-09-25 11:03:05 +04:00
|
|
|
rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) {
|
1999-12-14 09:50:43 +03:00
|
|
|
klass = RBASIC(obj)->klass;
|
|
|
|
}
|
|
|
|
else {
|
2002-01-10 23:18:39 +03:00
|
|
|
klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
|
1999-12-14 09:50:43 +03:00
|
|
|
}
|
|
|
|
if (OBJ_TAINTED(obj)) {
|
|
|
|
OBJ_TAINT(klass);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-12-14 09:50:43 +03:00
|
|
|
else {
|
|
|
|
FL_UNSET(klass, FL_TAINT);
|
|
|
|
}
|
2000-06-22 12:29:58 +04:00
|
|
|
if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass);
|
2000-07-27 13:49:34 +04:00
|
|
|
ALLOW_INTS;
|
1999-12-14 09:50:43 +03:00
|
|
|
|
|
|
|
return klass;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_singleton_method(obj, name, func, argc)
|
|
|
|
VALUE obj;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
|
|
|
rb_define_method(rb_singleton_class(obj), name, func, argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_module_function(module, name, func, argc)
|
|
|
|
VALUE module;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
|
|
|
rb_define_private_method(module, name, func, argc);
|
|
|
|
rb_define_singleton_method(module, name, func, argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rb_define_global_function(name, func, argc)
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE (*func)();
|
|
|
|
int argc;
|
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_module_function(rb_mKernel, name, func, argc);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_define_alias(klass, name1, name2)
|
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name1, *name2;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1998-01-16 15:19:22 +03:00
|
|
|
rb_alias(klass, rb_intern(name1), rb_intern(name2));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_attr(klass, name, read, write)
|
1998-01-16 15:19:22 +03:00
|
|
|
VALUE klass;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *name;
|
1998-01-16 15:19:22 +03:00
|
|
|
int read, write;
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_attr(klass, rb_intern(name), read, write, Qfalse);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
#ifdef HAVE_STDARG_PROTOTYPES
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define va_init_list(a,b) va_start(a,b)
|
|
|
|
#else
|
1998-01-16 15:13:05 +03:00
|
|
|
#include <varargs.h>
|
1999-01-20 07:59:39 +03:00
|
|
|
#define va_init_list(a,b) va_start(a)
|
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
int
|
1999-01-20 07:59:39 +03:00
|
|
|
#ifdef HAVE_STDARG_PROTOTYPES
|
2002-04-18 12:46:18 +04:00
|
|
|
rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
|
1999-01-20 07:59:39 +03:00
|
|
|
#else
|
1998-01-16 15:13:05 +03:00
|
|
|
rb_scan_args(argc, argv, fmt, va_alist)
|
|
|
|
int argc;
|
2002-04-18 12:46:18 +04:00
|
|
|
const VALUE *argv;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *fmt;
|
1998-01-16 15:13:05 +03:00
|
|
|
va_dcl
|
1999-01-20 07:59:39 +03:00
|
|
|
#endif
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2000-02-18 09:59:36 +03:00
|
|
|
int n, i = 0;
|
1999-08-13 09:45:20 +04:00
|
|
|
const char *p = fmt;
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE *var;
|
|
|
|
va_list vargs;
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
va_init_list(vargs, fmt);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-02-25 06:51:23 +03:00
|
|
|
if (*p == '*') goto rest_arg;
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (ISDIGIT(*p)) {
|
1998-01-16 15:13:05 +03:00
|
|
|
n = *p - '0';
|
|
|
|
if (n > argc)
|
2001-11-19 08:03:03 +03:00
|
|
|
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n);
|
1998-01-16 15:13:05 +03:00
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
var = va_arg(vargs, VALUE*);
|
1999-08-13 09:45:20 +04:00
|
|
|
if (var) *var = argv[i];
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (ISDIGIT(*p)) {
|
1998-01-16 15:13:05 +03:00
|
|
|
n = i + *p - '0';
|
|
|
|
for (; i<n; i++) {
|
|
|
|
var = va_arg(vargs, VALUE*);
|
|
|
|
if (argc > i) {
|
1999-08-13 09:45:20 +04:00
|
|
|
if (var) *var = argv[i];
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-08-13 09:45:20 +04:00
|
|
|
if (var) *var = Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(*p == '*') {
|
2000-02-25 06:51:23 +03:00
|
|
|
rest_arg:
|
1998-01-16 15:13:05 +03:00
|
|
|
var = va_arg(vargs, VALUE*);
|
|
|
|
if (argc > i) {
|
1999-08-13 09:45:20 +04:00
|
|
|
if (var) *var = rb_ary_new4(argc-i, argv+i);
|
2000-02-18 09:59:36 +03:00
|
|
|
i = argc;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
1999-08-13 09:45:20 +04:00
|
|
|
if (var) *var = rb_ary_new();
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-02-18 09:59:36 +03:00
|
|
|
p++;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-02-18 09:59:36 +03:00
|
|
|
|
|
|
|
if (*p == '&') {
|
|
|
|
var = va_arg(vargs, VALUE*);
|
2000-05-24 08:34:26 +04:00
|
|
|
if (rb_block_given_p()) {
|
2003-06-16 11:14:50 +04:00
|
|
|
*var = rb_block_proc();
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
*var = Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-02-18 09:59:36 +03:00
|
|
|
p++;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2000-02-18 09:59:36 +03:00
|
|
|
va_end(vargs);
|
|
|
|
|
|
|
|
if (*p != '\0') {
|
1998-01-16 15:13:05 +03:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2000-02-18 09:59:36 +03:00
|
|
|
if (argc > i) {
|
2004-03-29 11:54:38 +04:00
|
|
|
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i);
|
2000-02-18 09:59:36 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return argc;
|
|
|
|
|
|
|
|
error:
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_fatal("bad scan arg format: %s", fmt);
|
1998-01-16 15:13:05 +03:00
|
|
|
return 0;
|
|
|
|
}
|