class BasicObject
BasicObject 是 Ruby 中所有类的父类。特别是,BasicObject 是类 Object 的父类,而 Object 本身又是每个 Ruby 类的默认父类。
class Foo; end Foo.superclass # => Object Object.superclass # => BasicObject
BasicObject 是唯一没有父类的类。
BasicObject.superclass # => nil
类 BasicObject 可用于创建独立于 Ruby 对象层次结构的对象层次结构(例如,类 Delegator)。这些对象
可以使用各种策略在 BasicObject 的子类中提供标准库的有用部分。
-
直接子类可以
include Kernel,这将定义诸如puts、exit等方法。 -
可以创建并包含一个自定义的类似 Kernel 的模块。
-
可以通过
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) end end
这里有什么¶ ↑
以下是为 BasicObject 定义的方法
-
::new:返回一个新的 BasicObject 实例。 -
!:返回self的布尔非:true或false。 -
!=:返回self和给定对象是否不相等。 -
==:返回self和给定对象是否等效。 -
__id__:返回self的整数对象标识符。 -
__send__:调用由给定符号标识的方法。 -
equal?:返回self和给定对象是否是同一个对象。 -
instance_eval:在self的上下文中计算给定的字符串或代码块。 -
instance_exec:在self的上下文中执行给定的代码块,传递给定的参数。 -
method_missing:当使用未定义的方法调用self时调用。 -
singleton_method_added:当向self添加单例方法时调用。 -
singleton_method_removed:当从self中删除单例方法时调用。 -
singleton_method_undefined:当在self中取消定义单例方法时调用。
公共类方法
公共实例方法
源代码
VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
return rb_obj_not(result);
}
如果两个对象不相等,则返回 true,否则返回 false。
源代码
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
return RBOOL(obj1 == obj2);
}
相等性 — 在 Object 级别,== 仅当 obj 和 other 是同一个对象时才返回 true。通常,此方法在后代类中被覆盖以提供特定于类的含义。
与 == 不同,equal? 方法永远不应被子类覆盖,因为它用于确定对象标识(即,a.equal?(b) 当且仅当 a 与 b 是同一个对象时)。
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
如果 obj 和 other 引用同一个哈希键,则 eql? 方法返回 true。 Hash 使用此方法来测试成员是否相等。对于任何一对 eql? 返回 true 的对象,两个对象的哈希值必须相等。因此,任何覆盖 eql? 的子类也应适当地覆盖 hash。
对于 Object 类的对象,eql? 与 == 同义。子类通常通过将 eql? 别名为它们覆盖的 == 方法来延续这一传统,但也存在例外。例如,Numeric 类型在 == 中执行类型转换,但在 eql? 中不执行类型转换,因此
1 == 1.0 #=> true 1.eql? 1.0 #=> false
源代码
VALUE
rb_obj_id(VALUE obj)
{
/* If obj is an immediate, the object ID is obj directly converted to a Numeric.
* Otherwise, the object ID is a Numeric that is a non-zero multiple of
* (RUBY_IMMEDIATE_MASK + 1) which guarantees that it does not collide with
* any immediates. */
return rb_find_object_id(rb_gc_get_objspace(), obj, rb_gc_impl_object_id);
}
返回 obj 的整数标识符。
在对给定对象的所有 object_id 调用中,将返回相同的数字,并且没有两个活动对象会共享一个 ID。
注意:为了优化,内置类的某些对象被重用。对于立即值和冻结的字符串字面量,情况就是如此。
BasicObject 实现 __id__,Kernel 实现 object_id。
立即值不是通过引用传递的,而是通过值传递的:nil、true、false、Fixnums、Symbols 和一些 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
源代码
VALUE
rb_f_send(int argc, VALUE *argv, VALUE recv)
{
return send_internal_kw(argc, argv, recv, CALL_FCALL);
}
调用由 symbol 标识的方法,传递任何指定的参数。当方法由字符串标识时,该字符串将转换为符号。
BasicObject 实现 __send__,Kernel 实现 send。当 obj 具有与 Socket 相同的方法名称时,__send__ 比 send 更安全。另请参阅 public_send。
class Klass def hello(*args) "Hello " + args.join(' ') end end k = Klass.new k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
相等性 — 在 Object 级别,== 仅当 obj 和 other 是同一个对象时才返回 true。通常,此方法在后代类中被覆盖以提供特定于类的含义。
与 == 不同,equal? 方法永远不应被子类覆盖,因为它用于确定对象标识(即,a.equal?(b) 当且仅当 a 与 b 是同一个对象时)。
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
如果 obj 和 other 引用同一个哈希键,则 eql? 方法返回 true。 Hash 使用此方法来测试成员是否相等。对于任何一对 eql? 返回 true 的对象,两个对象的哈希值必须相等。因此,任何覆盖 eql? 的子类也应适当地覆盖 hash。
对于 Object 类的对象,eql? 与 == 同义。子类通常通过将 eql? 别名为它们覆盖的 == 方法来延续这一传统,但也存在例外。例如,Numeric 类型在 == 中执行类型转换,但在 eql? 中不执行类型转换,因此
1 == 1.0 #=> true 1.eql? 1.0 #=> false
源代码
static VALUE
rb_obj_instance_eval_internal(int argc, const VALUE *argv, VALUE self)
{
return specific_eval(argc, argv, self, TRUE, RB_PASS_CALLED_KEYWORDS);
}
在接收器 (obj) 的上下文中计算包含 Ruby 源代码的字符串或给定的代码块。为了设置上下文,在代码执行时,变量 self 设置为 obj,从而使代码能够访问 obj 的实例变量和私有方法。
当 instance_eval 被赋予一个代码块时,obj 也作为代码块的唯一参数传递。
当 instance_eval 被赋予一个 String 时,可选的第二个和第三个参数会提供文件名和起始行号,这些参数在报告编译错误时使用。
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
源代码
static VALUE
rb_obj_instance_exec_internal(int argc, const VALUE *argv, VALUE self)
{
return yield_under(self, TRUE, argc, argv, RB_PASS_CALLED_KEYWORDS);
}
在接收器 (obj) 的上下文中执行给定的代码块。为了设置上下文,在代码执行时,变量 self 设置为 obj,从而使代码能够访问 obj 的实例变量。参数作为代码块参数传递。
class KlassWithSecret def initialize @secret = 99 end end k = KlassWithSecret.new k.instance_exec(5) {|x| @secret+x } #=> 104
私有实例方法
源代码
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);
}
当 obj 被发送一个无法处理的消息时,由 Ruby 调用。symbol 是调用的方法的符号,args 是传递给它的任何参数。默认情况下,当调用此方法时,解释器会引发错误。但是,可以覆盖该方法以提供更动态的行为。如果确定不应处理特定方法,则应调用 super,以便祖先可以获取丢失的方法。下面的示例创建了一个类 Roman,该类使用由罗马数字组成的名称响应方法,返回相应的整数值。
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
源代码
#define rb_obj_singleton_method_added rb_obj_dummy1
每当向接收器添加单例方法时,都将作为回调调用。
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
产生
Adding singleton_method_added Adding one Adding three
源代码
#define rb_obj_singleton_method_removed rb_obj_dummy1
每当从接收器中删除单例方法时,都将作为回调调用。
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
产生
Removing three Removing one
源代码
#define rb_obj_singleton_method_undefined rb_obj_dummy1
每当在接收器中取消定义单例方法时,都将作为回调调用。
module Chatty def Chatty.singleton_method_undefined(id) puts "Undefining #{id.id2name}" end def Chatty.one() end class << self undef_method(:one) end end
产生
Undefining one