Spec-Zone.ru › Ruby 3.4

класс 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.

Публичные методы класса

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

Возвращает новый экземпляр BasicObject.

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

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

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

obj != other → true or 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 or false Показать исходный код
eql?(other) → true or 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
Также имеет псевдоним: equal?
__id__ → integer Показать исходный код
object_id → integer
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 возвращают одно и то же число, и ни у каких двух активных объектов идентификаторы не совпадают.

Примечание: некоторые объекты встроенных классов повторно используются для оптимизации. Это относится к непосредственным значениям и замороженным строковым литералам.

BasicObject реализует __id__, а Kernel реализует object_id.

Непосредственные значения передаются не по ссылке, а по значению: nil, true, false, Fixnum, символы и некоторые значения Float.

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);
}

Вызывает метод, указанный в 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"
equal?(other) → true or false
eql?(other) → true or 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?, должен также соответствующим образом переопределить hash.

Для объектов класса 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 передана 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
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, благодаря чему код получает доступ к переменным экземпляра 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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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