mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
74cdd893eb
Looking at the source code, FIXABLE tends to be just before LOING2FIX to check applicability of that operation. Why not try computing first then check for overflow, which should be optimial. I also tried the same thing for unsigned types but resulted in slower execution. It seems RB_POSFIXABLE() is fast enough on modern CPUs. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57789 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
3681 lines
91 KiB
C
3681 lines
91 KiB
C
/**********************************************************************
|
|
|
|
object.c -
|
|
|
|
$Author$
|
|
created at: Thu Jul 15 12:01:24 JST 1993
|
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
|
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
|
Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
|
|
|
**********************************************************************/
|
|
|
|
#include "internal.h"
|
|
#include "ruby/st.h"
|
|
#include "ruby/util.h"
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include "constant.h"
|
|
#include "id.h"
|
|
#include "probes.h"
|
|
|
|
VALUE rb_cBasicObject;
|
|
VALUE rb_mKernel;
|
|
VALUE rb_cObject;
|
|
VALUE rb_cModule;
|
|
VALUE rb_cClass;
|
|
VALUE rb_cData;
|
|
|
|
VALUE rb_cNilClass;
|
|
VALUE rb_cTrueClass;
|
|
VALUE rb_cFalseClass;
|
|
|
|
#define id_eq idEq
|
|
#define id_eql idEqlP
|
|
#define id_match idEqTilde
|
|
#define id_inspect idInspect
|
|
#define id_init_copy idInitialize_copy
|
|
#define id_init_clone idInitialize_clone
|
|
#define id_init_dup idInitialize_dup
|
|
#define id_const_missing idConst_missing
|
|
|
|
#define CLASS_OR_MODULE_P(obj) \
|
|
(!SPECIAL_CONST_P(obj) && \
|
|
(BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE))
|
|
|
|
VALUE
|
|
rb_obj_hide(VALUE obj)
|
|
{
|
|
if (!SPECIAL_CONST_P(obj)) {
|
|
RBASIC_CLEAR_CLASS(obj);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_reveal(VALUE obj, VALUE klass)
|
|
{
|
|
if (!SPECIAL_CONST_P(obj)) {
|
|
RBASIC_SET_CLASS(obj, klass);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
|
|
{
|
|
RBASIC(obj)->flags = type;
|
|
RBASIC_SET_CLASS(obj, klass);
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj === other -> true or false
|
|
*
|
|
* Case Equality -- For class Object, effectively the same as calling
|
|
* <code>#==</code>, but typically overridden by descendants to provide
|
|
* meaningful semantics in +case+ statements.
|
|
*/
|
|
|
|
VALUE
|
|
rb_equal(VALUE obj1, VALUE obj2)
|
|
{
|
|
VALUE result;
|
|
|
|
if (obj1 == obj2) return Qtrue;
|
|
result = rb_funcall(obj1, id_eq, 1, obj2);
|
|
if (RTEST(result)) return Qtrue;
|
|
return Qfalse;
|
|
}
|
|
|
|
int
|
|
rb_eql(VALUE obj1, VALUE obj2)
|
|
{
|
|
return RTEST(rb_funcall(obj1, id_eql, 1, obj2));
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj == other -> true or false
|
|
* obj.equal?(other) -> true or false
|
|
* obj.eql?(other) -> true or false
|
|
*
|
|
* Equality --- At the <code>Object</code> level, <code>==</code> returns
|
|
* <code>true</code> only if +obj+ and +other+ are the same object.
|
|
* Typically, this method is overridden in descendant classes to provide
|
|
* class-specific meaning.
|
|
*
|
|
* Unlike <code>==</code>, the <code>equal?</code> method should never be
|
|
* overridden by subclasses as it is used to determine object identity
|
|
* (that is, <code>a.equal?(b)</code> if and only if <code>a</code> is the
|
|
* same object as <code>b</code>):
|
|
*
|
|
* obj = "a"
|
|
* other = obj.dup
|
|
*
|
|
* obj == other #=> true
|
|
* obj.equal? other #=> false
|
|
* obj.equal? obj #=> true
|
|
*
|
|
* The <code>eql?</code> method returns <code>true</code> if +obj+ and
|
|
* +other+ refer to the same hash key. This is used by Hash to test members
|
|
* for equality. For objects of class <code>Object</code>, <code>eql?</code>
|
|
* is synonymous with <code>==</code>. Subclasses normally continue this
|
|
* tradition by aliasing <code>eql?</code> to their overridden <code>==</code>
|
|
* method, but there are exceptions. <code>Numeric</code> types, for
|
|
* example, perform type conversion across <code>==</code>, but not across
|
|
* <code>eql?</code>, so:
|
|
*
|
|
* 1 == 1.0 #=> true
|
|
* 1.eql? 1.0 #=> false
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_equal(VALUE obj1, VALUE obj2)
|
|
{
|
|
if (obj1 == obj2) return Qtrue;
|
|
return Qfalse;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* call-seq:
|
|
* obj.hash -> integer
|
|
*
|
|
* Generates an Integer hash value for this object. This function must have the
|
|
* property that <code>a.eql?(b)</code> implies <code>a.hash == b.hash</code>.
|
|
*
|
|
* The hash value is used along with #eql? by the Hash class to determine if
|
|
* two objects reference the same hash key. Any hash value that exceeds the
|
|
* capacity of an Integer will be truncated before being used.
|
|
*
|
|
* The hash value for an object may not be identical across invocations or
|
|
* implementations of Ruby. If you need a stable identifier across Ruby
|
|
* invocations and implementations you will need to generate one with a custom
|
|
* method.
|
|
*/
|
|
VALUE
|
|
rb_obj_hash(VALUE obj)
|
|
{
|
|
VALUE oid = rb_obj_id(obj);
|
|
#if SIZEOF_LONG == SIZEOF_VOIDP
|
|
st_index_t index = NUM2LONG(oid);
|
|
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
|
|
st_index_t index = NUM2LL(oid);
|
|
#else
|
|
# error not supported
|
|
#endif
|
|
return LONG2FIX(rb_objid_hash(index));
|
|
}
|
|
#else
|
|
VALUE rb_obj_hash(VALUE obj);
|
|
#endif
|
|
|
|
/*
|
|
* call-seq:
|
|
* !obj -> true or false
|
|
*
|
|
* Boolean negate.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_not(VALUE obj)
|
|
{
|
|
return RTEST(obj) ? Qfalse : Qtrue;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj != other -> true or false
|
|
*
|
|
* Returns true if two objects are not-equal, otherwise false.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_not_equal(VALUE obj1, VALUE obj2)
|
|
{
|
|
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
|
|
return RTEST(result) ? Qfalse : Qtrue;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_real(VALUE cl)
|
|
{
|
|
while (cl &&
|
|
((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS)) {
|
|
cl = RCLASS_SUPER(cl);
|
|
}
|
|
return cl;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.class -> class
|
|
*
|
|
* Returns the class of <i>obj</i>. This method must always be
|
|
* called with an explicit receiver, as <code>class</code> is also a
|
|
* reserved word in Ruby.
|
|
*
|
|
* 1.class #=> Integer
|
|
* self.class #=> Object
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_class(VALUE obj)
|
|
{
|
|
return rb_class_real(CLASS_OF(obj));
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.singleton_class -> class
|
|
*
|
|
* Returns the singleton class of <i>obj</i>. This method creates
|
|
* a new singleton class if <i>obj</i> does not have one.
|
|
*
|
|
* If <i>obj</i> is <code>nil</code>, <code>true</code>, or
|
|
* <code>false</code>, it returns NilClass, TrueClass, or FalseClass,
|
|
* respectively.
|
|
* If <i>obj</i> is an Integer, a Float or a Symbol, it raises a TypeError.
|
|
*
|
|
* Object.new.singleton_class #=> #<Class:#<Object:0xb7ce1e24>>
|
|
* String.singleton_class #=> #<Class:String>
|
|
* nil.singleton_class #=> NilClass
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_singleton_class(VALUE obj)
|
|
{
|
|
return rb_singleton_class(obj);
|
|
}
|
|
|
|
void
|
|
rb_obj_copy_ivar(VALUE dest, VALUE obj)
|
|
{
|
|
if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) {
|
|
xfree(ROBJECT_IVPTR(dest));
|
|
ROBJECT(dest)->as.heap.ivptr = 0;
|
|
ROBJECT(dest)->as.heap.numiv = 0;
|
|
ROBJECT(dest)->as.heap.iv_index_tbl = 0;
|
|
}
|
|
if (RBASIC(obj)->flags & ROBJECT_EMBED) {
|
|
MEMCPY(ROBJECT(dest)->as.ary, ROBJECT(obj)->as.ary, VALUE, ROBJECT_EMBED_LEN_MAX);
|
|
RBASIC(dest)->flags |= ROBJECT_EMBED;
|
|
}
|
|
else {
|
|
uint32_t len = ROBJECT(obj)->as.heap.numiv;
|
|
VALUE *ptr = 0;
|
|
if (len > 0) {
|
|
ptr = ALLOC_N(VALUE, len);
|
|
MEMCPY(ptr, ROBJECT(obj)->as.heap.ivptr, VALUE, len);
|
|
}
|
|
ROBJECT(dest)->as.heap.ivptr = ptr;
|
|
ROBJECT(dest)->as.heap.numiv = len;
|
|
ROBJECT(dest)->as.heap.iv_index_tbl = ROBJECT(obj)->as.heap.iv_index_tbl;
|
|
RBASIC(dest)->flags &= ~ROBJECT_EMBED;
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_copy(VALUE dest, VALUE obj)
|
|
{
|
|
if (OBJ_FROZEN(dest)) {
|
|
rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest));
|
|
}
|
|
RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
|
|
RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT);
|
|
rb_copy_wb_protected_attribute(dest, obj);
|
|
rb_copy_generic_ivar(dest, obj);
|
|
rb_gc_copy_finalizer(dest, obj);
|
|
if (RB_TYPE_P(obj, T_OBJECT)) {
|
|
rb_obj_copy_ivar(dest, obj);
|
|
}
|
|
}
|
|
|
|
static int freeze_opt(int argc, VALUE *argv);
|
|
static VALUE immutable_obj_clone(VALUE obj, int kwfreeze);
|
|
static VALUE mutable_obj_clone(VALUE obj, int kwfreeze);
|
|
PUREFUNC(static inline int special_object_p(VALUE obj));
|
|
static inline int
|
|
special_object_p(VALUE obj)
|
|
{
|
|
if (SPECIAL_CONST_P(obj)) return TRUE;
|
|
switch (BUILTIN_TYPE(obj)) {
|
|
case T_BIGNUM:
|
|
case T_FLOAT:
|
|
case T_SYMBOL:
|
|
case T_RATIONAL:
|
|
case T_COMPLEX:
|
|
/* not a comprehensive list */
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.clone(freeze: true) -> an_object
|
|
*
|
|
* Produces a shallow copy of <i>obj</i>---the instance variables of
|
|
* <i>obj</i> are copied, but not the objects they reference.
|
|
* <code>clone</code> copies the frozen (unless :freeze keyword argument
|
|
* is given with a false value) and tainted state of <i>obj</i>.
|
|
* See also the discussion under <code>Object#dup</code>.
|
|
*
|
|
* class Klass
|
|
* attr_accessor :str
|
|
* end
|
|
* s1 = Klass.new #=> #<Klass:0x401b3a38>
|
|
* s1.str = "Hello" #=> "Hello"
|
|
* s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello">
|
|
* s2.str[1,4] = "i" #=> "i"
|
|
* s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">"
|
|
* s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">"
|
|
*
|
|
* This method may have class-specific behavior. If so, that
|
|
* behavior will be documented under the #+initialize_copy+ method of
|
|
* the class.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_clone2(int argc, VALUE *argv, VALUE obj)
|
|
{
|
|
int kwfreeze = freeze_opt(argc, argv);
|
|
if (!special_object_p(obj))
|
|
return mutable_obj_clone(obj, kwfreeze);
|
|
return immutable_obj_clone(obj, kwfreeze);
|
|
}
|
|
|
|
VALUE
|
|
rb_immutable_obj_clone(int argc, VALUE *argv, VALUE obj)
|
|
{
|
|
int kwfreeze = freeze_opt(argc, argv);
|
|
return immutable_obj_clone(obj, kwfreeze);
|
|
}
|
|
|
|
static int
|
|
freeze_opt(int argc, VALUE *argv)
|
|
{
|
|
static ID keyword_ids[1];
|
|
VALUE opt;
|
|
VALUE kwfreeze;
|
|
|
|
if (!keyword_ids[0]) {
|
|
CONST_ID(keyword_ids[0], "freeze");
|
|
}
|
|
rb_scan_args(argc, argv, "0:", &opt);
|
|
if (!NIL_P(opt)) {
|
|
rb_get_kwargs(opt, keyword_ids, 0, 1, &kwfreeze);
|
|
if (kwfreeze == Qfalse) return FALSE;
|
|
if (kwfreeze != Qundef && kwfreeze != Qtrue) {
|
|
rb_raise(rb_eArgError, "unexpected value for freeze: %"PRIsVALUE,
|
|
rb_obj_class(kwfreeze));
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static VALUE
|
|
immutable_obj_clone(VALUE obj, int kwfreeze)
|
|
{
|
|
if (!kwfreeze)
|
|
rb_raise(rb_eArgError, "can't unfreeze %"PRIsVALUE,
|
|
rb_obj_class(obj));
|
|
return obj;
|
|
}
|
|
|
|
static VALUE
|
|
mutable_obj_clone(VALUE obj, int kwfreeze)
|
|
{
|
|
VALUE clone, singleton;
|
|
|
|
clone = rb_obj_alloc(rb_obj_class(obj));
|
|
RBASIC(clone)->flags &= (FL_TAINT|FL_PROMOTED0|FL_PROMOTED1);
|
|
RBASIC(clone)->flags |= RBASIC(obj)->flags & ~(FL_PROMOTED0|FL_PROMOTED1|FL_FREEZE|FL_FINALIZE);
|
|
|
|
singleton = rb_singleton_class_clone_and_attach(obj, clone);
|
|
RBASIC_SET_CLASS(clone, singleton);
|
|
if (FL_TEST(singleton, FL_SINGLETON)) {
|
|
rb_singleton_class_attached(singleton, clone);
|
|
}
|
|
|
|
init_copy(clone, obj);
|
|
rb_funcall(clone, id_init_clone, 1, obj);
|
|
|
|
if (kwfreeze) {
|
|
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
|
|
}
|
|
|
|
return clone;
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_clone(VALUE obj)
|
|
{
|
|
if (special_object_p(obj)) return obj;
|
|
return mutable_obj_clone(obj, Qtrue);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.dup -> an_object
|
|
*
|
|
* Produces a shallow copy of <i>obj</i>---the instance variables of
|
|
* <i>obj</i> are copied, but not the objects they reference.
|
|
* <code>dup</code> copies the tainted state of <i>obj</i>.
|
|
*
|
|
* This method may have class-specific behavior. If so, that
|
|
* behavior will be documented under the #+initialize_copy+ method of
|
|
* the class.
|
|
*
|
|
* === on dup vs clone
|
|
*
|
|
* In general, <code>clone</code> and <code>dup</code> may have different
|
|
* semantics in descendant classes. While <code>clone</code> is used to
|
|
* duplicate an object, including its internal state, <code>dup</code>
|
|
* typically uses the class of the descendant object to create the new
|
|
* instance.
|
|
*
|
|
* When using #dup, any modules that the object has been extended with will not
|
|
* be copied.
|
|
*
|
|
* class Klass
|
|
* attr_accessor :str
|
|
* end
|
|
*
|
|
* module Foo
|
|
* def foo; 'foo'; end
|
|
* end
|
|
*
|
|
* s1 = Klass.new #=> #<Klass:0x401b3a38>
|
|
* s1.extend(Foo) #=> #<Klass:0x401b3a38>
|
|
* s1.foo #=> "foo"
|
|
*
|
|
* s2 = s1.clone #=> #<Klass:0x401b3a38>
|
|
* s2.foo #=> "foo"
|
|
*
|
|
* s3 = s1.dup #=> #<Klass:0x401b3a38>
|
|
* s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401b3a38>
|
|
*
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_dup(VALUE obj)
|
|
{
|
|
VALUE dup;
|
|
|
|
if (special_object_p(obj)) {
|
|
return obj;
|
|
}
|
|
dup = rb_obj_alloc(rb_obj_class(obj));
|
|
init_copy(dup, obj);
|
|
rb_funcall(dup, id_init_dup, 1, obj);
|
|
|
|
return dup;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.itself -> an_object
|
|
*
|
|
* Returns <i>obj</i>.
|
|
*
|
|
* string = 'my string' #=> "my string"
|
|
* string.itself.object_id == string.object_id #=> true
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_itself(VALUE obj)
|
|
{
|
|
return obj;
|
|
}
|
|
|
|
/* :nodoc: */
|
|
VALUE
|
|
rb_obj_init_copy(VALUE obj, VALUE orig)
|
|
{
|
|
if (obj == orig) return obj;
|
|
rb_check_frozen(obj);
|
|
rb_check_trusted(obj);
|
|
if (TYPE(obj) != TYPE(orig) || rb_obj_class(obj) != rb_obj_class(orig)) {
|
|
rb_raise(rb_eTypeError, "initialize_copy should take same class object");
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/* :nodoc: */
|
|
VALUE
|
|
rb_obj_init_dup_clone(VALUE obj, VALUE orig)
|
|
{
|
|
rb_funcall(obj, id_init_copy, 1, orig);
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.to_s -> string
|
|
*
|
|
* Returns a string representing <i>obj</i>. The default
|
|
* <code>to_s</code> prints the object's class and an encoding of the
|
|
* object id. As a special case, the top-level object that is the
|
|
* initial execution context of Ruby programs returns ``main''.
|
|
*/
|
|
|
|
VALUE
|
|
rb_any_to_s(VALUE obj)
|
|
{
|
|
VALUE str;
|
|
VALUE cname = rb_class_name(CLASS_OF(obj));
|
|
|
|
str = rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)obj);
|
|
OBJ_INFECT(str, obj);
|
|
|
|
return str;
|
|
}
|
|
|
|
VALUE rb_str_escape(VALUE str);
|
|
/*
|
|
* If the default internal or external encoding is ASCII compatible,
|
|
* the encoding of the inspected result must be compatible with it.
|
|
* If the default internal or external encoding is ASCII incompatible,
|
|
* the result must be ASCII only.
|
|
*/
|
|
VALUE
|
|
rb_inspect(VALUE obj)
|
|
{
|
|
VALUE str = rb_obj_as_string(rb_funcallv(obj, id_inspect, 0, 0));
|
|
rb_encoding *enc = rb_default_internal_encoding();
|
|
if (enc == NULL) enc = rb_default_external_encoding();
|
|
if (!rb_enc_asciicompat(enc)) {
|
|
if (!rb_enc_str_asciionly_p(str))
|
|
return rb_str_escape(str);
|
|
return str;
|
|
}
|
|
if (rb_enc_get(str) != enc && !rb_enc_str_asciionly_p(str))
|
|
return rb_str_escape(str);
|
|
return str;
|
|
}
|
|
|
|
static int
|
|
inspect_i(st_data_t k, st_data_t v, st_data_t a)
|
|
{
|
|
ID id = (ID)k;
|
|
VALUE value = (VALUE)v;
|
|
VALUE str = (VALUE)a;
|
|
|
|
/* need not to show internal data */
|
|
if (CLASS_OF(value) == 0) return ST_CONTINUE;
|
|
if (!rb_is_instance_id(id)) return ST_CONTINUE;
|
|
if (RSTRING_PTR(str)[0] == '-') { /* first element */
|
|
RSTRING_PTR(str)[0] = '#';
|
|
rb_str_cat2(str, " ");
|
|
}
|
|
else {
|
|
rb_str_cat2(str, ", ");
|
|
}
|
|
rb_str_catf(str, "%"PRIsVALUE"=%+"PRIsVALUE,
|
|
rb_id2str(id), value);
|
|
|
|
return ST_CONTINUE;
|
|
}
|
|
|
|
static VALUE
|
|
inspect_obj(VALUE obj, VALUE str, int recur)
|
|
{
|
|
if (recur) {
|
|
rb_str_cat2(str, " ...");
|
|
}
|
|
else {
|
|
rb_ivar_foreach(obj, inspect_i, str);
|
|
}
|
|
rb_str_cat2(str, ">");
|
|
RSTRING_PTR(str)[0] = '#';
|
|
OBJ_INFECT(str, obj);
|
|
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.inspect -> string
|
|
*
|
|
* Returns a string containing a human-readable representation of <i>obj</i>.
|
|
* The default <code>inspect</code> shows the object's class name,
|
|
* an encoding of the object id, and a list of the instance variables and
|
|
* their values (by calling #inspect on each of them).
|
|
* User defined classes should override this method to provide a better
|
|
* representation of <i>obj</i>. When overriding this method, it should
|
|
* return a string whose encoding is compatible with the default external
|
|
* encoding.
|
|
*
|
|
* [ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
|
|
* Time.new.inspect #=> "2008-03-08 19:43:39 +0900"
|
|
*
|
|
* class Foo
|
|
* end
|
|
* Foo.new.inspect #=> "#<Foo:0x0300c868>"
|
|
*
|
|
* class Bar
|
|
* def initialize
|
|
* @bar = 1
|
|
* end
|
|
* end
|
|
* Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>"
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_inspect(VALUE obj)
|
|
{
|
|
if (rb_ivar_count(obj) > 0) {
|
|
VALUE str;
|
|
VALUE c = rb_class_name(CLASS_OF(obj));
|
|
|
|
str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj);
|
|
return rb_exec_recursive(inspect_obj, obj, str);
|
|
}
|
|
else {
|
|
return rb_any_to_s(obj);
|
|
}
|
|
}
|
|
|
|
static VALUE
|
|
class_or_module_required(VALUE c)
|
|
{
|
|
if (SPECIAL_CONST_P(c)) goto not_class;
|
|
switch (BUILTIN_TYPE(c)) {
|
|
case T_MODULE:
|
|
case T_CLASS:
|
|
case T_ICLASS:
|
|
break;
|
|
|
|
default:
|
|
not_class:
|
|
rb_raise(rb_eTypeError, "class or module required");
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static VALUE class_search_ancestor(VALUE cl, VALUE c);
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.instance_of?(class) -> true or false
|
|
*
|
|
* Returns <code>true</code> if <i>obj</i> is an instance of the given
|
|
* class. See also <code>Object#kind_of?</code>.
|
|
*
|
|
* class A; end
|
|
* class B < A; end
|
|
* class C < B; end
|
|
*
|
|
* b = B.new
|
|
* b.instance_of? A #=> false
|
|
* b.instance_of? B #=> true
|
|
* b.instance_of? C #=> false
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_is_instance_of(VALUE obj, VALUE c)
|
|
{
|
|
c = class_or_module_required(c);
|
|
if (rb_obj_class(obj) == c) return Qtrue;
|
|
return Qfalse;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.is_a?(class) -> true or false
|
|
* obj.kind_of?(class) -> true or false
|
|
*
|
|
* Returns <code>true</code> if <i>class</i> is the class of
|
|
* <i>obj</i>, or if <i>class</i> is one of the superclasses of
|
|
* <i>obj</i> or modules included in <i>obj</i>.
|
|
*
|
|
* module M; end
|
|
* class A
|
|
* include M
|
|
* end
|
|
* class B < A; end
|
|
* class C < B; end
|
|
*
|
|
* b = B.new
|
|
* b.is_a? A #=> true
|
|
* b.is_a? B #=> true
|
|
* b.is_a? C #=> false
|
|
* b.is_a? M #=> true
|
|
*
|
|
* b.kind_of? A #=> true
|
|
* b.kind_of? B #=> true
|
|
* b.kind_of? C #=> false
|
|
* b.kind_of? M #=> true
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_is_kind_of(VALUE obj, VALUE c)
|
|
{
|
|
VALUE cl = CLASS_OF(obj);
|
|
|
|
c = class_or_module_required(c);
|
|
return class_search_ancestor(cl, RCLASS_ORIGIN(c)) ? Qtrue : Qfalse;
|
|
}
|
|
|
|
static VALUE
|
|
class_search_ancestor(VALUE cl, VALUE c)
|
|
{
|
|
while (cl) {
|
|
if (cl == c || RCLASS_M_TBL(cl) == RCLASS_M_TBL(c))
|
|
return cl;
|
|
cl = RCLASS_SUPER(cl);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_search_ancestor(VALUE cl, VALUE c)
|
|
{
|
|
cl = class_or_module_required(cl);
|
|
c = class_or_module_required(c);
|
|
return class_search_ancestor(cl, RCLASS_ORIGIN(c));
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.tap{|x|...} -> obj
|
|
*
|
|
* Yields self to the block, and then returns self.
|
|
* The primary purpose of this method is to "tap into" a method chain,
|
|
* in order to perform operations on intermediate results within the chain.
|
|
*
|
|
* (1..10) .tap {|x| puts "original: #{x.inspect}"}
|
|
* .to_a .tap {|x| puts "array: #{x.inspect}"}
|
|
* .select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"}
|
|
* .map {|x| x*x} .tap {|x| puts "squares: #{x.inspect}"}
|
|
*
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_tap(VALUE obj)
|
|
{
|
|
rb_yield(obj);
|
|
return obj;
|
|
}
|
|
|
|
|
|
/*
|
|
* Document-method: inherited
|
|
*
|
|
* call-seq:
|
|
* inherited(subclass)
|
|
*
|
|
* Callback invoked whenever a subclass of the current class is created.
|
|
*
|
|
* Example:
|
|
*
|
|
* class Foo
|
|
* def self.inherited(subclass)
|
|
* puts "New subclass: #{subclass}"
|
|
* end
|
|
* end
|
|
*
|
|
* class Bar < Foo
|
|
* end
|
|
*
|
|
* class Baz < Bar
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* New subclass: Bar
|
|
* New subclass: Baz
|
|
*/
|
|
|
|
/* Document-method: method_added
|
|
*
|
|
* call-seq:
|
|
* method_added(method_name)
|
|
*
|
|
* Invoked as a callback whenever an instance method is added to the
|
|
* receiver.
|
|
*
|
|
* module Chatty
|
|
* def self.method_added(method_name)
|
|
* puts "Adding #{method_name.inspect}"
|
|
* end
|
|
* def self.some_class_method() end
|
|
* def some_instance_method() end
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Adding :some_instance_method
|
|
*
|
|
*/
|
|
|
|
/* Document-method: method_removed
|
|
*
|
|
* call-seq:
|
|
* method_removed(method_name)
|
|
*
|
|
* Invoked as a callback whenever an instance method is removed from the
|
|
* receiver.
|
|
*
|
|
* module Chatty
|
|
* def self.method_removed(method_name)
|
|
* puts "Removing #{method_name.inspect}"
|
|
* end
|
|
* def self.some_class_method() end
|
|
* def some_instance_method() end
|
|
* class << self
|
|
* remove_method :some_class_method
|
|
* end
|
|
* remove_method :some_instance_method
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Removing :some_instance_method
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Document-method: singleton_method_added
|
|
*
|
|
* call-seq:
|
|
* singleton_method_added(symbol)
|
|
*
|
|
* Invoked as a callback whenever a singleton method is added to the
|
|
* receiver.
|
|
*
|
|
* module Chatty
|
|
* def Chatty.singleton_method_added(id)
|
|
* puts "Adding #{id.id2name}"
|
|
* end
|
|
* def self.one() end
|
|
* def two() end
|
|
* def Chatty.three() end
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Adding singleton_method_added
|
|
* Adding one
|
|
* Adding three
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Document-method: singleton_method_removed
|
|
*
|
|
* call-seq:
|
|
* singleton_method_removed(symbol)
|
|
*
|
|
* Invoked as a callback whenever a singleton method is removed from
|
|
* the receiver.
|
|
*
|
|
* module Chatty
|
|
* def Chatty.singleton_method_removed(id)
|
|
* puts "Removing #{id.id2name}"
|
|
* end
|
|
* def self.one() end
|
|
* def two() end
|
|
* def Chatty.three() end
|
|
* class << self
|
|
* remove_method :three
|
|
* remove_method :one
|
|
* end
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Removing three
|
|
* Removing one
|
|
*/
|
|
|
|
/*
|
|
* Document-method: singleton_method_undefined
|
|
*
|
|
* call-seq:
|
|
* singleton_method_undefined(symbol)
|
|
*
|
|
* Invoked as a callback whenever a singleton method is undefined in
|
|
* the receiver.
|
|
*
|
|
* module Chatty
|
|
* def Chatty.singleton_method_undefined(id)
|
|
* puts "Undefining #{id.id2name}"
|
|
* end
|
|
* def Chatty.one() end
|
|
* class << self
|
|
* undef_method(:one)
|
|
* end
|
|
* end
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Undefining one
|
|
*/
|
|
|
|
/*
|
|
* Document-method: extended
|
|
*
|
|
* call-seq:
|
|
* extended(othermod)
|
|
*
|
|
* The equivalent of <tt>included</tt>, but for extended modules.
|
|
*
|
|
* module A
|
|
* def self.extended(mod)
|
|
* puts "#{self} extended in #{mod}"
|
|
* end
|
|
* end
|
|
* module Enumerable
|
|
* extend A
|
|
* end
|
|
* # => prints "A extended in Enumerable"
|
|
*/
|
|
|
|
/*
|
|
* Document-method: included
|
|
*
|
|
* call-seq:
|
|
* included(othermod)
|
|
*
|
|
* Callback invoked whenever the receiver is included in another
|
|
* module or class. This should be used in preference to
|
|
* <tt>Module.append_features</tt> if your code wants to perform some
|
|
* action when a module is included in another.
|
|
*
|
|
* module A
|
|
* def A.included(mod)
|
|
* puts "#{self} included in #{mod}"
|
|
* end
|
|
* end
|
|
* module Enumerable
|
|
* include A
|
|
* end
|
|
* # => prints "A included in Enumerable"
|
|
*/
|
|
|
|
/*
|
|
* Document-method: prepended
|
|
*
|
|
* call-seq:
|
|
* prepended(othermod)
|
|
*
|
|
* The equivalent of <tt>included</tt>, but for prepended modules.
|
|
*
|
|
* module A
|
|
* def self.prepended(mod)
|
|
* puts "#{self} prepended to #{mod}"
|
|
* end
|
|
* end
|
|
* module Enumerable
|
|
* prepend A
|
|
* end
|
|
* # => prints "A prepended to Enumerable"
|
|
*/
|
|
|
|
/*
|
|
* Document-method: initialize
|
|
*
|
|
* call-seq:
|
|
* BasicObject.new
|
|
*
|
|
* Returns a new BasicObject.
|
|
*/
|
|
|
|
/*
|
|
* Not documented
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_dummy(void)
|
|
{
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.tainted? -> true or false
|
|
*
|
|
* Returns true if the object is tainted.
|
|
*
|
|
* See #taint for more information.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_tainted(VALUE obj)
|
|
{
|
|
if (OBJ_TAINTED(obj))
|
|
return Qtrue;
|
|
return Qfalse;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.taint -> obj
|
|
*
|
|
* Mark the object as tainted.
|
|
*
|
|
* Objects that are marked as tainted will be restricted from various built-in
|
|
* methods. This is to prevent insecure data, such as command-line arguments
|
|
* or strings read from Kernel#gets, from inadvertently compromising the user's
|
|
* system.
|
|
*
|
|
* To check whether an object is tainted, use #tainted?.
|
|
*
|
|
* You should only untaint a tainted object if your code has inspected it and
|
|
* determined that it is safe. To do so use #untaint.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_taint(VALUE obj)
|
|
{
|
|
if (!OBJ_TAINTED(obj) && OBJ_TAINTABLE(obj)) {
|
|
rb_check_frozen(obj);
|
|
OBJ_TAINT(obj);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.untaint -> obj
|
|
*
|
|
* Removes the tainted mark from the object.
|
|
*
|
|
* See #taint for more information.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_untaint(VALUE obj)
|
|
{
|
|
if (OBJ_TAINTED(obj)) {
|
|
rb_check_frozen(obj);
|
|
FL_UNSET(obj, FL_TAINT);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.untrusted? -> true or false
|
|
*
|
|
* Deprecated method that is equivalent to #tainted?.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_untrusted(VALUE obj)
|
|
{
|
|
rb_warning("untrusted? is deprecated and its behavior is same as tainted?");
|
|
return rb_obj_tainted(obj);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.untrust -> obj
|
|
*
|
|
* Deprecated method that is equivalent to #taint.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_untrust(VALUE obj)
|
|
{
|
|
rb_warning("untrust is deprecated and its behavior is same as taint");
|
|
return rb_obj_taint(obj);
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.trust -> obj
|
|
*
|
|
* Deprecated method that is equivalent to #untaint.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_trust(VALUE obj)
|
|
{
|
|
rb_warning("trust is deprecated and its behavior is same as untaint");
|
|
return rb_obj_untaint(obj);
|
|
}
|
|
|
|
void
|
|
rb_obj_infect(VALUE obj1, VALUE obj2)
|
|
{
|
|
OBJ_INFECT(obj1, obj2);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.freeze -> obj
|
|
*
|
|
* Prevents further modifications to <i>obj</i>. A
|
|
* <code>RuntimeError</code> will be raised if modification is attempted.
|
|
* There is no way to unfreeze a frozen object. See also
|
|
* <code>Object#frozen?</code>.
|
|
*
|
|
* This method returns self.
|
|
*
|
|
* a = [ "a", "b", "c" ]
|
|
* a.freeze
|
|
* a << "z"
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* prog.rb:3:in `<<': can't modify frozen Array (RuntimeError)
|
|
* from prog.rb:3
|
|
*
|
|
* Objects of the following classes are always frozen: Integer,
|
|
* Float, Symbol.
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_freeze(VALUE obj)
|
|
{
|
|
if (!OBJ_FROZEN(obj)) {
|
|
OBJ_FREEZE(obj);
|
|
if (SPECIAL_CONST_P(obj)) {
|
|
rb_bug("special consts should be frozen.");
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.frozen? -> true or false
|
|
*
|
|
* Returns the freeze status of <i>obj</i>.
|
|
*
|
|
* a = [ "a", "b", "c" ]
|
|
* a.freeze #=> ["a", "b", "c"]
|
|
* a.frozen? #=> true
|
|
*/
|
|
|
|
VALUE
|
|
rb_obj_frozen_p(VALUE obj)
|
|
{
|
|
return OBJ_FROZEN(obj) ? Qtrue : Qfalse;
|
|
}
|
|
|
|
|
|
/*
|
|
* Document-class: NilClass
|
|
*
|
|
* The class of the singleton object <code>nil</code>.
|
|
*/
|
|
|
|
/*
|
|
* call-seq:
|
|
* nil.to_i -> 0
|
|
*
|
|
* Always returns zero.
|
|
*
|
|
* nil.to_i #=> 0
|
|
*/
|
|
|
|
|
|
static VALUE
|
|
nil_to_i(VALUE obj)
|
|
{
|
|
return INT2FIX(0);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* nil.to_f -> 0.0
|
|
*
|
|
* Always returns zero.
|
|
*
|
|
* nil.to_f #=> 0.0
|
|
*/
|
|
|
|
static VALUE
|
|
nil_to_f(VALUE obj)
|
|
{
|
|
return DBL2NUM(0.0);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* nil.to_s -> ""
|
|
*
|
|
* Always returns the empty string.
|
|
*/
|
|
|
|
static VALUE
|
|
nil_to_s(VALUE obj)
|
|
{
|
|
return rb_usascii_str_new(0, 0);
|
|
}
|
|
|
|
/*
|
|
* Document-method: to_a
|
|
*
|
|
* call-seq:
|
|
* nil.to_a -> []
|
|
*
|
|
* Always returns an empty array.
|
|
*
|
|
* nil.to_a #=> []
|
|
*/
|
|
|
|
static VALUE
|
|
nil_to_a(VALUE obj)
|
|
{
|
|
return rb_ary_new2(0);
|
|
}
|
|
|
|
/*
|
|
* Document-method: to_h
|
|
*
|
|
* call-seq:
|
|
* nil.to_h -> {}
|
|
*
|
|
* Always returns an empty hash.
|
|
*
|
|
* nil.to_h #=> {}
|
|
*/
|
|
|
|
static VALUE
|
|
nil_to_h(VALUE obj)
|
|
{
|
|
return rb_hash_new();
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* nil.inspect -> "nil"
|
|
*
|
|
* Always returns the string "nil".
|
|
*/
|
|
|
|
static VALUE
|
|
nil_inspect(VALUE obj)
|
|
{
|
|
return rb_usascii_str_new2("nil");
|
|
}
|
|
|
|
/***********************************************************************
|
|
* Document-class: TrueClass
|
|
*
|
|
* The global value <code>true</code> is the only instance of class
|
|
* <code>TrueClass</code> and represents a logically true value in
|
|
* boolean expressions. The class provides operators allowing
|
|
* <code>true</code> to be used in logical expressions.
|
|
*/
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* true.to_s -> "true"
|
|
*
|
|
* The string representation of <code>true</code> is "true".
|
|
*/
|
|
|
|
static VALUE
|
|
true_to_s(VALUE obj)
|
|
{
|
|
return rb_usascii_str_new2("true");
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* true & obj -> true or false
|
|
*
|
|
* And---Returns <code>false</code> if <i>obj</i> is
|
|
* <code>nil</code> or <code>false</code>, <code>true</code> otherwise.
|
|
*/
|
|
|
|
static VALUE
|
|
true_and(VALUE obj, VALUE obj2)
|
|
{
|
|
return RTEST(obj2)?Qtrue:Qfalse;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* true | obj -> true
|
|
*
|
|
* Or---Returns <code>true</code>. As <i>obj</i> is an argument to
|
|
* a method call, it is always evaluated; there is no short-circuit
|
|
* evaluation in this case.
|
|
*
|
|
* true | puts("or")
|
|
* true || puts("logical or")
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* or
|
|
*/
|
|
|
|
static VALUE
|
|
true_or(VALUE obj, VALUE obj2)
|
|
{
|
|
return Qtrue;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* true ^ obj -> !obj
|
|
*
|
|
* Exclusive Or---Returns <code>true</code> if <i>obj</i> is
|
|
* <code>nil</code> or <code>false</code>, <code>false</code>
|
|
* otherwise.
|
|
*/
|
|
|
|
static VALUE
|
|
true_xor(VALUE obj, VALUE obj2)
|
|
{
|
|
return RTEST(obj2)?Qfalse:Qtrue;
|
|
}
|
|
|
|
|
|
/*
|
|
* Document-class: FalseClass
|
|
*
|
|
* The global value <code>false</code> is the only instance of class
|
|
* <code>FalseClass</code> and represents a logically false value in
|
|
* boolean expressions. The class provides operators allowing
|
|
* <code>false</code> to participate correctly in logical expressions.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* call-seq:
|
|
* false.to_s -> "false"
|
|
*
|
|
* 'nuf said...
|
|
*/
|
|
|
|
static VALUE
|
|
false_to_s(VALUE obj)
|
|
{
|
|
return rb_usascii_str_new2("false");
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* false & obj -> false
|
|
* nil & obj -> false
|
|
*
|
|
* And---Returns <code>false</code>. <i>obj</i> is always
|
|
* evaluated as it is the argument to a method call---there is no
|
|
* short-circuit evaluation in this case.
|
|
*/
|
|
|
|
static VALUE
|
|
false_and(VALUE obj, VALUE obj2)
|
|
{
|
|
return Qfalse;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* false | obj -> true or false
|
|
* nil | obj -> true or false
|
|
*
|
|
* Or---Returns <code>false</code> if <i>obj</i> is
|
|
* <code>nil</code> or <code>false</code>; <code>true</code> otherwise.
|
|
*/
|
|
|
|
static VALUE
|
|
false_or(VALUE obj, VALUE obj2)
|
|
{
|
|
return RTEST(obj2)?Qtrue:Qfalse;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* false ^ obj -> true or false
|
|
* nil ^ obj -> true or false
|
|
*
|
|
* Exclusive Or---If <i>obj</i> is <code>nil</code> or
|
|
* <code>false</code>, returns <code>false</code>; otherwise, returns
|
|
* <code>true</code>.
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
false_xor(VALUE obj, VALUE obj2)
|
|
{
|
|
return RTEST(obj2)?Qtrue:Qfalse;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* nil.nil? -> true
|
|
*
|
|
* Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_true(VALUE obj)
|
|
{
|
|
return Qtrue;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.nil? -> true or false
|
|
*
|
|
* Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
|
|
*
|
|
* Object.new.nil? #=> false
|
|
* nil.nil? #=> true
|
|
*/
|
|
|
|
|
|
static VALUE
|
|
rb_false(VALUE obj)
|
|
{
|
|
return Qfalse;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj =~ other -> nil
|
|
*
|
|
* Pattern Match---Overridden by descendants (notably
|
|
* <code>Regexp</code> and <code>String</code>) to provide meaningful
|
|
* pattern-match semantics.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_match(VALUE obj1, VALUE obj2)
|
|
{
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj !~ other -> true or false
|
|
*
|
|
* Returns true if two objects do not match (using the <i>=~</i>
|
|
* method), otherwise false.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_not_match(VALUE obj1, VALUE obj2)
|
|
{
|
|
VALUE result = rb_funcall(obj1, id_match, 1, obj2);
|
|
return RTEST(result) ? Qfalse : Qtrue;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj <=> other -> 0 or nil
|
|
*
|
|
* Returns 0 if +obj+ and +other+ are the same object
|
|
* or <code>obj == other</code>, otherwise nil.
|
|
*
|
|
* The <code><=></code> is used by various methods to compare objects, for example
|
|
* Enumerable#sort, Enumerable#max etc.
|
|
*
|
|
* Your implementation of <code><=></code> should return one of the following values: -1, 0,
|
|
* 1 or nil. -1 means self is smaller than other. 0 means self is equal to other.
|
|
* 1 means self is bigger than other. Nil means the two values could not be
|
|
* compared.
|
|
*
|
|
* When you define <code><=></code>, you can include Comparable to gain the methods
|
|
* <code><=</code>, <code><</code>, <code>==</code>, <code>>=</code>, <code>></code> and <code>between?</code>.
|
|
*/
|
|
static VALUE
|
|
rb_obj_cmp(VALUE obj1, VALUE obj2)
|
|
{
|
|
if (obj1 == obj2 || rb_equal(obj1, obj2))
|
|
return INT2FIX(0);
|
|
return Qnil;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Document-class: Module
|
|
*
|
|
* A <code>Module</code> is a collection of methods and constants. The
|
|
* methods in a module may be instance methods or module methods.
|
|
* Instance methods appear as methods in a class when the module is
|
|
* included, module methods do not. Conversely, module methods may be
|
|
* called without creating an encapsulating object, while instance
|
|
* methods may not. (See <code>Module#module_function</code>.)
|
|
*
|
|
* In the descriptions that follow, the parameter <i>sym</i> refers
|
|
* to a symbol, which is either a quoted string or a
|
|
* <code>Symbol</code> (such as <code>:name</code>).
|
|
*
|
|
* module Mod
|
|
* include Math
|
|
* CONST = 1
|
|
* def meth
|
|
* # ...
|
|
* end
|
|
* end
|
|
* Mod.class #=> Module
|
|
* Mod.constants #=> [:CONST, :PI, :E]
|
|
* Mod.instance_methods #=> [:meth]
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.to_s -> string
|
|
*
|
|
* Returns a string representing this module or class. For basic
|
|
* classes and modules, this is the name. For singletons, we
|
|
* show information on the thing we're attached to as well.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_to_s(VALUE klass)
|
|
{
|
|
ID id_defined_at;
|
|
VALUE refined_class, defined_at;
|
|
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
|
VALUE s = rb_usascii_str_new2("#<Class:");
|
|
VALUE v = rb_ivar_get(klass, id__attached__);
|
|
|
|
if (CLASS_OR_MODULE_P(v)) {
|
|
rb_str_append(s, rb_inspect(v));
|
|
}
|
|
else {
|
|
rb_str_append(s, rb_any_to_s(v));
|
|
}
|
|
rb_str_cat2(s, ">");
|
|
|
|
return s;
|
|
}
|
|
refined_class = rb_refinement_module_get_refined_class(klass);
|
|
if (!NIL_P(refined_class)) {
|
|
VALUE s = rb_usascii_str_new2("#<refinement:");
|
|
|
|
rb_str_concat(s, rb_inspect(refined_class));
|
|
rb_str_cat2(s, "@");
|
|
CONST_ID(id_defined_at, "__defined_at__");
|
|
defined_at = rb_attr_get(klass, id_defined_at);
|
|
rb_str_concat(s, rb_inspect(defined_at));
|
|
rb_str_cat2(s, ">");
|
|
return s;
|
|
}
|
|
return rb_str_dup(rb_class_name(klass));
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.freeze -> mod
|
|
*
|
|
* Prevents further modifications to <i>mod</i>.
|
|
*
|
|
* This method returns self.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_freeze(VALUE mod)
|
|
{
|
|
rb_class_name(mod);
|
|
return rb_obj_freeze(mod);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod === obj -> true or false
|
|
*
|
|
* Case Equality---Returns <code>true</code> if <i>obj</i> is an
|
|
* instance of <i>mod</i> or an instance of one of <i>mod</i>'s descendants.
|
|
* Of limited use for modules, but can be used in <code>case</code> statements
|
|
* to classify objects by class.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_eqq(VALUE mod, VALUE arg)
|
|
{
|
|
return rb_obj_is_kind_of(arg, mod);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod <= other -> true, false, or nil
|
|
*
|
|
* Returns true if <i>mod</i> is a subclass of <i>other</i> or
|
|
* is the same as <i>other</i>. Returns
|
|
* <code>nil</code> if there's no relationship between the two.
|
|
* (Think of the relationship in terms of the class definition:
|
|
* "class A < B" implies "A < B".)
|
|
*
|
|
*/
|
|
|
|
VALUE
|
|
rb_class_inherited_p(VALUE mod, VALUE arg)
|
|
{
|
|
if (mod == arg) return Qtrue;
|
|
if (!CLASS_OR_MODULE_P(arg) && !RB_TYPE_P(arg, T_ICLASS)) {
|
|
rb_raise(rb_eTypeError, "compared with non class/module");
|
|
}
|
|
if (class_search_ancestor(mod, RCLASS_ORIGIN(arg))) {
|
|
return Qtrue;
|
|
}
|
|
/* not mod < arg; check if mod > arg */
|
|
if (class_search_ancestor(arg, mod)) {
|
|
return Qfalse;
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod < other -> true, false, or nil
|
|
*
|
|
* Returns true if <i>mod</i> is a subclass of <i>other</i>. Returns
|
|
* <code>nil</code> if there's no relationship between the two.
|
|
* (Think of the relationship in terms of the class definition:
|
|
* "class A < B" implies "A < B".)
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_lt(VALUE mod, VALUE arg)
|
|
{
|
|
if (mod == arg) return Qfalse;
|
|
return rb_class_inherited_p(mod, arg);
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod >= other -> true, false, or nil
|
|
*
|
|
* Returns true if <i>mod</i> is an ancestor of <i>other</i>, or the
|
|
* two modules are the same. Returns
|
|
* <code>nil</code> if there's no relationship between the two.
|
|
* (Think of the relationship in terms of the class definition:
|
|
* "class A < B" implies "B > A".)
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_ge(VALUE mod, VALUE arg)
|
|
{
|
|
if (!CLASS_OR_MODULE_P(arg)) {
|
|
rb_raise(rb_eTypeError, "compared with non class/module");
|
|
}
|
|
|
|
return rb_class_inherited_p(arg, mod);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod > other -> true, false, or nil
|
|
*
|
|
* Returns true if <i>mod</i> is an ancestor of <i>other</i>. Returns
|
|
* <code>nil</code> if there's no relationship between the two.
|
|
* (Think of the relationship in terms of the class definition:
|
|
* "class A < B" implies "B > A".)
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_gt(VALUE mod, VALUE arg)
|
|
{
|
|
if (mod == arg) return Qfalse;
|
|
return rb_mod_ge(mod, arg);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* module <=> other_module -> -1, 0, +1, or nil
|
|
*
|
|
* Comparison---Returns -1, 0, +1 or nil depending on whether +module+
|
|
* includes +other_module+, they are the same, or if +module+ is included by
|
|
* +other_module+.
|
|
*
|
|
* Returns +nil+ if +module+ has no relationship with +other_module+, if
|
|
* +other_module+ is not a module, or if the two values are incomparable.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_cmp(VALUE mod, VALUE arg)
|
|
{
|
|
VALUE cmp;
|
|
|
|
if (mod == arg) return INT2FIX(0);
|
|
if (!CLASS_OR_MODULE_P(arg)) {
|
|
return Qnil;
|
|
}
|
|
|
|
cmp = rb_class_inherited_p(mod, arg);
|
|
if (NIL_P(cmp)) return Qnil;
|
|
if (cmp) {
|
|
return INT2FIX(-1);
|
|
}
|
|
return INT2FIX(1);
|
|
}
|
|
|
|
static VALUE
|
|
rb_module_s_alloc(VALUE klass)
|
|
{
|
|
VALUE mod = rb_module_new();
|
|
|
|
RBASIC_SET_CLASS(mod, klass);
|
|
return mod;
|
|
}
|
|
|
|
static VALUE
|
|
rb_class_s_alloc(VALUE klass)
|
|
{
|
|
return rb_class_boot(0);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* Module.new -> mod
|
|
* Module.new {|mod| block } -> mod
|
|
*
|
|
* Creates a new anonymous module. If a block is given, it is passed
|
|
* the module object, and the block is evaluated in the context of this
|
|
* module like <code>module_eval</code>.
|
|
*
|
|
* fred = Module.new do
|
|
* def meth1
|
|
* "hello"
|
|
* end
|
|
* def meth2
|
|
* "bye"
|
|
* end
|
|
* end
|
|
* a = "my string"
|
|
* a.extend(fred) #=> "my string"
|
|
* a.meth1 #=> "hello"
|
|
* a.meth2 #=> "bye"
|
|
*
|
|
* Assign the module to a constant (name starting uppercase) if you
|
|
* want to treat it like a regular module.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_initialize(VALUE module)
|
|
{
|
|
if (rb_block_given_p()) {
|
|
rb_mod_module_exec(1, &module, module);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
/* :nodoc: */
|
|
static VALUE
|
|
rb_mod_initialize_clone(VALUE clone, VALUE orig)
|
|
{
|
|
VALUE ret;
|
|
ret = rb_obj_init_dup_clone(clone, orig);
|
|
if (OBJ_FROZEN(orig))
|
|
rb_class_name(clone);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* Class.new(super_class=Object) -> a_class
|
|
* Class.new(super_class=Object) { |mod| ... } -> a_class
|
|
*
|
|
* Creates a new anonymous (unnamed) class with the given superclass
|
|
* (or <code>Object</code> if no parameter is given). You can give a
|
|
* class a name by assigning the class object to a constant.
|
|
*
|
|
* If a block is given, it is passed the class object, and the block
|
|
* is evaluated in the context of this class like
|
|
* <code>class_eval</code>.
|
|
*
|
|
* fred = Class.new do
|
|
* def meth1
|
|
* "hello"
|
|
* end
|
|
* def meth2
|
|
* "bye"
|
|
* end
|
|
* end
|
|
*
|
|
* a = fred.new #=> #<#<Class:0x100381890>:0x100376b98>
|
|
* a.meth1 #=> "hello"
|
|
* a.meth2 #=> "bye"
|
|
*
|
|
* Assign the class to a constant (name starting uppercase) if you
|
|
* want to treat it like a regular class.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_class_initialize(int argc, VALUE *argv, VALUE klass)
|
|
{
|
|
VALUE super;
|
|
|
|
if (RCLASS_SUPER(klass) != 0 || klass == rb_cBasicObject) {
|
|
rb_raise(rb_eTypeError, "already initialized class");
|
|
}
|
|
if (argc == 0) {
|
|
super = rb_cObject;
|
|
}
|
|
else {
|
|
rb_scan_args(argc, argv, "01", &super);
|
|
rb_check_inheritable(super);
|
|
if (super != rb_cBasicObject && !RCLASS_SUPER(super)) {
|
|
rb_raise(rb_eTypeError, "can't inherit uninitialized class");
|
|
}
|
|
}
|
|
RCLASS_SET_SUPER(klass, super);
|
|
rb_make_metaclass(klass, RBASIC(super)->klass);
|
|
rb_class_inherited(super, klass);
|
|
rb_mod_initialize(klass);
|
|
|
|
return klass;
|
|
}
|
|
|
|
void
|
|
rb_undefined_alloc(VALUE klass)
|
|
{
|
|
rb_raise(rb_eTypeError, "allocator undefined for %"PRIsVALUE,
|
|
klass);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* class.allocate() -> obj
|
|
*
|
|
* Allocates space for a new object of <i>class</i>'s class and does not
|
|
* call initialize on the new instance. The returned object must be an
|
|
* instance of <i>class</i>.
|
|
*
|
|
* klass = Class.new do
|
|
* def initialize(*args)
|
|
* @initialized = true
|
|
* end
|
|
*
|
|
* def initialized?
|
|
* @initialized || false
|
|
* end
|
|
* end
|
|
*
|
|
* klass.allocate.initialized? #=> false
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_class_alloc(VALUE klass)
|
|
{
|
|
VALUE obj;
|
|
rb_alloc_func_t allocator;
|
|
|
|
if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) {
|
|
rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
|
|
}
|
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
|
rb_raise(rb_eTypeError, "can't create instance of singleton class");
|
|
}
|
|
allocator = rb_get_alloc_func(klass);
|
|
if (!allocator) {
|
|
rb_undefined_alloc(klass);
|
|
}
|
|
|
|
RUBY_DTRACE_CREATE_HOOK(OBJECT, rb_class2name(klass));
|
|
|
|
obj = (*allocator)(klass);
|
|
|
|
if (rb_obj_class(obj) != rb_class_real(klass)) {
|
|
rb_raise(rb_eTypeError, "wrong instance allocation");
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_alloc(VALUE klass)
|
|
{
|
|
Check_Type(klass, T_CLASS);
|
|
return rb_class_alloc(klass);
|
|
}
|
|
|
|
static VALUE
|
|
rb_class_allocate_instance(VALUE klass)
|
|
{
|
|
NEWOBJ_OF(obj, struct RObject, klass, T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0));
|
|
return (VALUE)obj;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* class.new(args, ...) -> obj
|
|
*
|
|
* Calls <code>allocate</code> to create a new object of
|
|
* <i>class</i>'s class, then invokes that object's
|
|
* <code>initialize</code> method, passing it <i>args</i>.
|
|
* This is the method that ends up getting called whenever
|
|
* an object is constructed using .new.
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_class_s_new(int argc, const VALUE *argv, VALUE klass)
|
|
{
|
|
VALUE obj;
|
|
|
|
obj = rb_class_alloc(klass);
|
|
rb_obj_call_init(obj, argc, argv);
|
|
|
|
return obj;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
|
|
{
|
|
Check_Type(klass, T_CLASS);
|
|
return rb_class_s_new(argc, argv, klass);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* class.superclass -> a_super_class or nil
|
|
*
|
|
* Returns the superclass of <i>class</i>, or <code>nil</code>.
|
|
*
|
|
* File.superclass #=> IO
|
|
* IO.superclass #=> Object
|
|
* Object.superclass #=> BasicObject
|
|
* class Foo; end
|
|
* class Bar < Foo; end
|
|
* Bar.superclass #=> Foo
|
|
*
|
|
* Returns nil when the given class does not have a parent class:
|
|
*
|
|
* BasicObject.superclass #=> nil
|
|
*
|
|
*/
|
|
|
|
VALUE
|
|
rb_class_superclass(VALUE klass)
|
|
{
|
|
VALUE super = RCLASS_SUPER(klass);
|
|
|
|
if (!super) {
|
|
if (klass == rb_cBasicObject) return Qnil;
|
|
rb_raise(rb_eTypeError, "uninitialized class");
|
|
}
|
|
while (RB_TYPE_P(super, T_ICLASS)) {
|
|
super = RCLASS_SUPER(super);
|
|
}
|
|
if (!super) {
|
|
return Qnil;
|
|
}
|
|
return super;
|
|
}
|
|
|
|
VALUE
|
|
rb_class_get_superclass(VALUE klass)
|
|
{
|
|
return RCLASS(klass)->super;
|
|
}
|
|
|
|
#define id_for_var(obj, name, part, type) \
|
|
id_for_setter(obj, name, type, "`%1$s' is not allowed as "#part" "#type" variable name")
|
|
#define id_for_setter(obj, name, type, message) \
|
|
check_setter_id(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message))
|
|
static ID
|
|
check_setter_id(VALUE obj, VALUE *pname,
|
|
int (*valid_id_p)(ID), int (*valid_name_p)(VALUE),
|
|
const char *message, size_t message_len)
|
|
{
|
|
ID id = rb_check_id(pname);
|
|
VALUE name = *pname;
|
|
|
|
if (id ? !valid_id_p(id) : !valid_name_p(name)) {
|
|
rb_name_err_raise_str(rb_fstring_new(message, message_len),
|
|
obj, name);
|
|
}
|
|
return id;
|
|
}
|
|
|
|
static int
|
|
rb_is_attr_name(VALUE name)
|
|
{
|
|
return rb_is_local_name(name) || rb_is_const_name(name);
|
|
}
|
|
|
|
static int
|
|
rb_is_attr_id(ID id)
|
|
{
|
|
return rb_is_local_id(id) || rb_is_const_id(id);
|
|
}
|
|
|
|
static const char wrong_constant_name[] = "wrong constant name %1$s";
|
|
static const char invalid_attribute_name[] = "invalid attribute name `%1$s'";
|
|
|
|
static ID
|
|
id_for_attr(VALUE obj, VALUE name)
|
|
{
|
|
ID id = id_for_setter(obj, name, attr, invalid_attribute_name);
|
|
if (!id) id = rb_intern_str(name);
|
|
return id;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* attr_reader(symbol, ...) -> nil
|
|
* attr(symbol, ...) -> nil
|
|
* attr_reader(string, ...) -> nil
|
|
* attr(string, ...) -> nil
|
|
*
|
|
* Creates instance variables and corresponding methods that return the
|
|
* value of each instance variable. Equivalent to calling
|
|
* ``<code>attr</code><i>:name</i>'' on each name in turn.
|
|
* String arguments are converted to symbols.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_attr_reader(int argc, VALUE *argv, VALUE klass)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<argc; i++) {
|
|
rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, FALSE, TRUE);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
VALUE
|
|
rb_mod_attr(int argc, VALUE *argv, VALUE klass)
|
|
{
|
|
if (argc == 2 && (argv[1] == Qtrue || argv[1] == Qfalse)) {
|
|
rb_warning("optional boolean argument is obsoleted");
|
|
rb_attr(klass, id_for_attr(klass, argv[0]), 1, RTEST(argv[1]), TRUE);
|
|
return Qnil;
|
|
}
|
|
return rb_mod_attr_reader(argc, argv, klass);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* attr_writer(symbol, ...) -> nil
|
|
* attr_writer(string, ...) -> nil
|
|
*
|
|
* Creates an accessor method to allow assignment to the attribute
|
|
* <i>symbol</i><code>.id2name</code>.
|
|
* String arguments are converted to symbols.
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_attr_writer(int argc, VALUE *argv, VALUE klass)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<argc; i++) {
|
|
rb_attr(klass, id_for_attr(klass, argv[i]), FALSE, TRUE, TRUE);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* attr_accessor(symbol, ...) -> nil
|
|
* attr_accessor(string, ...) -> nil
|
|
*
|
|
* Defines a named attribute for this module, where the name is
|
|
* <i>symbol.</i><code>id2name</code>, creating an instance variable
|
|
* (<code>@name</code>) and a corresponding access method to read it.
|
|
* Also creates a method called <code>name=</code> to set the attribute.
|
|
* String arguments are converted to symbols.
|
|
*
|
|
* module Mod
|
|
* attr_accessor(:one, :two)
|
|
* end
|
|
* Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<argc; i++) {
|
|
rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, TRUE, TRUE);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.const_get(sym, inherit=true) -> obj
|
|
* mod.const_get(str, inherit=true) -> obj
|
|
*
|
|
* Checks for a constant with the given name in <i>mod</i>.
|
|
* If +inherit+ is set, the lookup will also search
|
|
* the ancestors (and +Object+ if <i>mod</i> is a +Module+).
|
|
*
|
|
* The value of the constant is returned if a definition is found,
|
|
* otherwise a +NameError+ is raised.
|
|
*
|
|
* Math.const_get(:PI) #=> 3.14159265358979
|
|
*
|
|
* This method will recursively look up constant names if a namespaced
|
|
* class name is provided. For example:
|
|
*
|
|
* module Foo; class Bar; end end
|
|
* Object.const_get 'Foo::Bar'
|
|
*
|
|
* The +inherit+ flag is respected on each lookup. For example:
|
|
*
|
|
* module Foo
|
|
* class Bar
|
|
* VAL = 10
|
|
* end
|
|
*
|
|
* class Baz < Bar; end
|
|
* end
|
|
*
|
|
* Object.const_get 'Foo::Baz::VAL' # => 10
|
|
* Object.const_get 'Foo::Baz::VAL', false # => NameError
|
|
*
|
|
* If the argument is not a valid constant name a +NameError+ will be
|
|
* raised with a warning "wrong constant name".
|
|
*
|
|
* Object.const_get 'foobar' #=> NameError: wrong constant name foobar
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
|
|
{
|
|
VALUE name, recur;
|
|
rb_encoding *enc;
|
|
const char *pbeg, *p, *path, *pend;
|
|
ID id;
|
|
|
|
rb_check_arity(argc, 1, 2);
|
|
name = argv[0];
|
|
recur = (argc == 1) ? Qtrue : argv[1];
|
|
|
|
if (SYMBOL_P(name)) {
|
|
if (!rb_is_const_sym(name)) goto wrong_name;
|
|
id = rb_check_id(&name);
|
|
if (!id) return rb_const_missing(mod, name);
|
|
return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
|
|
}
|
|
|
|
path = StringValuePtr(name);
|
|
enc = rb_enc_get(name);
|
|
|
|
if (!rb_enc_asciicompat(enc)) {
|
|
rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
|
|
}
|
|
|
|
pbeg = p = path;
|
|
pend = path + RSTRING_LEN(name);
|
|
|
|
if (p >= pend || !*p) {
|
|
wrong_name:
|
|
rb_name_err_raise(wrong_constant_name, mod, name);
|
|
}
|
|
|
|
if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
|
|
mod = rb_cObject;
|
|
p += 2;
|
|
pbeg = p;
|
|
}
|
|
|
|
while (p < pend) {
|
|
VALUE part;
|
|
long len, beglen;
|
|
|
|
while (p < pend && *p != ':') p++;
|
|
|
|
if (pbeg == p) goto wrong_name;
|
|
|
|
id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
|
|
beglen = pbeg-path;
|
|
|
|
if (p < pend && p[0] == ':') {
|
|
if (p + 2 >= pend || p[1] != ':') goto wrong_name;
|
|
p += 2;
|
|
pbeg = p;
|
|
}
|
|
|
|
if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
|
|
QUOTE(name));
|
|
}
|
|
|
|
if (!id) {
|
|
part = rb_str_subseq(name, beglen, len);
|
|
OBJ_FREEZE(part);
|
|
if (!ISUPPER(*pbeg) || !rb_is_const_name(part)) {
|
|
name = part;
|
|
goto wrong_name;
|
|
}
|
|
else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) {
|
|
part = rb_str_intern(part);
|
|
mod = rb_const_missing(mod, part);
|
|
continue;
|
|
}
|
|
else {
|
|
rb_mod_const_missing(mod, part);
|
|
}
|
|
}
|
|
if (!rb_is_const_id(id)) {
|
|
name = ID2SYM(id);
|
|
goto wrong_name;
|
|
}
|
|
mod = RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
|
|
}
|
|
|
|
return mod;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.const_set(sym, obj) -> obj
|
|
* mod.const_set(str, obj) -> obj
|
|
*
|
|
* Sets the named constant to the given object, returning that object.
|
|
* Creates a new constant if no constant with the given name previously
|
|
* existed.
|
|
*
|
|
* Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0) #=> 3.14285714285714
|
|
* Math::HIGH_SCHOOL_PI - Math::PI #=> 0.00126448926734968
|
|
*
|
|
* If +sym+ or +str+ is not a valid constant name a +NameError+ will be
|
|
* raised with a warning "wrong constant name".
|
|
*
|
|
* Object.const_set('foobar', 42) #=> NameError: wrong constant name foobar
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_const_set(VALUE mod, VALUE name, VALUE value)
|
|
{
|
|
ID id = id_for_setter(mod, name, const, wrong_constant_name);
|
|
if (!id) id = rb_intern_str(name);
|
|
rb_const_set(mod, id, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.const_defined?(sym, inherit=true) -> true or false
|
|
* mod.const_defined?(str, inherit=true) -> true or false
|
|
*
|
|
* Says whether _mod_ or its ancestors have a constant with the given name:
|
|
*
|
|
* Float.const_defined?(:EPSILON) #=> true, found in Float itself
|
|
* Float.const_defined?("String") #=> true, found in Object (ancestor)
|
|
* BasicObject.const_defined?(:Hash) #=> false
|
|
*
|
|
* If _mod_ is a +Module+, additionally +Object+ and its ancestors are checked:
|
|
*
|
|
* Math.const_defined?(:String) #=> true, found in Object
|
|
*
|
|
* In each of the checked classes or modules, if the constant is not present
|
|
* but there is an autoload for it, +true+ is returned directly without
|
|
* autoloading:
|
|
*
|
|
* module Admin
|
|
* autoload :User, 'admin/user'
|
|
* end
|
|
* Admin.const_defined?(:User) #=> true
|
|
*
|
|
* If the constant is not found the callback +const_missing+ is *not* called
|
|
* and the method returns +false+.
|
|
*
|
|
* If +inherit+ is false, the lookup only checks the constants in the receiver:
|
|
*
|
|
* IO.const_defined?(:SYNC) #=> true, found in File::Constants (ancestor)
|
|
* IO.const_defined?(:SYNC, false) #=> false, not found in IO itself
|
|
*
|
|
* In this case, the same logic for autoloading applies.
|
|
*
|
|
* If the argument is not a valid constant name a +NameError+ is raised with the
|
|
* message "wrong constant name _name_":
|
|
*
|
|
* Hash.const_defined? 'foobar' #=> NameError: wrong constant name foobar
|
|
*
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)
|
|
{
|
|
VALUE name, recur;
|
|
rb_encoding *enc;
|
|
const char *pbeg, *p, *path, *pend;
|
|
ID id;
|
|
|
|
rb_check_arity(argc, 1, 2);
|
|
name = argv[0];
|
|
recur = (argc == 1) ? Qtrue : argv[1];
|
|
|
|
if (SYMBOL_P(name)) {
|
|
if (!rb_is_const_sym(name)) goto wrong_name;
|
|
id = rb_check_id(&name);
|
|
if (!id) return Qfalse;
|
|
return RTEST(recur) ? rb_const_defined(mod, id) : rb_const_defined_at(mod, id);
|
|
}
|
|
|
|
path = StringValuePtr(name);
|
|
enc = rb_enc_get(name);
|
|
|
|
if (!rb_enc_asciicompat(enc)) {
|
|
rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
|
|
}
|
|
|
|
pbeg = p = path;
|
|
pend = path + RSTRING_LEN(name);
|
|
|
|
if (p >= pend || !*p) {
|
|
wrong_name:
|
|
rb_name_err_raise(wrong_constant_name, mod, name);
|
|
}
|
|
|
|
if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
|
|
mod = rb_cObject;
|
|
p += 2;
|
|
pbeg = p;
|
|
}
|
|
|
|
while (p < pend) {
|
|
VALUE part;
|
|
long len, beglen;
|
|
|
|
while (p < pend && *p != ':') p++;
|
|
|
|
if (pbeg == p) goto wrong_name;
|
|
|
|
id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
|
|
beglen = pbeg-path;
|
|
|
|
if (p < pend && p[0] == ':') {
|
|
if (p + 2 >= pend || p[1] != ':') goto wrong_name;
|
|
p += 2;
|
|
pbeg = p;
|
|
}
|
|
|
|
if (!id) {
|
|
part = rb_str_subseq(name, beglen, len);
|
|
OBJ_FREEZE(part);
|
|
if (!ISUPPER(*pbeg) || !rb_is_const_name(part)) {
|
|
name = part;
|
|
goto wrong_name;
|
|
}
|
|
else {
|
|
return Qfalse;
|
|
}
|
|
}
|
|
if (!rb_is_const_id(id)) {
|
|
name = ID2SYM(id);
|
|
goto wrong_name;
|
|
}
|
|
if (RTEST(recur)) {
|
|
if (!rb_const_defined(mod, id))
|
|
return Qfalse;
|
|
mod = rb_const_get(mod, id);
|
|
}
|
|
else {
|
|
if (!rb_const_defined_at(mod, id))
|
|
return Qfalse;
|
|
mod = rb_const_get_at(mod, id);
|
|
}
|
|
recur = Qfalse;
|
|
|
|
if (p < pend && !RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
|
|
QUOTE(name));
|
|
}
|
|
}
|
|
|
|
return Qtrue;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.instance_variable_get(symbol) -> obj
|
|
* obj.instance_variable_get(string) -> obj
|
|
*
|
|
* Returns the value of the given instance variable, or nil if the
|
|
* instance variable is not set. The <code>@</code> part of the
|
|
* variable name should be included for regular instance
|
|
* variables. Throws a <code>NameError</code> exception if the
|
|
* supplied symbol is not valid as an instance variable name.
|
|
* String arguments are converted to symbols.
|
|
*
|
|
* class Fred
|
|
* def initialize(p1, p2)
|
|
* @a, @b = p1, p2
|
|
* end
|
|
* end
|
|
* fred = Fred.new('cat', 99)
|
|
* fred.instance_variable_get(:@a) #=> "cat"
|
|
* fred.instance_variable_get("@b") #=> 99
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_ivar_get(VALUE obj, VALUE iv)
|
|
{
|
|
ID id = id_for_var(obj, iv, an, instance);
|
|
|
|
if (!id) {
|
|
return Qnil;
|
|
}
|
|
return rb_ivar_get(obj, id);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.instance_variable_set(symbol, obj) -> obj
|
|
* obj.instance_variable_set(string, obj) -> obj
|
|
*
|
|
* Sets the instance variable named by <i>symbol</i> to the given
|
|
* object, thereby frustrating the efforts of the class's
|
|
* author to attempt to provide proper encapsulation. The variable
|
|
* does not have to exist prior to this call.
|
|
* If the instance variable name is passed as a string, that string
|
|
* is converted to a symbol.
|
|
*
|
|
* class Fred
|
|
* def initialize(p1, p2)
|
|
* @a, @b = p1, p2
|
|
* end
|
|
* end
|
|
* fred = Fred.new('cat', 99)
|
|
* fred.instance_variable_set(:@a, 'dog') #=> "dog"
|
|
* fred.instance_variable_set(:@c, 'cat') #=> "cat"
|
|
* fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_ivar_set(VALUE obj, VALUE iv, VALUE val)
|
|
{
|
|
ID id = id_for_var(obj, iv, an, instance);
|
|
if (!id) id = rb_intern_str(iv);
|
|
return rb_ivar_set(obj, id, val);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.instance_variable_defined?(symbol) -> true or false
|
|
* obj.instance_variable_defined?(string) -> true or false
|
|
*
|
|
* Returns <code>true</code> if the given instance variable is
|
|
* defined in <i>obj</i>.
|
|
* String arguments are converted to symbols.
|
|
*
|
|
* class Fred
|
|
* def initialize(p1, p2)
|
|
* @a, @b = p1, p2
|
|
* end
|
|
* end
|
|
* fred = Fred.new('cat', 99)
|
|
* fred.instance_variable_defined?(:@a) #=> true
|
|
* fred.instance_variable_defined?("@b") #=> true
|
|
* fred.instance_variable_defined?("@c") #=> false
|
|
*/
|
|
|
|
static VALUE
|
|
rb_obj_ivar_defined(VALUE obj, VALUE iv)
|
|
{
|
|
ID id = id_for_var(obj, iv, an, instance);
|
|
|
|
if (!id) {
|
|
return Qfalse;
|
|
}
|
|
return rb_ivar_defined(obj, id);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.class_variable_get(symbol) -> obj
|
|
* mod.class_variable_get(string) -> obj
|
|
*
|
|
* Returns the value of the given class variable (or throws a
|
|
* <code>NameError</code> exception). The <code>@@</code> part of the
|
|
* variable name should be included for regular class variables.
|
|
* String arguments are converted to symbols.
|
|
*
|
|
* class Fred
|
|
* @@foo = 99
|
|
* end
|
|
* Fred.class_variable_get(:@@foo) #=> 99
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_cvar_get(VALUE obj, VALUE iv)
|
|
{
|
|
ID id = id_for_var(obj, iv, a, class);
|
|
|
|
if (!id) {
|
|
rb_name_err_raise("uninitialized class variable %1$s in %2$s",
|
|
obj, iv);
|
|
}
|
|
return rb_cvar_get(obj, id);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.class_variable_set(symbol, obj) -> obj
|
|
* obj.class_variable_set(string, obj) -> obj
|
|
*
|
|
* Sets the class variable named by <i>symbol</i> to the given
|
|
* object.
|
|
* If the class variable name is passed as a string, that string
|
|
* is converted to a symbol.
|
|
*
|
|
* class Fred
|
|
* @@foo = 99
|
|
* def foo
|
|
* @@foo
|
|
* end
|
|
* end
|
|
* Fred.class_variable_set(:@@foo, 101) #=> 101
|
|
* Fred.new.foo #=> 101
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_cvar_set(VALUE obj, VALUE iv, VALUE val)
|
|
{
|
|
ID id = id_for_var(obj, iv, a, class);
|
|
if (!id) id = rb_intern_str(iv);
|
|
rb_cvar_set(obj, id, val);
|
|
return val;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* obj.class_variable_defined?(symbol) -> true or false
|
|
* obj.class_variable_defined?(string) -> true or false
|
|
*
|
|
* Returns <code>true</code> if the given class variable is defined
|
|
* in <i>obj</i>.
|
|
* String arguments are converted to symbols.
|
|
*
|
|
* class Fred
|
|
* @@foo = 99
|
|
* end
|
|
* Fred.class_variable_defined?(:@@foo) #=> true
|
|
* Fred.class_variable_defined?(:@@bar) #=> false
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_cvar_defined(VALUE obj, VALUE iv)
|
|
{
|
|
ID id = id_for_var(obj, iv, a, class);
|
|
|
|
if (!id) {
|
|
return Qfalse;
|
|
}
|
|
return rb_cvar_defined(obj, id);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* mod.singleton_class? -> true or false
|
|
*
|
|
* Returns <code>true</code> if <i>mod</i> is a singleton class or
|
|
* <code>false</code> if it is an ordinary class or module.
|
|
*
|
|
* class C
|
|
* end
|
|
* C.singleton_class? #=> false
|
|
* C.singleton_class.singleton_class? #=> true
|
|
*/
|
|
|
|
static VALUE
|
|
rb_mod_singleton_p(VALUE klass)
|
|
{
|
|
if (RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON))
|
|
return Qtrue;
|
|
return Qfalse;
|
|
}
|
|
|
|
static const struct conv_method_tbl {
|
|
const char method[6];
|
|
unsigned short id;
|
|
} conv_method_names[] = {
|
|
#define M(n) {#n, (unsigned short)idTo_##n}
|
|
M(int),
|
|
M(ary),
|
|
M(str),
|
|
M(sym),
|
|
M(hash),
|
|
M(proc),
|
|
M(io),
|
|
M(a),
|
|
M(s),
|
|
M(i),
|
|
#undef M
|
|
};
|
|
#define IMPLICIT_CONVERSIONS 7
|
|
|
|
static VALUE
|
|
convert_type(VALUE val, const char *tname, const char *method, int raise)
|
|
{
|
|
ID m = 0;
|
|
int i = numberof(conv_method_names);
|
|
VALUE r;
|
|
static const char prefix[] = "to_";
|
|
|
|
if (strncmp(prefix, method, sizeof(prefix)-1) == 0) {
|
|
const char *const meth = &method[sizeof(prefix)-1];
|
|
for (i=0; i < numberof(conv_method_names); i++) {
|
|
if (conv_method_names[i].method[0] == meth[0] &&
|
|
strcmp(conv_method_names[i].method, meth) == 0) {
|
|
m = conv_method_names[i].id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!m) m = rb_intern(method);
|
|
r = rb_check_funcall(val, m, 0, 0);
|
|
if (r == Qundef) {
|
|
if (raise) {
|
|
const char *msg = i < IMPLICIT_CONVERSIONS ?
|
|
"no implicit conversion of" : "can't convert";
|
|
const char *cname = NIL_P(val) ? "nil" :
|
|
val == Qtrue ? "true" :
|
|
val == Qfalse ? "false" :
|
|
NULL;
|
|
if (cname)
|
|
rb_raise(rb_eTypeError, "%s %s into %s", msg, cname, tname);
|
|
rb_raise(rb_eTypeError, "%s %"PRIsVALUE" into %s", msg,
|
|
rb_obj_class(val),
|
|
tname);
|
|
}
|
|
return Qnil;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
NORETURN(static void conversion_mismatch(VALUE, const char *, const char *, VALUE));
|
|
static void
|
|
conversion_mismatch(VALUE val, const char *tname, const char *method, VALUE result)
|
|
{
|
|
VALUE cname = rb_obj_class(val);
|
|
rb_raise(rb_eTypeError,
|
|
"can't convert %"PRIsVALUE" to %s (%"PRIsVALUE"#%s gives %"PRIsVALUE")",
|
|
cname, tname, cname, method, rb_obj_class(result));
|
|
}
|
|
|
|
VALUE
|
|
rb_convert_type(VALUE val, int type, const char *tname, const char *method)
|
|
{
|
|
VALUE v;
|
|
|
|
if (TYPE(val) == type) return val;
|
|
v = convert_type(val, tname, method, TRUE);
|
|
if (TYPE(v) != type) {
|
|
conversion_mismatch(val, tname, method, v);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
VALUE
|
|
rb_check_convert_type(VALUE val, int type, const char *tname, const char *method)
|
|
{
|
|
VALUE v;
|
|
|
|
/* always convert T_DATA */
|
|
if (TYPE(val) == type && type != T_DATA) return val;
|
|
v = convert_type(val, tname, method, FALSE);
|
|
if (NIL_P(v)) return Qnil;
|
|
if (TYPE(v) != type) {
|
|
conversion_mismatch(val, tname, method, v);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
|
|
static VALUE
|
|
rb_to_integer(VALUE val, const char *method)
|
|
{
|
|
VALUE v;
|
|
|
|
if (FIXNUM_P(val)) return val;
|
|
if (RB_TYPE_P(val, T_BIGNUM)) return val;
|
|
v = convert_type(val, "Integer", method, TRUE);
|
|
if (!rb_obj_is_kind_of(v, rb_cInteger)) {
|
|
conversion_mismatch(val, "Integer", method, v);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
VALUE
|
|
rb_check_to_integer(VALUE val, const char *method)
|
|
{
|
|
VALUE v;
|
|
|
|
if (FIXNUM_P(val)) return val;
|
|
if (RB_TYPE_P(val, T_BIGNUM)) return val;
|
|
v = convert_type(val, "Integer", method, FALSE);
|
|
if (!rb_obj_is_kind_of(v, rb_cInteger)) {
|
|
return Qnil;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
VALUE
|
|
rb_to_int(VALUE val)
|
|
{
|
|
return rb_to_integer(val, "to_int");
|
|
}
|
|
|
|
VALUE
|
|
rb_check_to_int(VALUE val)
|
|
{
|
|
return rb_check_to_integer(val, "to_int");
|
|
}
|
|
|
|
static VALUE
|
|
rb_convert_to_integer(VALUE val, int base)
|
|
{
|
|
VALUE tmp;
|
|
|
|
if (RB_FLOAT_TYPE_P(val)) {
|
|
if (base != 0) goto arg_error;
|
|
return rb_dbl2ival(RFLOAT_VALUE(val));
|
|
}
|
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
if (base != 0) goto arg_error;
|
|
return val;
|
|
}
|
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
return rb_str_to_inum(val, base, TRUE);
|
|
}
|
|
else if (NIL_P(val)) {
|
|
if (base != 0) goto arg_error;
|
|
rb_raise(rb_eTypeError, "can't convert nil into Integer");
|
|
}
|
|
if (base != 0) {
|
|
tmp = rb_check_string_type(val);
|
|
if (!NIL_P(tmp)) return rb_str_to_inum(tmp, base, TRUE);
|
|
arg_error:
|
|
rb_raise(rb_eArgError, "base specified for non string value");
|
|
}
|
|
tmp = convert_type(val, "Integer", "to_int", FALSE);
|
|
if (NIL_P(tmp)) {
|
|
return rb_to_integer(val, "to_i");
|
|
}
|
|
return tmp;
|
|
|
|
}
|
|
|
|
VALUE
|
|
rb_Integer(VALUE val)
|
|
{
|
|
return rb_convert_to_integer(val, 0);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* Integer(arg, base=0) -> integer
|
|
*
|
|
* Converts <i>arg</i> to an <code>Integer</code>.
|
|
* Numeric types are converted directly (with floating point numbers
|
|
* being truncated). <i>base</i> (0, or between 2 and 36) is a base for
|
|
* integer string representation. If <i>arg</i> is a <code>String</code>,
|
|
* when <i>base</i> is omitted or equals zero, radix indicators
|
|
* (<code>0</code>, <code>0b</code>, and <code>0x</code>) are honored.
|
|
* In any case, strings should be strictly conformed to numeric
|
|
* representation. This behavior is different from that of
|
|
* <code>String#to_i</code>. Non string values will be converted by first
|
|
* trying <code>to_int</code>, then <code>to_i</code>. Passing <code>nil</code>
|
|
* raises a TypeError.
|
|
*
|
|
* Integer(123.999) #=> 123
|
|
* Integer("0x1a") #=> 26
|
|
* Integer(Time.new) #=> 1204973019
|
|
* Integer("0930", 10) #=> 930
|
|
* Integer("111", 2) #=> 7
|
|
* Integer(nil) #=> TypeError
|
|
*/
|
|
|
|
static VALUE
|
|
rb_f_integer(int argc, VALUE *argv, VALUE obj)
|
|
{
|
|
VALUE arg = Qnil;
|
|
int base = 0;
|
|
|
|
switch (argc) {
|
|
case 2:
|
|
base = NUM2INT(argv[1]);
|
|
case 1:
|
|
arg = argv[0];
|
|
break;
|
|
default:
|
|
/* should cause ArgumentError */
|
|
rb_scan_args(argc, argv, "11", NULL, NULL);
|
|
}
|
|
return rb_convert_to_integer(arg, base);
|
|
}
|
|
|
|
double
|
|
rb_cstr_to_dbl(const char *p, int badcheck)
|
|
{
|
|
const char *q;
|
|
char *end;
|
|
double d;
|
|
const char *ellipsis = "";
|
|
int w;
|
|
enum {max_width = 20};
|
|
#define OutOfRange() ((end - p > max_width) ? \
|
|
(w = max_width, ellipsis = "...") : \
|
|
(w = (int)(end - p), ellipsis = ""))
|
|
|
|
if (!p) return 0.0;
|
|
q = p;
|
|
while (ISSPACE(*p)) p++;
|
|
|
|
if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
|
return 0.0;
|
|
}
|
|
|
|
d = strtod(p, &end);
|
|
if (errno == ERANGE) {
|
|
OutOfRange();
|
|
rb_warning("Float %.*s%s out of range", w, p, ellipsis);
|
|
errno = 0;
|
|
}
|
|
if (p == end) {
|
|
if (badcheck) {
|
|
bad:
|
|
rb_invalid_str(q, "Float()");
|
|
}
|
|
return d;
|
|
}
|
|
if (*end) {
|
|
char buf[DBL_DIG * 4 + 10];
|
|
char *n = buf;
|
|
char *e = buf + sizeof(buf) - 1;
|
|
char prev = 0;
|
|
|
|
while (p < end && n < e) prev = *n++ = *p++;
|
|
while (*p) {
|
|
if (*p == '_') {
|
|
/* remove underscores between digits */
|
|
if (badcheck) {
|
|
if (n == buf || !ISDIGIT(prev)) goto bad;
|
|
++p;
|
|
if (!ISDIGIT(*p)) goto bad;
|
|
}
|
|
else {
|
|
while (*++p == '_');
|
|
continue;
|
|
}
|
|
}
|
|
prev = *p++;
|
|
if (n < e) *n++ = prev;
|
|
}
|
|
*n = '\0';
|
|
p = buf;
|
|
|
|
if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
|
return 0.0;
|
|
}
|
|
|
|
d = strtod(p, &end);
|
|
if (errno == ERANGE) {
|
|
OutOfRange();
|
|
rb_warning("Float %.*s%s out of range", w, p, ellipsis);
|
|
errno = 0;
|
|
}
|
|
if (badcheck) {
|
|
if (!end || p == end) goto bad;
|
|
while (*end && ISSPACE(*end)) end++;
|
|
if (*end) goto bad;
|
|
}
|
|
}
|
|
if (errno == ERANGE) {
|
|
errno = 0;
|
|
OutOfRange();
|
|
rb_raise(rb_eArgError, "Float %.*s%s out of range", w, q, ellipsis);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
double
|
|
rb_str_to_dbl(VALUE str, int badcheck)
|
|
{
|
|
char *s;
|
|
long len;
|
|
double ret;
|
|
VALUE v = 0;
|
|
|
|
StringValue(str);
|
|
s = RSTRING_PTR(str);
|
|
len = RSTRING_LEN(str);
|
|
if (s) {
|
|
if (badcheck && memchr(s, '\0', len)) {
|
|
rb_raise(rb_eArgError, "string for Float contains null byte");
|
|
}
|
|
if (s[len]) { /* no sentinel somehow */
|
|
char *p = ALLOCV(v, len);
|
|
MEMCPY(p, s, char, len);
|
|
p[len] = '\0';
|
|
s = p;
|
|
}
|
|
}
|
|
ret = rb_cstr_to_dbl(s, badcheck);
|
|
if (v)
|
|
ALLOCV_END(v);
|
|
return ret;
|
|
}
|
|
|
|
#define fix2dbl_without_to_f(x) (double)FIX2LONG(x)
|
|
#define big2dbl_without_to_f(x) rb_big2dbl(x)
|
|
#define int2dbl_without_to_f(x) \
|
|
(FIXNUM_P(x) ? fix2dbl_without_to_f(x) : big2dbl_without_to_f(x))
|
|
#define rat2dbl_without_to_f(x) \
|
|
(int2dbl_without_to_f(rb_rational_num(x)) / \
|
|
int2dbl_without_to_f(rb_rational_den(x)))
|
|
|
|
#define special_const_to_float(val, pre, post) \
|
|
switch (val) { \
|
|
case Qnil: \
|
|
rb_raise(rb_eTypeError, pre "nil" post); \
|
|
case Qtrue: \
|
|
rb_raise(rb_eTypeError, pre "true" post); \
|
|
case Qfalse: \
|
|
rb_raise(rb_eTypeError, pre "false" post); \
|
|
}
|
|
|
|
static inline void
|
|
conversion_to_float(VALUE val)
|
|
{
|
|
special_const_to_float(val, "can't convert ", " into Float");
|
|
}
|
|
|
|
static inline void
|
|
implicit_conversion_to_float(VALUE val)
|
|
{
|
|
special_const_to_float(val, "no implicit conversion to float from ", "");
|
|
}
|
|
|
|
static int
|
|
to_float(VALUE *valp)
|
|
{
|
|
VALUE val = *valp;
|
|
if (SPECIAL_CONST_P(val)) {
|
|
if (FIXNUM_P(val)) {
|
|
*valp = DBL2NUM(fix2dbl_without_to_f(val));
|
|
return T_FLOAT;
|
|
}
|
|
else if (FLONUM_P(val)) {
|
|
return T_FLOAT;
|
|
}
|
|
else {
|
|
conversion_to_float(val);
|
|
}
|
|
}
|
|
else {
|
|
int type = BUILTIN_TYPE(val);
|
|
switch (type) {
|
|
case T_FLOAT:
|
|
return T_FLOAT;
|
|
case T_BIGNUM:
|
|
*valp = DBL2NUM(big2dbl_without_to_f(val));
|
|
return T_FLOAT;
|
|
case T_RATIONAL:
|
|
*valp = DBL2NUM(rat2dbl_without_to_f(val));
|
|
return T_FLOAT;
|
|
case T_STRING:
|
|
return T_STRING;
|
|
}
|
|
}
|
|
return T_NONE;
|
|
}
|
|
|
|
VALUE
|
|
rb_Float(VALUE val)
|
|
{
|
|
switch (to_float(&val)) {
|
|
case T_FLOAT:
|
|
return val;
|
|
case T_STRING:
|
|
return DBL2NUM(rb_str_to_dbl(val, TRUE));
|
|
}
|
|
return rb_convert_type(val, T_FLOAT, "Float", "to_f");
|
|
}
|
|
|
|
FUNC_MINIMIZED(static VALUE rb_f_float(VALUE obj, VALUE arg));
|
|
|
|
/*
|
|
* call-seq:
|
|
* Float(arg) -> float
|
|
*
|
|
* Returns <i>arg</i> converted to a float. Numeric types are converted
|
|
* directly, and with exception to string and nil the rest are converted using <i>arg</i>.to_f.
|
|
* Converting a <code>string</code> with invalid characters will result in a <code>ArgumentError</code>.
|
|
* Converting <code>nil</code> generates a <code>TypeError</code>.
|
|
*
|
|
* Float(1) #=> 1.0
|
|
* Float("123.456") #=> 123.456
|
|
* Float("123.0_badstring") #=> ArgumentError: invalid value for Float(): "123.0_badstring"
|
|
* Float(nil) #=> TypeError: can't convert nil into Float
|
|
*/
|
|
|
|
static VALUE
|
|
rb_f_float(VALUE obj, VALUE arg)
|
|
{
|
|
return rb_Float(arg);
|
|
}
|
|
|
|
static VALUE
|
|
numeric_to_float(VALUE val)
|
|
{
|
|
if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
|
|
rb_raise(rb_eTypeError, "can't convert %"PRIsVALUE" into Float",
|
|
rb_obj_class(val));
|
|
}
|
|
return rb_convert_type(val, T_FLOAT, "Float", "to_f");
|
|
}
|
|
|
|
VALUE
|
|
rb_to_float(VALUE val)
|
|
{
|
|
switch (to_float(&val)) {
|
|
case T_FLOAT:
|
|
return val;
|
|
}
|
|
return numeric_to_float(val);
|
|
}
|
|
|
|
VALUE
|
|
rb_check_to_float(VALUE val)
|
|
{
|
|
if (RB_TYPE_P(val, T_FLOAT)) return val;
|
|
if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
|
|
return Qnil;
|
|
}
|
|
return rb_check_convert_type(val, T_FLOAT, "Float", "to_f");
|
|
}
|
|
|
|
static ID id_to_f;
|
|
|
|
static inline int
|
|
basic_to_f_p(VALUE klass)
|
|
{
|
|
return rb_method_basic_definition_p(klass, id_to_f);
|
|
}
|
|
|
|
double
|
|
rb_num_to_dbl(VALUE val)
|
|
{
|
|
if (SPECIAL_CONST_P(val)) {
|
|
if (FIXNUM_P(val)) {
|
|
if (basic_to_f_p(rb_cInteger))
|
|
return fix2dbl_without_to_f(val);
|
|
}
|
|
else if (FLONUM_P(val)) {
|
|
return rb_float_flonum_value(val);
|
|
}
|
|
else {
|
|
conversion_to_float(val);
|
|
}
|
|
}
|
|
else {
|
|
switch (BUILTIN_TYPE(val)) {
|
|
case T_FLOAT:
|
|
return rb_float_noflonum_value(val);
|
|
case T_BIGNUM:
|
|
if (basic_to_f_p(rb_cInteger))
|
|
return big2dbl_without_to_f(val);
|
|
break;
|
|
case T_RATIONAL:
|
|
if (basic_to_f_p(rb_cRational))
|
|
return rat2dbl_without_to_f(val);
|
|
break;
|
|
}
|
|
}
|
|
val = numeric_to_float(val);
|
|
return RFLOAT_VALUE(val);
|
|
}
|
|
|
|
double
|
|
rb_num2dbl(VALUE val)
|
|
{
|
|
if (SPECIAL_CONST_P(val)) {
|
|
if (FIXNUM_P(val)) {
|
|
return fix2dbl_without_to_f(val);
|
|
}
|
|
else if (FLONUM_P(val)) {
|
|
return rb_float_flonum_value(val);
|
|
}
|
|
else {
|
|
implicit_conversion_to_float(val);
|
|
}
|
|
}
|
|
else {
|
|
switch (BUILTIN_TYPE(val)) {
|
|
case T_FLOAT:
|
|
return rb_float_noflonum_value(val);
|
|
case T_BIGNUM:
|
|
return big2dbl_without_to_f(val);
|
|
case T_RATIONAL:
|
|
return rat2dbl_without_to_f(val);
|
|
case T_STRING:
|
|
rb_raise(rb_eTypeError, "no implicit conversion to float from string");
|
|
}
|
|
}
|
|
val = rb_convert_type(val, T_FLOAT, "Float", "to_f");
|
|
return RFLOAT_VALUE(val);
|
|
}
|
|
|
|
VALUE
|
|
rb_String(VALUE val)
|
|
{
|
|
VALUE tmp = rb_check_string_type(val);
|
|
if (NIL_P(tmp))
|
|
tmp = rb_convert_type(val, T_STRING, "String", "to_s");
|
|
return tmp;
|
|
}
|
|
|
|
|
|
/*
|
|
* call-seq:
|
|
* String(arg) -> string
|
|
*
|
|
* Returns <i>arg</i> as a <code>String</code>.
|
|
*
|
|
* First tries to call its <code>to_str</code> method, then its <code>to_s</code> method.
|
|
*
|
|
* String(self) #=> "main"
|
|
* String(self.class) #=> "Object"
|
|
* String(123456) #=> "123456"
|
|
*/
|
|
|
|
static VALUE
|
|
rb_f_string(VALUE obj, VALUE arg)
|
|
{
|
|
return rb_String(arg);
|
|
}
|
|
|
|
VALUE
|
|
rb_Array(VALUE val)
|
|
{
|
|
VALUE tmp = rb_check_array_type(val);
|
|
|
|
if (NIL_P(tmp)) {
|
|
tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a");
|
|
if (NIL_P(tmp)) {
|
|
return rb_ary_new3(1, val);
|
|
}
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* Array(arg) -> array
|
|
*
|
|
* Returns +arg+ as an Array.
|
|
*
|
|
* First tries to call <code>to_ary</code> on +arg+, then <code>to_a</code>.
|
|
*
|
|
* Array(1..5) #=> [1, 2, 3, 4, 5]
|
|
*/
|
|
|
|
static VALUE
|
|
rb_f_array(VALUE obj, VALUE arg)
|
|
{
|
|
return rb_Array(arg);
|
|
}
|
|
|
|
VALUE
|
|
rb_Hash(VALUE val)
|
|
{
|
|
VALUE tmp;
|
|
|
|
if (NIL_P(val)) return rb_hash_new();
|
|
tmp = rb_check_hash_type(val);
|
|
if (NIL_P(tmp)) {
|
|
if (RB_TYPE_P(val, T_ARRAY) && RARRAY_LEN(val) == 0)
|
|
return rb_hash_new();
|
|
rb_raise(rb_eTypeError, "can't convert %s into Hash", rb_obj_classname(val));
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* Hash(arg) -> hash
|
|
*
|
|
* Converts <i>arg</i> to a <code>Hash</code> by calling
|
|
* <i>arg</i><code>.to_hash</code>. Returns an empty <code>Hash</code> when
|
|
* <i>arg</i> is <tt>nil</tt> or <tt>[]</tt>.
|
|
*
|
|
* Hash([]) #=> {}
|
|
* Hash(nil) #=> {}
|
|
* Hash(key: :value) #=> {:key => :value}
|
|
* Hash([1, 2, 3]) #=> TypeError
|
|
*/
|
|
|
|
static VALUE
|
|
rb_f_hash(VALUE obj, VALUE arg)
|
|
{
|
|
return rb_Hash(arg);
|
|
}
|
|
|
|
struct dig_method {
|
|
VALUE klass;
|
|
int basic;
|
|
};
|
|
|
|
static ID id_dig;
|
|
|
|
static int
|
|
dig_basic_p(VALUE obj, struct dig_method *cache)
|
|
{
|
|
VALUE klass = RBASIC_CLASS(obj);
|
|
if (klass != cache->klass) {
|
|
cache->klass = klass;
|
|
cache->basic = rb_method_basic_definition_p(klass, id_dig);
|
|
}
|
|
return cache->basic;
|
|
}
|
|
|
|
static void
|
|
no_dig_method(int found, VALUE recv, ID mid, int argc, const VALUE *argv, VALUE data)
|
|
{
|
|
if (!found) {
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not have #dig method",
|
|
CLASS_OF(data));
|
|
}
|
|
}
|
|
|
|
VALUE
|
|
rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
|
|
{
|
|
struct dig_method hash = {Qnil}, ary = {Qnil}, strt = {Qnil};
|
|
|
|
for (; argc > 0; ++argv, --argc) {
|
|
if (NIL_P(obj)) return notfound;
|
|
if (!SPECIAL_CONST_P(obj)) {
|
|
switch (BUILTIN_TYPE(obj)) {
|
|
case T_HASH:
|
|
if (dig_basic_p(obj, &hash)) {
|
|
obj = rb_hash_aref(obj, *argv);
|
|
continue;
|
|
}
|
|
break;
|
|
case T_ARRAY:
|
|
if (dig_basic_p(obj, &ary)) {
|
|
obj = rb_ary_at(obj, *argv);
|
|
continue;
|
|
}
|
|
break;
|
|
case T_STRUCT:
|
|
if (dig_basic_p(obj, &strt)) {
|
|
obj = rb_struct_lookup(obj, *argv);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return rb_check_funcall_with_hook(obj, id_dig, argc, argv,
|
|
no_dig_method, obj);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
* Document-class: Class
|
|
*
|
|
* Classes in Ruby are first-class objects---each is an instance of
|
|
* class <code>Class</code>.
|
|
*
|
|
* Typically, you create a new class by using:
|
|
*
|
|
* class Name
|
|
* # some code describing the class behavior
|
|
* end
|
|
*
|
|
* When a new class is created, an object of type Class is initialized and
|
|
* assigned to a global constant (<code>Name</code> in this case).
|
|
*
|
|
* When <code>Name.new</code> is called to create a new object, the
|
|
* <code>new</code> method in <code>Class</code> is run by default.
|
|
* This can be demonstrated by overriding <code>new</code> in
|
|
* <code>Class</code>:
|
|
*
|
|
* class Class
|
|
* alias old_new new
|
|
* def new(*args)
|
|
* print "Creating a new ", self.name, "\n"
|
|
* old_new(*args)
|
|
* end
|
|
* end
|
|
*
|
|
* class Name
|
|
* end
|
|
*
|
|
* n = Name.new
|
|
*
|
|
* <em>produces:</em>
|
|
*
|
|
* Creating a new Name
|
|
*
|
|
* Classes, modules, and objects are interrelated. In the diagram
|
|
* that follows, the vertical arrows represent inheritance, and the
|
|
* parentheses metaclasses. All metaclasses are instances
|
|
* of the class `Class'.
|
|
* +---------+ +-...
|
|
* | | |
|
|
* BasicObject-----|-->(BasicObject)-------|-...
|
|
* ^ | ^ |
|
|
* | | | |
|
|
* Object---------|----->(Object)---------|-...
|
|
* ^ | ^ |
|
|
* | | | |
|
|
* +-------+ | +--------+ |
|
|
* | | | | | |
|
|
* | Module-|---------|--->(Module)-|-...
|
|
* | ^ | | ^ |
|
|
* | | | | | |
|
|
* | Class-|---------|---->(Class)-|-...
|
|
* | ^ | | ^ |
|
|
* | +---+ | +----+
|
|
* | |
|
|
* obj--->OtherClass---------->(OtherClass)-----------...
|
|
*
|
|
*/
|
|
|
|
|
|
/*!
|
|
* Initializes the world of objects and classes.
|
|
*
|
|
* At first, the function bootstraps the class hierarchy.
|
|
* It initializes the most fundamental classes and their metaclasses.
|
|
* - \c BasicObject
|
|
* - \c Object
|
|
* - \c Module
|
|
* - \c Class
|
|
* After the bootstrap step, the class hierarchy becomes as the following
|
|
* diagram.
|
|
*
|
|
* \image html boottime-classes.png
|
|
*
|
|
* Then, the function defines classes, modules and methods as usual.
|
|
* \ingroup class
|
|
*/
|
|
|
|
/* Document-class: BasicObject
|
|
*
|
|
* BasicObject is the parent class of all classes in Ruby. It's an explicit
|
|
* blank class.
|
|
*
|
|
* BasicObject can be used for creating object hierarchies independent of
|
|
* Ruby's object hierarchy, proxy objects like the Delegator class, or other
|
|
* uses where namespace pollution from Ruby's methods and classes must be
|
|
* avoided.
|
|
*
|
|
* To avoid polluting BasicObject for other users an appropriately named
|
|
* subclass of BasicObject should be created instead of directly modifying
|
|
* BasicObject:
|
|
*
|
|
* class MyObjectSystem < BasicObject
|
|
* end
|
|
*
|
|
* BasicObject does not include Kernel (for methods like +puts+) and
|
|
* BasicObject is outside of the namespace of the standard library so common
|
|
* classes will not be found without using a full class path.
|
|
*
|
|
* A variety of strategies can be used to provide useful portions of the
|
|
* standard library to subclasses of BasicObject. A subclass could
|
|
* <code>include Kernel</code> to obtain +puts+, +exit+, etc. A custom
|
|
* Kernel-like module could be created and included or delegation can be used
|
|
* via #method_missing:
|
|
*
|
|
* class MyObjectSystem < BasicObject
|
|
* DELEGATE = [:puts, :p]
|
|
*
|
|
* def method_missing(name, *args, &block)
|
|
* super unless DELEGATE.include? name
|
|
* ::Kernel.send(name, *args, &block)
|
|
* end
|
|
*
|
|
* def respond_to_missing?(name, include_private = false)
|
|
* DELEGATE.include?(name) or super
|
|
* end
|
|
* end
|
|
*
|
|
* Access to classes and modules from the Ruby standard library can be
|
|
* obtained in a BasicObject subclass by referencing the desired constant
|
|
* from the root like <code>::File</code> or <code>::Enumerator</code>.
|
|
* Like #method_missing, #const_missing can be used to delegate constant
|
|
* lookup to +Object+:
|
|
*
|
|
* class MyObjectSystem < BasicObject
|
|
* def self.const_missing(name)
|
|
* ::Object.const_get(name)
|
|
* end
|
|
* end
|
|
*/
|
|
|
|
/* Document-class: Object
|
|
*
|
|
* Object is the default root of all Ruby objects. Object inherits from
|
|
* BasicObject which allows creating alternate object hierarchies. Methods
|
|
* on Object are available to all classes unless explicitly overridden.
|
|
*
|
|
* Object mixes in the Kernel module, making the built-in kernel functions
|
|
* globally accessible. Although the instance methods of Object are defined
|
|
* by the Kernel module, we have chosen to document them here for clarity.
|
|
*
|
|
* When referencing constants in classes inheriting from Object you do not
|
|
* need to use the full namespace. For example, referencing +File+ inside
|
|
* +YourClass+ will find the top-level File class.
|
|
*
|
|
* In the descriptions of Object's methods, the parameter <i>symbol</i> refers
|
|
* to a symbol, which is either a quoted string or a Symbol (such as
|
|
* <code>:name</code>).
|
|
*/
|
|
|
|
void
|
|
InitVM_Object(void)
|
|
{
|
|
Init_class_hierarchy();
|
|
|
|
#if 0
|
|
// teach RDoc about these classes
|
|
rb_cBasicObject = rb_define_class("BasicObject", Qnil);
|
|
rb_cObject = rb_define_class("Object", rb_cBasicObject);
|
|
rb_cModule = rb_define_class("Module", rb_cObject);
|
|
rb_cClass = rb_define_class("Class", rb_cModule);
|
|
#endif
|
|
|
|
#undef rb_intern
|
|
#define rb_intern(str) rb_intern_const(str)
|
|
|
|
rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);
|
|
rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);
|
|
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);
|
|
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);
|
|
rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0);
|
|
rb_define_method(rb_cBasicObject, "!=", rb_obj_not_equal, 1);
|
|
|
|
rb_define_private_method(rb_cBasicObject, "singleton_method_added", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cBasicObject, "singleton_method_removed", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cBasicObject, "singleton_method_undefined", rb_obj_dummy, 1);
|
|
|
|
/* Document-module: Kernel
|
|
*
|
|
* The Kernel module is included by class Object, so its methods are
|
|
* available in every Ruby object.
|
|
*
|
|
* The Kernel instance methods are documented in class Object while the
|
|
* module methods are documented here. These methods are called without a
|
|
* receiver and thus can be called in functional form:
|
|
*
|
|
* sprintf "%.1f", 1.234 #=> "1.2"
|
|
*
|
|
*/
|
|
rb_mKernel = rb_define_module("Kernel");
|
|
rb_include_module(rb_cObject, rb_mKernel);
|
|
rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "prepended", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1);
|
|
rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1);
|
|
|
|
rb_define_method(rb_mKernel, "nil?", rb_false, 0);
|
|
rb_define_method(rb_mKernel, "===", rb_equal, 1);
|
|
rb_define_method(rb_mKernel, "=~", rb_obj_match, 1);
|
|
rb_define_method(rb_mKernel, "!~", rb_obj_not_match, 1);
|
|
rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1);
|
|
rb_define_method(rb_mKernel, "hash", rb_obj_hash, 0);
|
|
rb_define_method(rb_mKernel, "<=>", rb_obj_cmp, 1);
|
|
|
|
rb_define_method(rb_mKernel, "class", rb_obj_class, 0);
|
|
rb_define_method(rb_mKernel, "singleton_class", rb_obj_singleton_class, 0);
|
|
rb_define_method(rb_mKernel, "clone", rb_obj_clone2, -1);
|
|
rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0);
|
|
rb_define_method(rb_mKernel, "itself", rb_obj_itself, 0);
|
|
rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1);
|
|
rb_define_method(rb_mKernel, "initialize_dup", rb_obj_init_dup_clone, 1);
|
|
rb_define_method(rb_mKernel, "initialize_clone", rb_obj_init_dup_clone, 1);
|
|
|
|
rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0);
|
|
rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0);
|
|
rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0);
|
|
rb_define_method(rb_mKernel, "untrust", rb_obj_untrust, 0);
|
|
rb_define_method(rb_mKernel, "untrusted?", rb_obj_untrusted, 0);
|
|
rb_define_method(rb_mKernel, "trust", rb_obj_trust, 0);
|
|
rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0);
|
|
rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0);
|
|
|
|
rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0);
|
|
rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0);
|
|
rb_define_method(rb_mKernel, "methods", rb_obj_methods, -1); /* in class.c */
|
|
rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); /* in class.c */
|
|
rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, -1); /* in class.c */
|
|
rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, -1); /* in class.c */
|
|
rb_define_method(rb_mKernel, "public_methods", rb_obj_public_methods, -1); /* in class.c */
|
|
rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); /* in variable.c */
|
|
rb_define_method(rb_mKernel, "instance_variable_get", rb_obj_ivar_get, 1);
|
|
rb_define_method(rb_mKernel, "instance_variable_set", rb_obj_ivar_set, 2);
|
|
rb_define_method(rb_mKernel, "instance_variable_defined?", rb_obj_ivar_defined, 1);
|
|
rb_define_method(rb_mKernel, "remove_instance_variable",
|
|
rb_obj_remove_instance_variable, 1); /* in variable.c */
|
|
|
|
rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1);
|
|
rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1);
|
|
rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1);
|
|
rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0);
|
|
|
|
rb_define_global_function("sprintf", rb_f_sprintf, -1); /* in sprintf.c */
|
|
rb_define_global_function("format", rb_f_sprintf, -1); /* in sprintf.c */
|
|
|
|
rb_define_global_function("Integer", rb_f_integer, -1);
|
|
rb_define_global_function("Float", rb_f_float, 1);
|
|
|
|
rb_define_global_function("String", rb_f_string, 1);
|
|
rb_define_global_function("Array", rb_f_array, 1);
|
|
rb_define_global_function("Hash", rb_f_hash, 1);
|
|
|
|
rb_cNilClass = rb_define_class("NilClass", rb_cObject);
|
|
rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0);
|
|
rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0);
|
|
rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0);
|
|
rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0);
|
|
rb_define_method(rb_cNilClass, "to_h", nil_to_h, 0);
|
|
rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0);
|
|
rb_define_method(rb_cNilClass, "&", false_and, 1);
|
|
rb_define_method(rb_cNilClass, "|", false_or, 1);
|
|
rb_define_method(rb_cNilClass, "^", false_xor, 1);
|
|
rb_define_method(rb_cNilClass, "===", rb_equal, 1);
|
|
|
|
rb_define_method(rb_cNilClass, "nil?", rb_true, 0);
|
|
rb_undef_alloc_func(rb_cNilClass);
|
|
rb_undef_method(CLASS_OF(rb_cNilClass), "new");
|
|
/*
|
|
* An obsolete alias of +nil+
|
|
*/
|
|
rb_define_global_const("NIL", Qnil);
|
|
rb_deprecate_constant(rb_cObject, "NIL");
|
|
|
|
rb_define_method(rb_cModule, "freeze", rb_mod_freeze, 0);
|
|
rb_define_method(rb_cModule, "===", rb_mod_eqq, 1);
|
|
rb_define_method(rb_cModule, "==", rb_obj_equal, 1);
|
|
rb_define_method(rb_cModule, "<=>", rb_mod_cmp, 1);
|
|
rb_define_method(rb_cModule, "<", rb_mod_lt, 1);
|
|
rb_define_method(rb_cModule, "<=", rb_class_inherited_p, 1);
|
|
rb_define_method(rb_cModule, ">", rb_mod_gt, 1);
|
|
rb_define_method(rb_cModule, ">=", rb_mod_ge, 1);
|
|
rb_define_method(rb_cModule, "initialize_copy", rb_mod_init_copy, 1); /* in class.c */
|
|
rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0);
|
|
rb_define_alias(rb_cModule, "inspect", "to_s");
|
|
rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
|
|
rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */
|
|
rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */
|
|
rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */
|
|
|
|
rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1);
|
|
rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1);
|
|
rb_define_private_method(rb_cModule, "attr_writer", rb_mod_attr_writer, -1);
|
|
rb_define_private_method(rb_cModule, "attr_accessor", rb_mod_attr_accessor, -1);
|
|
|
|
rb_define_alloc_func(rb_cModule, rb_module_s_alloc);
|
|
rb_define_method(rb_cModule, "initialize", rb_mod_initialize, 0);
|
|
rb_define_method(rb_cModule, "initialize_clone", rb_mod_initialize_clone, 1);
|
|
rb_define_method(rb_cModule, "instance_methods", rb_class_instance_methods, -1); /* in class.c */
|
|
rb_define_method(rb_cModule, "public_instance_methods",
|
|
rb_class_public_instance_methods, -1); /* in class.c */
|
|
rb_define_method(rb_cModule, "protected_instance_methods",
|
|
rb_class_protected_instance_methods, -1); /* in class.c */
|
|
rb_define_method(rb_cModule, "private_instance_methods",
|
|
rb_class_private_instance_methods, -1); /* in class.c */
|
|
|
|
rb_define_method(rb_cModule, "constants", rb_mod_constants, -1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "const_get", rb_mod_const_get, -1);
|
|
rb_define_method(rb_cModule, "const_set", rb_mod_const_set, 2);
|
|
rb_define_method(rb_cModule, "const_defined?", rb_mod_const_defined, -1);
|
|
rb_define_private_method(rb_cModule, "remove_const",
|
|
rb_mod_remove_const, 1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "const_missing",
|
|
rb_mod_const_missing, 1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "class_variables",
|
|
rb_mod_class_variables, -1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "remove_class_variable",
|
|
rb_mod_remove_cvar, 1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "class_variable_get", rb_mod_cvar_get, 1);
|
|
rb_define_method(rb_cModule, "class_variable_set", rb_mod_cvar_set, 2);
|
|
rb_define_method(rb_cModule, "class_variable_defined?", rb_mod_cvar_defined, 1);
|
|
rb_define_method(rb_cModule, "public_constant", rb_mod_public_constant, -1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "private_constant", rb_mod_private_constant, -1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "deprecate_constant", rb_mod_deprecate_constant, -1); /* in variable.c */
|
|
rb_define_method(rb_cModule, "singleton_class?", rb_mod_singleton_p, 0);
|
|
|
|
rb_define_method(rb_cClass, "allocate", rb_class_alloc, 0);
|
|
rb_define_method(rb_cClass, "new", rb_class_s_new, -1);
|
|
rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1);
|
|
rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
|
|
rb_define_alloc_func(rb_cClass, rb_class_s_alloc);
|
|
rb_undef_method(rb_cClass, "extend_object");
|
|
rb_undef_method(rb_cClass, "append_features");
|
|
rb_undef_method(rb_cClass, "prepend_features");
|
|
|
|
/*
|
|
* Document-class: Data
|
|
*
|
|
* This is a recommended base class for C extensions using Data_Make_Struct
|
|
* or Data_Wrap_Struct, see doc/extension.rdoc for details.
|
|
*/
|
|
rb_cData = rb_define_class("Data", rb_cObject);
|
|
rb_undef_alloc_func(rb_cData);
|
|
|
|
rb_cTrueClass = rb_define_class("TrueClass", rb_cObject);
|
|
rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0);
|
|
rb_define_alias(rb_cTrueClass, "inspect", "to_s");
|
|
rb_define_method(rb_cTrueClass, "&", true_and, 1);
|
|
rb_define_method(rb_cTrueClass, "|", true_or, 1);
|
|
rb_define_method(rb_cTrueClass, "^", true_xor, 1);
|
|
rb_define_method(rb_cTrueClass, "===", rb_equal, 1);
|
|
rb_undef_alloc_func(rb_cTrueClass);
|
|
rb_undef_method(CLASS_OF(rb_cTrueClass), "new");
|
|
/*
|
|
* An obsolete alias of +true+
|
|
*/
|
|
rb_define_global_const("TRUE", Qtrue);
|
|
rb_deprecate_constant(rb_cObject, "TRUE");
|
|
|
|
rb_cFalseClass = rb_define_class("FalseClass", rb_cObject);
|
|
rb_define_method(rb_cFalseClass, "to_s", false_to_s, 0);
|
|
rb_define_alias(rb_cFalseClass, "inspect", "to_s");
|
|
rb_define_method(rb_cFalseClass, "&", false_and, 1);
|
|
rb_define_method(rb_cFalseClass, "|", false_or, 1);
|
|
rb_define_method(rb_cFalseClass, "^", false_xor, 1);
|
|
rb_define_method(rb_cFalseClass, "===", rb_equal, 1);
|
|
rb_undef_alloc_func(rb_cFalseClass);
|
|
rb_undef_method(CLASS_OF(rb_cFalseClass), "new");
|
|
/*
|
|
* An obsolete alias of +false+
|
|
*/
|
|
rb_define_global_const("FALSE", Qfalse);
|
|
rb_deprecate_constant(rb_cObject, "FALSE");
|
|
}
|
|
|
|
void
|
|
Init_Object(void)
|
|
{
|
|
id_to_f = rb_intern_const("to_f");
|
|
id_dig = rb_intern_const("dig");
|
|
InitVM(Object);
|
|
}
|