класс BasicObject
BasicObject — это базовый класс всех классов в Ruby. Это явный пустой класс.
BasicObject может использоваться для создания иерархий объектов, независимых от иерархии объектов Ruby, для прокси-объектов, таких как класс Delegator, или в других случаях, где необходимо избежать загрязнения пространства имён методами и классами Ruby.
Чтобы избежать загрязнения BasicObject для других пользователей, следует создавать соответствующий подкласс BasicObject, а не изменять непосредственно BasicObject:
class MyObjectSystem < BasicObject end
BasicObject не включает Kernel (для методов, таких как puts) и BasicObject находится вне пространства имён стандартной библиотеки, поэтому общие классы не будут найдены без использования полного пути к классу.
Для предоставления полезных частей стандартной библиотеки подклассам BasicObject можно использовать различные стратегии. Подкласс может include
Kernel для получения puts, exit, и т. д. Можно создать и включить модуль, похожий на Kernel, или использовать делегирование через 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
Доступ к классам и модулям из стандартной библиотеки Ruby в подклассе BasicObject можно получить, обращаясь к нужному константе из корня, например, ::File или ::Enumerator. Как и method_missing, const_missing можно использовать для делегирования поиска констант Object:
class MyObjectSystem < BasicObject
def self.const_missing(name)
::Object.const_get(name)
end
end
Методы публичного класса
static VALUE
rb_obj_dummy(void)
{
return Qnil;
} Не задокументировано
Методы публичного экземпляра
VALUE
rb_obj_not(VALUE obj)
{
return RTEST(obj) ? Qfalse : Qtrue;
} Логическое отрицание.
VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
return RTEST(result) ? Qfalse : Qtrue;
} Возвращает true, если два объекта не равны, иначе false.
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
if (obj1 == obj2) return Qtrue;
return Qfalse;
} Равенство — На уровне 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 для проверки членов на равенство. Для объектов класса Object, eql? является синонимом ==. Подклассы обычно продолжают эту традицию, алиасируя eql? до своего переопределённого метода ==, но есть исключения. Например, типы Numeric выполняют преобразование типов через ==, но не через eql?, поэтому:
1 == 1.0 #=> true 1.eql? 1.0 #=> false
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
*/
if (STATIC_SYM_P(obj)) {
return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
}
else if (FLONUM_P(obj)) {
#if SIZEOF_LONG == SIZEOF_VOIDP
return LONG2NUM((SIGNED_VALUE)obj);
#else
return LL2NUM((SIGNED_VALUE)obj);
#endif
}
else if (SPECIAL_CONST_P(obj)) {
return LONG2NUM((SIGNED_VALUE)obj);
}
return nonspecial_obj_id(obj);
} Возвращает целочисленный идентификатор для obj.
Одно и то же число будет возвращено при всех вызовах 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(argc, argv, recv, CALL_FCALL);
} Вызывает метод, идентифицированный символом, передавая ему любые указанные аргументы. Вы можете использовать __send__, если имя send конфликтует с существующим методом в obj. Когда метод идентифицируется строкой, строка преобразуется в символ.
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
if (obj1 == obj2) return Qtrue;
return Qfalse;
} Равенство — На уровне 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 для проверки членов на равенство. Для объектов класса Object, eql? является синонимом ==. Подклассы обычно продолжают эту традицию, алиасируя eql? до своего переопределённого метода ==, но есть исключения. Например, типы Numeric выполняют преобразование типов через ==, но не через eql?, поэтому:
1 == 1.0 #=> true 1.eql? 1.0 #=> false
VALUE
rb_obj_instance_eval(int argc, const VALUE *argv, VALUE self)
{
VALUE klass = singleton_class_for_eval(self);
return specific_eval(argc, argv, klass, self);
} Вычисляет строку, содержащую исходный код Ruby, или заданный блок, в контексте получателя (obj). Для установки контекста переменная self устанавливается в obj во время выполнения кода, давая коду доступ к переменным экземпляра и частным методам obj.
Когда instance_eval получает блок, obj также передаётся в качестве единственного аргумента блока.
Когда instance_eval получает строку, необязательные второй и третий параметры предоставляют имя файла и начальный номер строки, которые используются при сообщении об ошибках компиляции.
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
VALUE
rb_obj_instance_exec(int argc, const VALUE *argv, VALUE self)
{
VALUE klass = singleton_class_for_eval(self);
return yield_under(klass, self, argc, argv);
} Выполняет заданный блок в контексте получателя (obj). Для установки контекста переменная self устанавливается в 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;
} Вызывается Ruby, когда obj отправляет сообщение, которое он не может обработать. символ — символ вызываемого метода, а args — любые аргументы, которые были переданы ему. По умолчанию интерпретатор выводит ошибку при вызове этого метода. Однако можно переопределить метод для обеспечения более динамического поведения. Если принято решение, что определенный метод не должен обрабатываться, то должен быть вызван super, чтобы предки могли получить пропущенный метод. Пример ниже создаёт класс Roman, который реагирует на методы с именами, состоящими из римских цифр, возвращая соответствующие целочисленные значения.
class Roman
def roman_to_int(str)
# ...
end
def method_missing(methId)
str = methId.id2name
roman_to_int(str)
end
end
r = Roman.new
r.iv #=> 4
r.xxiii #=> 23
r.mm #=> 2000
static VALUE
rb_obj_dummy(void)
{
return Qnil;
} Вызывается в качестве обратного вызова всякий раз, когда к получателю добавляется метод одиночки.
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
static VALUE
rb_obj_dummy(void)
{
return Qnil;
} Вызывается в качестве обратного вызова всякий раз, когда метод одиночки удаляется из получателя.
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
static VALUE
rb_obj_dummy(void)
{
return Qnil;
} Вызывается в качестве обратного вызова всякий раз, когда метод одиночки не определен в получателе.
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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.