класс BasicObject
BasicObject — родительский класс всех классов в Ruby. В частности, BasicObject является родительским классом класса Object, который, в свою очередь, является родительским классом по умолчанию для каждого класса Ruby:
class Foo; end Foo.superclass # => Object Object.superclass # => BasicObject
BasicObject — единственный класс, у которого нет родительского класса:
BasicObject.superclass # => nil
Класс BasicObject можно использовать для создания иерархии объектов (например, класс Delegator), независимой от иерархии объектов Ruby. Такие объекты:
-
Не имеют «загрязнения» пространства имён множеством методов, предоставляемых классом
Objectи включённым в него модулемKernel. -
Не имеют определений распространённых классов, поэтому ссылки на такие классы должны быть полностью квалифицированы (
::String, а неString).
Для предоставления полезных частей стандартной библиотеки в подклассах 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становится неопределённым одиночный метод.
Открытые методы класса
#define rb_obj_initialize rb_obj_dummy0
Возвращает новый экземпляр BasicObject.
Открытые методы экземпляра
VALUE
rb_obj_not(VALUE obj)
{
return RBOOL(!RTEST(obj));
} Логическое отрицание.
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 метод == возвращает true, только если obj и other являются одним и тем же объектом. Обычно этот метод переопределяется в классах-потомках, чтобы задать смысл, специфичный для класса.
В отличие от ==, метод equal? никогда не следует переопределять в подклассах, поскольку он используется для определения идентичности объектов (то есть a.equal?(b) тогда и только тогда, когда a является тем же объектом, что и b):
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
Метод eql? возвращает true, если obj и other указывают на один и тот же ключ хэша. Этот метод используется классом 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, object_id);
} Возвращает целочисленный идентификатор для obj.
При каждом вызове object_id для данного объекта будет возвращаться одно и то же число, и ни у каких двух существующих объектов не будет одинакового идентификатора.
Примечание: некоторые объекты встроенных классов повторно используются для оптимизации. Это относится к непосредственным значениям и замороженным строковым литералам.
BasicObject реализует __id__, а Kernel реализует object_id.
Непосредственные значения передаются не по ссылке, а по значению: nil, true, false, Fixnum, символы и некоторые числа с плавающей точкой.
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. Метод __send__ безопаснее, чем send, если у obj есть метод с таким же именем, как у Socket. См. также public_send.
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
Равенство — на уровне Object метод == возвращает true, только если obj и other являются одним и тем же объектом. Обычно этот метод переопределяется в классах-потомках, чтобы задать смысл, специфичный для класса.
В отличие от ==, метод equal? никогда не следует переопределять в подклассах, поскольку он используется для определения идентичности объектов (то есть a.equal?(b) тогда и только тогда, когда a является тем же объектом, что и b):
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
Метод eql? возвращает true, если obj и other указывают на один и тот же ключ хэша. Этот метод используется классом 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);
} Вычисляет строку с исходным кодом Ruby или заданный блок в контексте получателя (obj). Чтобы установить контекст, во время выполнения кода переменной 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);
} Вызывается Ruby, когда obj получает сообщение, которое не может обработать. 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
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.