Class: BasicObject
Overview
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 include Kernel
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)
return 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 ::File
or ::Enumerator
. 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
Direct Known Subclasses
Instance Method Summary collapse
-
#! ⇒ Boolean
Boolean negate.
-
#!=(other) ⇒ Boolean
Returns true if two objects are not-equal, otherwise false.
-
#==(obj2) ⇒ Object
Equality — At the Object level, #== returns
true
only ifobj
andother
are the same object. -
#__id__ ⇒ Object
call-seq: obj.__id__ -> integer obj.object_id -> integer.
-
#__send__(*args) ⇒ Object
Invokes the method identified by symbol, passing it any arguments specified.
-
#equal?(obj2) ⇒ Object
Equality — At the Object level, #== returns
true
only ifobj
andother
are the same object. -
#initialize ⇒ Object
constructor
private
call-seq: BasicObject.new.
-
#instance_eval(*args) ⇒ Object
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj).
-
#instance_exec(arg...) {|var...| ... } ⇒ Object
Executes the given block within the context of the receiver (obj).
-
#method_missing(symbol[, *args]) ⇒ Object
private
Invoked by Ruby when obj is sent a message it cannot handle.
-
#singleton_method_added(_y) ⇒ Object
private
call-seq: singleton_method_added(symbol).
-
#singleton_method_removed(_y) ⇒ Object
private
call-seq: singleton_method_removed(symbol).
-
#singleton_method_undefined(_y) ⇒ Object
private
call-seq: singleton_method_undefined(symbol).
Constructor Details
#initialize ⇒ Object (private)
1140 1141 1142 1143 1144 |
# File 'object.c', line 1140
static VALUE
rb_obj_dummy0(VALUE _)
{
return rb_obj_dummy();
}
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol[, *args]) ⇒ Object (private)
Invoked by Ruby when obj is sent a message it cannot handle. symbol is the symbol for the method called, and args are any arguments that were passed to it. By default, the interpreter raises an error when this method is called. However, it is possible to override the method to provide more dynamic behavior. If it is decided that a particular method should not be handled, then super should be called, so that ancestors can pick up the missing method. The example below creates a class Roman
, which responds to methods with names consisting of roman numerals, returning the corresponding integer values.
class Roman
def roman_to_int(str)
# ...
end
def method_missing(symbol, *args)
str = symbol.id2name
begin
roman_to_int(str)
rescue
super(symbol, *args)
end
end
end
r = Roman.new
r.iv #=> 4
r.xxiii #=> 23
r.mm #=> 2000
r.foo #=> NoMethodError
877 878 879 880 881 882 883 |
# File 'vm_eval.c', line 877
static VALUE
rb_method_missing(int argc, const VALUE *argv, VALUE obj)
{
rb_execution_context_t *ec = GET_EC();
raise_method_missing(ec, argc, argv, obj, ec->method_missing_reason);
UNREACHABLE_RETURN(Qnil);
}
|
Instance Method Details
#! ⇒ Boolean
Boolean negate.
253 254 255 256 257 |
# File 'object.c', line 253
MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
return RTEST(obj) ? Qfalse : Qtrue;
}
|
#!=(other) ⇒ Boolean
Returns true if two objects are not-equal, otherwise false.
269 270 271 272 273 274 |
# File 'object.c', line 269
MJIT_FUNC_EXPORTED VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
return RTEST(result) ? Qfalse : Qtrue;
}
|
#==(other) ⇒ Boolean #equal?(other) ⇒ Boolean #eql?(other) ⇒ Boolean
Equality — At the Object level, #== returns true
only if obj
and other
are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
Unlike #==, the #equal? method should never be overridden by subclasses as it is used to determine object identity (that is, a.equal?(b)
if and only if a
is the same object as b
):
obj = "a"
other = obj.dup
obj == other #=> true
obj.equal? other #=> false
obj.equal? obj #=> true
The #eql? method returns true
if obj
and other
refer to the same hash key. This is used by Hash to test members for equality. For any pair of objects where #eql? returns true
, the #hash value of both objects must be equal. So any subclass that overrides #eql? should also override #hash appropriately.
For objects of class Object, #eql? is synonymous with #==. Subclasses normally continue this tradition by aliasing #eql? to their overridden #== method, but there are exceptions. Numeric types, for example, perform type conversion across #==, but not across #eql?, so:
1 == 1.0 #=> true
1.eql? 1.0 #=> false
234 235 236 237 238 239 |
# File 'object.c', line 234
MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
if (obj1 == obj2) return Qtrue;
return Qfalse;
}
|
#__id__ ⇒ Object
call-seq:
obj.__id__ -> integer
obj.object_id -> integer
Returns an integer identifier for obj
.
The same number will be returned on all calls to object_id
for a given object, and no two active objects will share an id.
Note: that some objects of builtin classes are reused for optimization. This is the case for immediate values and frozen string literals.
BasicObject implements __id__
, Kernel implements object_id
.
Immediate values are not passed by reference but are passed by value: nil
, true
, false
, Fixnums, Symbols, and some Floats.
Object.new.object_id == Object.new.object_id # => false
(21 * 2).object_id == (21 * 2).object_id # => true
"hello".object_id == "hello".object_id # => false
"hi".freeze.object_id == "hi".freeze.object_id # => true
4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 |
# File 'gc.c', line 4122
VALUE
rb_obj_id(VALUE obj)
{
/*
* 32-bit VALUE space
* MSB ------------------------ LSB
* false 00000000000000000000000000000000
* true 00000000000000000000000000000010
* nil 00000000000000000000000000000100
* undef 00000000000000000000000000000110
* symbol ssssssssssssssssssssssss00001110
* object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE))
* fixnum fffffffffffffffffffffffffffffff1
*
* object_id space
* LSB
* false 00000000000000000000000000000000
* true 00000000000000000000000000000010
* nil 00000000000000000000000000000100
* undef 00000000000000000000000000000110
* symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4)
* object oooooooooooooooooooooooooooooo0 o...o % A = 0
* fixnum fffffffffffffffffffffffffffffff1 bignum if required
*
* where A = sizeof(RVALUE)/4
*
* sizeof(RVALUE) is
* 20 if 32-bit, double is 4-byte aligned
* 24 if 32-bit, double is 8-byte aligned
* 40 if 64-bit
*/
return rb_find_object_id(obj, cached_object_id);
}
|
#send(symbol[, args...]) ⇒ Object #__send__(symbol[, args...]) ⇒ Object #send(string[, args...]) ⇒ Object #__send__(string[, args...]) ⇒ Object
Invokes the method identified by symbol, passing it any
arguments specified.
When the method is identified by a string, the string is converted
to a symbol.
BasicObject implements +__send__+, Kernel implements +send+.
<code>__send__</code> is safer than +send+
when _obj_ has the same method name like <code>Socket</code>.
See also <code>public_send</code>.
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
1294 1295 1296 1297 1298 |
# File 'vm_eval.c', line 1294
VALUE
rb_f_send(int argc, VALUE *argv, VALUE recv)
{
return send_internal_kw(argc, argv, recv, CALL_FCALL);
}
|
#==(other) ⇒ Boolean #equal?(other) ⇒ Boolean #eql?(other) ⇒ Boolean
Equality — At the Object level, #== returns true
only if obj
and other
are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
Unlike #==, the #equal? method should never be overridden by subclasses as it is used to determine object identity (that is, a.equal?(b)
if and only if a
is the same object as b
):
obj = "a"
other = obj.dup
obj == other #=> true
obj.equal? other #=> false
obj.equal? obj #=> true
The #eql? method returns true
if obj
and other
refer to the same hash key. This is used by Hash to test members for equality. For any pair of objects where #eql? returns true
, the #hash value of both objects must be equal. So any subclass that overrides #eql? should also override #hash appropriately.
For objects of class Object, #eql? is synonymous with #==. Subclasses normally continue this tradition by aliasing #eql? to their overridden #== method, but there are exceptions. Numeric types, for example, perform type conversion across #==, but not across #eql?, so:
1 == 1.0 #=> true
1.eql? 1.0 #=> false
234 235 236 237 238 239 |
# File 'object.c', line 234
MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
if (obj1 == obj2) return Qtrue;
return Qfalse;
}
|
#instance_eval(string[, filename [, lineno]]) ⇒ Object #instance_eval {|obj| ... } ⇒ Object
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self
is set to obj while the code is executing, giving the code access to obj’s instance variables and private methods.
When instance_eval
is given a block, obj is also passed in as the block’s only argument.
When instance_eval
is given a String
, the optional second and third parameters supply a filename and starting line number that are used when reporting compilation errors.
class KlassWithSecret
def initialize
@secret = 99
end
private
def the_secret
"Ssssh! The secret is #{@secret}."
end
end
k = KlassWithSecret.new
k.instance_eval { @secret } #=> 99
k.instance_eval { the_secret } #=> "Ssssh! The secret is 99."
k.instance_eval {|obj| obj == self } #=> true
2084 2085 2086 2087 2088 2089 |
# File 'vm_eval.c', line 2084
static VALUE
rb_obj_instance_eval_internal(int argc, const VALUE *argv, VALUE self)
{
VALUE klass = singleton_class_for_eval(self);
return specific_eval(argc, argv, klass, self, RB_PASS_CALLED_KEYWORDS);
}
|
#instance_exec(arg...) {|var...| ... } ⇒ Object
Executes the given block within the context of the receiver (obj). In order to set the context, the variable self
is set to obj while the code is executing, giving the code access to obj’s instance variables. Arguments are passed as block parameters.
class KlassWithSecret
def initialize
@secret = 99
end
end
k = KlassWithSecret.new
k.instance_exec(5) {|x| @secret+x } #=> 104
2116 2117 2118 2119 2120 2121 |
# File 'vm_eval.c', line 2116
static VALUE
rb_obj_instance_exec_internal(int argc, const VALUE *argv, VALUE self)
{
VALUE klass = singleton_class_for_eval(self);
return yield_under(klass, self, argc, argv, RB_PASS_CALLED_KEYWORDS);
}
|
#singleton_method_added(_y) ⇒ Object (private)
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
1146 1147 1148 1149 1150 |
# File 'object.c', line 1146
static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
return rb_obj_dummy();
}
|
#singleton_method_removed(_y) ⇒ Object (private)
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
1146 1147 1148 1149 1150 |
# File 'object.c', line 1146
static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
return rb_obj_dummy();
}
|
#singleton_method_undefined(_y) ⇒ Object (private)
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
1146 1147 1148 1149 1150 |
# File 'object.c', line 1146
static VALUE
rb_obj_dummy1(VALUE _x, VALUE _y)
{
return rb_obj_dummy();
}
|