Spec-Zone.ru › Ruby 3.3

класс 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, передавая заданные аргументы.

Методы публичного класса

new Показать исходный код
#define rb_obj_initialize rb_obj_dummy0

Возвращает новый BasicObject.

Методы публичного экземпляра

!obj → true или false Показать исходный код
VALUE
rb_obj_not(VALUE obj)
{
    return RBOOL(!RTEST(obj));
}

Логическое отрицание.

obj != other → true или false Показать исходный код
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.

obj == other → true или false Показать исходный код
eql?(other) → 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?, должен также соответствующим образом переопределить хэш.

Для объектов класса Object, eql? является синонимом ==. Подклассы обычно продолжают эту традицию, используя алиас eql? для переопределенного метода ==, но есть исключения. Например, типы Numeric выполняют преобразование типов через ==, но не через eql?, поэтому:

1 == 1.0     #=> true
1.eql? 1.0   #=> false
Также алиас: equal?
__id__ → целое число Показать исходный код
object_id → целое число
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
send(symbol [, args...]) → obj Показать исходный код
__send__(symbol [, args...]) → obj
send(string [, args...]) → obj
__send__(string [, args...]) → obj
VALUE
rb_f_send(int argc, VALUE *argv, VALUE recv)
{
    return send_internal_kw(argc, argv, recv, CALL_FCALL);
}

Вызывает метод, идентифицированный символом, передавая ему любые указанные аргументы. Когда метод идентифицируется строкой, строка преобразуется в символ.

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"
equal?(other) → true или false
eql?(other) → true или false

Равенство — На уровне 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
Алиас для: ==
instance_eval(string [, filename [, lineno]] ) → obj Показать исходный код
instance_eval {|obj| block } → obj
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
instance_exec(arg...) {|var...| block } → obj Показать исходный код
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

Методы частного экземпляра

method_missing(symbol [, *args] ) → result Показать исходный код
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
singleton_method_added(symbol) Показать исходный код
#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
singleton_method_removed(symbol) Показать исходный код
#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
singleton_method_undefined(symbol) Показать исходный код
#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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API