класс 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)
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
Доступ к классам и модулям из стандартной библиотеки Ruby можно получить в подклассе BasicObject путём ссылки на желаемую константу из корневого уровня, например, ::File или ::Enumerator. Как и method_missing, можно использовать const_missing для делегирования поиска констант в Object:
class MyObjectSystem < BasicObject
def self.const_missing(name)
::Object.const_get(name)
end
end
Что здесь
Вот методы, определённые для BasicObject:
-
-
::new -
Возвращает новый экземпляр BasicObject.
-
-
- !
-
Возвращает логическое отрицание
self:trueилиfalse.
-
- !=
-
Возвращает, равны ли
selfи заданный объект, или нет.
-
- ==
-
Возвращает, эквивалентны ли
selfи заданный объект.
-
- __id__
-
Возвращает целочисленный идентификатор объекта для
self.
-
- __send__
-
Вызывает метод, идентифицированный заданным символом.
-
-
equal? -
Возвращает, являются ли
selfи заданный объект одним и тем же объектом.
-
-
-
instance_eval -
Вычисляет заданную строку или блок в контексте
self.
-
-
-
instance_exec -
Выполняет заданный блок в контексте
self, передавая заданные аргументы.
-
-
-
method_missing -
Метод
Methodвызывается при вызове неопределенного метода дляself.
-
-
-
singleton_method_added -
Метод
Methodвызывается при добавлении синглтон-метода кself.
-
-
-
singleton_method_removed -
Метод
Methodвызывается при удалении синглтон-метода изself.
-
-
-
singleton_method_undefined -
Метод
Methodвызывается при неопределении синглтон-метода вself.
-
Методы публичного класса
#define rb_obj_initialize rb_obj_dummy0
Возвращает новый BasicObject.
Методы публичного экземпляра
MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
return RTEST(obj) ? Qfalse : Qtrue;
} Логическое отрицание.
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;
} Возвращает true, если два объекта не равны, в противном случае — false.
MJIT_FUNC_EXPORTED 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?, должен также корректно переопределить хэш.
Для объектов класса 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
*/
return rb_find_object_id(obj, cached_object_id);
} Возвращает целочисленное идентификатор для obj.
То же число будет возвращено при всех вызовах object_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. __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?, должен также корректно переопределить хэш.
Для объектов класса 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 получает строку, необязательные второй и третий параметры предоставляют имя файла и начальный номер строки, которые используются при отображении ошибок компиляции.
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 во время выполнения кода, предоставляя коду доступ к переменным экземпляра. Аргументы передаются в качестве параметров блока.
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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.