класс Object
Object — это корневой класс по умолчанию для всех объектов Ruby. Object наследуется от BasicObject, что позволяет создавать альтернативные иерархии объектов. Методы класса Object доступны всем классам, если только они явно не переопределены.
Object подключает модуль Kernel, делая встроенные функции ядра глобально доступными. Хотя методы экземпляров класса Object определены модулем Kernel, для наглядности мы решили описать их здесь.
При обращении к константам в классах, наследующихся от Object, не нужно указывать полное пространство имён. Например, обращение к File внутри YourClass найдёт класс File верхнего уровня.
В описаниях методов Object параметр symbol обозначает символ, которым может быть строка в кавычках или Symbol (например, :name).
Что здесь есть
Сначала рассмотрим, что находится в других разделах. Класс Object:
-
Наследуется от класса BasicObject.
-
Подключает модуль Kernel.
Класс Object предоставляет методы для:
Проверки
-
!~: возвращаетtrue, еслиselfне соответствует заданному объекту, в противном случае возвращаетfalse. -
<=>: возвращает 0, еслиselfи заданный объектobjectявляются одним и тем же объектом или еслиself == object; в противном случае возвращаетnil. -
===: реализует равенство для case, что фактически эквивалентно вызову==. -
eql?: реализует равенство для хеширования, что фактически эквивалентно вызову==. -
kind_of?(также имеет псевдонимis_a?): возвращает, является ли заданный аргумент предком singleton-классаself. -
instance_of?: возвращает, является лиselfэкземпляром заданного класса. -
instance_variable_defined?: возвращает, определена ли заданная переменная экземпляра вself. -
method: возвращает объект Method для заданного метода вself. -
methods: возвращает массив имён символов публичных и защищённых методов вself. -
nil?: возвращаетfalse. (Толькоnilотвечаетtrueна вызов методаnil?.) -
object_id: возвращает целое число, соответствующееselfи уникальное в текущем процессе -
private_methods: возвращает массив имён символов закрытых методов вself. -
protected_methods: возвращает массив имён символов защищённых методов вself. -
public_method: возвращает объект Method для заданного публичного метода вself. -
public_methods: возвращает массив имён символов публичных методов вself. -
respond_to?: возвращает, отвечает лиselfна вызов заданного метода. -
singleton_class: возвращает singleton-классself. -
singleton_method: возвращает объект Method для заданного singleton-метода вself. -
singleton_methods: возвращает массив имён символов singleton-методов вself. -
define_singleton_method: определяет singleton-метод вselfпо заданному имени метода в виде символа и блоку или процедуре. -
extend: подключает заданные модули к singleton-классуself. -
public_send: вызывает заданный публичный метод вselfс заданным аргументом. -
send: вызывает заданный метод вselfс заданным аргументом.
Переменные экземпляра
-
instance_variable_get: возвращает значение заданной переменной экземпляра вselfилиnil, если переменная экземпляра не задана. -
instance_variable_set: задаёт значение заданной переменной экземпляра вselfравным заданному объекту. -
instance_variables: возвращает массив имён символов переменных экземпляра вself. -
remove_instance_variable: удаляет именованную переменную экземпляра изself.
Прочее
-
clone: возвращает поверхностную копиюself, включая singleton-класс и состояние заморозки. -
define_singleton_method: определяет singleton-метод вselfпо заданному имени метода в виде символа и блоку или процедуре. -
dup: возвращает поверхностную незамороженную копиюself. -
enum_for(также имеет псевдонимto_enum): возвращаетEnumeratorдляself, используя заданный метод, аргументы и блок. -
extend: подключает заданные модули к singleton-классуself. -
freeze: запрещает дальнейшее изменениеself. -
hash: возвращает целочисленное хеш-значение дляself. -
inspect: возвращает удобочитаемое строковое представлениеself. -
itself: возвращаетself. -
method_missing: метод, вызываемый при обращении к неопределённому методу объектаself. -
public_send: вызывает заданный публичный метод вselfс заданным аргументом. -
send: вызывает заданный метод вselfс заданным аргументом. -
to_s: возвращает строковое представлениеself.
Константы
- ARGF
-
ARGF— это поток, предназначенный для использования в скриптах, обрабатывающих файлы, указанные в аргументах командной строки или переданные черезSTDIN.Подробнее см.
ARGF(класс). - ARGV
-
ARGVсодержит аргументы командной строки, использованные для запуска Ruby.Для обработки аргументов командной строки можно использовать такую библиотеку, как
OptionParser. - CROSS_COMPILING
- DATA
-
DATA— этоFile, содержащий раздел данных исполняемого файла. Чтобы создать раздел данных, используйте__END__:$ cat t.rb puts DATA.gets __END__ hello world! $ ruby t.rb hello world!
- ENV
-
ENV— это средство доступа к переменным окружения, работающее подобно Hash.Подробнее см.
ENV(класс). - RUBY_COPYRIGHT
-
Строка с информацией об авторских правах на Ruby
- RUBY_DESCRIPTION
-
Полная строка версии Ruby, например, выводимая командой
ruby -v - RUBY_ENGINE
-
Движок или интерпретатор, используемый этим экземпляром Ruby.
- RUBY_ENGINE_VERSION
-
Версия движка или интерпретатора, используемого этим экземпляром Ruby.
- RUBY_PATCHLEVEL
-
Уровень исправлений для этого экземпляра Ruby. Для разрабатываемой сборки Ruby уровень исправлений будет равен -1.
- RUBY_PLATFORM
-
Платформа для этого экземпляра Ruby
- RUBY_RELEASE_DATE
-
Дата выпуска этой версии Ruby
- RUBY_REVISION
-
Хеш коммита GIT для этого экземпляра Ruby.
- RUBY_VERSION
-
Версия запущенного Ruby
- Readline
- Ripper
-
Это записывает преобразование prism ripper в константу
Ripper, чтобы пользователи могли использоватьRipperбез каких-либо изменений. - STDERR
-
Содержит исходный поток stderr
- STDIN
-
Содержит исходный поток stdin
- STDOUT
-
Содержит исходный поток stdout
- TOPLEVEL_BINDING
-
Bindingобласти видимости верхнего уровня
Публичные методы класса
# File ext/psych/lib/psych/core_ext.rb, line 3 def self.yaml_tag url Psych.add_tag(url, self) end
Публичные методы экземпляра
static VALUE
rb_obj_not_match(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_match, 1, obj2);
return rb_obj_not(result);
} Возвращает true, если два объекта не совпадают (с использованием метода =~), иначе false.
static VALUE
rb_obj_cmp(VALUE obj1, VALUE obj2)
{
if (rb_equal(obj1, obj2))
return INT2FIX(0);
return Qnil;
} Возвращает 0, если obj и other являются одним и тем же объектом или obj == other, иначе nil.
<=> используется различными методами для сравнения объектов, например Enumerable#sort, Enumerable#max и т. д.
Ваша реализация <=> должна возвращать одно из следующих значений: -1, 0, 1 или nil. -1 означает, что self меньше other. 0 означает, что self равен other. 1 означает, что self больше other. Nil означает, что эти два значения нельзя сравнить.
Определив <=>, можно подключить Comparable, чтобы получить методы <=, <, ==, >=, > и between?.
#define case_equal rb_equal
Возвращает true или false.
Как и Object#==, возвращает результат, если object является экземпляром Object (а не экземпляром одного из его многочисленных подклассов).
Этот метод часто переопределяют в таких подклассах, чтобы обеспечить осмысленную семантику в выражениях case.
# File lib/delegate.rb, line 394
def DelegateClass(superclass, &block)
klass = Class.new(Delegator)
ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===]
protected_instance_methods = superclass.protected_instance_methods
protected_instance_methods -= ignores
public_instance_methods = superclass.public_instance_methods
public_instance_methods -= ignores
klass.module_eval do
def __getobj__ # :nodoc:
unless defined?(@delegate_dc_obj)
return yield if block_given?
__raise__ ::ArgumentError, "not delegated"
end
@delegate_dc_obj
end
def __setobj__(obj) # :nodoc:
__raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
@delegate_dc_obj = obj
end
protected_instance_methods.each do |method|
define_method(method, Delegator.delegating_block(method))
protected method
end
public_instance_methods.each do |method|
define_method(method, Delegator.delegating_block(method))
end
end
klass.define_singleton_method :public_instance_methods do |all=true|
super(all) | superclass.public_instance_methods
end
klass.define_singleton_method :protected_instance_methods do |all=true|
super(all) | superclass.protected_instance_methods
end
klass.define_singleton_method :instance_methods do |all=true|
super(all) | superclass.instance_methods
end
klass.define_singleton_method :public_instance_method do |name|
super(name)
rescue NameError
raise unless self.public_instance_methods.include?(name)
superclass.public_instance_method(name)
end
klass.define_singleton_method :instance_method do |name|
super(name)
rescue NameError
raise unless self.instance_methods.include?(name)
superclass.instance_method(name)
end
klass.module_eval(&block) if block
return klass
end Основной интерфейс этой библиотеки. Используйте его для настройки делегирования при определении своего класса.
class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
def initialize
super(obj_of_ClassToDelegateTo) # Step 2
end
end
или:
MyClass = DelegateClass(ClassToDelegateTo) do # Step 1
def initialize
super(obj_of_ClassToDelegateTo) # Step 2
end
end
Ниже приведён пример использования из Tempfile, который на самом деле является объектом File с несколькими особыми правилами, определяющими место хранения и момент удаления File. Это почти идеальный учебный пример использования делегирования.
class Tempfile < DelegateClass(File)
# constant and class member data initialization...
def initialize(basename, tmpdir=Dir::tmpdir)
# build up file path/name in var tmpname...
@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
# ...
super(@tmpfile)
# below this point, all methods of File are supported...
end
# ...
end
# File ext/digest/lib/digest.rb, line 110
def Digest(name)
const = name.to_sym
Digest::REQUIRE_MUTEX.synchronize {
# Ignore autoload's because it is void when we have #const_missing
Digest.const_missing(const)
}
rescue LoadError
# Constants do not necessarily rely on digest/*.
if Digest.const_defined?(const)
Digest.const_get(const)
else
raise
end
end Возвращает подкласс Digest по name потокобезопасным способом, даже при отложенной загрузке.
require 'digest'
Digest("MD5")
# => Digest::MD5
Digest(:SHA256)
# => Digest::SHA256
Digest(:Foo)
# => LoadError: library not found for class Digest::Foo -- digest/foo
static VALUE
rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
{
VALUE klass = rb_singleton_class(obj);
const rb_scope_visibility_t scope_visi = {METHOD_VISI_PUBLIC, FALSE};
return rb_mod_define_method_with_visibility(argc, argv, klass, &scope_visi);
} Определяет публичный метод-синглтон для получателя. Параметр method может быть объектом Proc, Method или UnboundMethod. Если указан блок, он используется как тело метода. Если у блока или метода есть параметры, они используются в качестве параметров метода.
class A
class << self
def class_name
to_s
end
end
end
A.define_singleton_method(:who_am_i) do
"I am: #{class_name}"
end
A.who_am_i # ==> "I am: A"
guy = "Bob"
guy.define_singleton_method(:hello) { "#{self}: Hello there!" }
guy.hello #=> "Bob: Hello there!"
chris = "Chris"
chris.define_singleton_method(:greet) {|greeting| "#{greeting}, I'm Chris!" }
chris.greet("Hi") #=> "Hi, I'm Chris!"
static VALUE
rb_obj_display(int argc, VALUE *argv, VALUE self)
{
VALUE out;
out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
rb_io_write(out, self);
return Qnil;
} Записывает self в указанный порт:
1.display "cat".display [ 4, 5, 6 ].display puts
Вывод:
1cat[4, 5, 6]
VALUE
rb_obj_dup(VALUE obj)
{
VALUE dup;
if (special_object_p(obj)) {
return obj;
}
dup = rb_obj_alloc(rb_obj_class(obj));
return rb_obj_dup_setup(obj, dup);
} Создаёт поверхностную копию obj — копируются переменные экземпляра объекта obj, но не объекты, на которые они ссылаются.
Этот метод может иметь поведение, специфичное для класса. В таком случае оно описано в разделе #initialize_copy класса.
о различиях между dup и clone
В общем случае clone и dup могут иметь различную семантику в классах-потомках. Метод clone используется для дублирования объекта, включая его внутреннее состояние, а dup обычно использует класс объекта-потомка для создания нового экземпляра.
При использовании dup модули, которыми был расширен объект, не копируются.
class Klass attr_accessor :str end module Foo def foo; 'foo'; end end s1 = Klass.new #=> #<Klass:0x401b3a38> s1.extend(Foo) #=> #<Klass:0x401b3a38> s1.foo #=> "foo" s2 = s1.clone #=> #<Klass:0x401be280> s2.foo #=> "foo" s3 = s1.dup #=> #<Klass:0x401c1084> s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401c1084>
Создаёт новый Enumerator, который выполняет перечисление, вызывая method для obj и передавая args, если они есть. Значения, выдаваемые методом, становятся значениями перечислителя.
Если передан блок, он будет использоваться для вычисления размера перечислителя без необходимости его обхода (см. Enumerator#size).
Примеры
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
# protect an array from being modified by some_method
a = [1, 2, 3]
some_method(a.to_enum)
# String#split in block form is more memory-effective:
very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') }
# This could be rewritten more idiomatically with to_enum:
very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first
При определении методов для универсального Enumerable обычно вызывают to_enum на случай, если блок не передан.
Вот такой пример с передачей параметров и блоком для вычисления размера:
module Enumerable
# a generic method to repeat the values of any enumerable
def repeat(n)
raise ArgumentError, "#{n} is negative!" if n < 0
unless block_given?
return to_enum(__method__, n) do # __method__ is :repeat here
sz = size # Call size and multiply by n...
sz * n if sz # but return nil if size itself is nil
end
end
each do |*val|
n.times { yield *val }
end
end
end
%i[hello world].repeat(2) { |w| puts w }
# => Prints 'hello', 'hello', 'world', 'world'
enum = (1..14).repeat(3)
# => returns an Enumerator when called without a block
enum.first(4) # => [1, 1, 1, 2]
enum.size # => 42
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, значения hash обоих объектов должны совпадать. Поэтому любой подкласс, переопределяющий eql?, должен также соответствующим образом переопределить hash.
Для объектов класса Object метод eql? является синонимом ==. Подклассы обычно следуют этой традиции, задавая псевдоним eql? для переопределённого метода ==, но бывают исключения. Например, типы Numeric выполняют преобразование типов при сравнении с помощью ==, но не при сравнении с помощью eql?, поэтому:
1 == 1.0 #=> true 1.eql? 1.0 #=> false
static VALUE
rb_obj_extend(int argc, VALUE *argv, VALUE obj)
{
int i;
ID id_extend_object, id_extended;
CONST_ID(id_extend_object, "extend_object");
CONST_ID(id_extended, "extended");
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
for (i = 0; i < argc; i++) {
Check_Type(argv[i], T_MODULE);
if (FL_TEST(argv[i], RMODULE_IS_REFINEMENT)) {
rb_raise(rb_eTypeError, "Cannot extend object with refinement");
}
}
while (argc--) {
rb_funcall(argv[argc], id_extend_object, 1, obj);
rb_funcall(argv[argc], id_extended, 1, obj);
}
return obj;
} Добавляет к obj методы экземпляра из каждого модуля, переданного в качестве параметра.
module Mod
def hello
"Hello from Mod.\n"
end
end
class Klass
def hello
"Hello from Klass.\n"
end
end
k = Klass.new
k.hello #=> "Hello from Klass.\n"
k.extend(Mod) #=> #<Klass:0x401b3bc8>
k.hello #=> "Hello from Mod.\n"
VALUE
rb_obj_freeze(VALUE obj)
{
if (!OBJ_FROZEN(obj)) {
OBJ_FREEZE(obj);
if (SPECIAL_CONST_P(obj)) {
rb_bug("special consts should be frozen.");
}
}
return obj;
} Запрещает дальнейшее изменение obj. При попытке изменить объект будет вызвано исключение FrozenError. Разморозить замороженный объект невозможно. См. также Object#frozen?.
Этот метод возвращает self.
a = [ "a", "b", "c" ] a.freeze a << "z"
результат:
prog.rb:3:in `<<': can't modify frozen Array (FrozenError) from prog.rb:3
Объекты следующих классов всегда заморожены: Integer, Float, Symbol.
VALUE
rb_obj_hash(VALUE obj)
{
long hnum = any_hash(obj, objid_hash);
return ST2FIX(hnum);
} Генерирует хеш-значение типа Integer для этого объекта. Эта функция должна обладать свойством: если a.eql?(b), то a.hash == b.hash.
Хеш-значение вместе с eql? используется классом Hash для определения того, ссылаются ли два объекта на один и тот же ключ хеша. Любое хеш-значение, превышающее ёмкость Integer, будет усечено перед использованием.
Хеш-значение объекта может различаться при разных запусках Ruby или в разных реализациях Ruby. Если вам нужен стабильный идентификатор для разных запусков и реализаций Ruby, его необходимо создать с помощью собственного метода.
Некоторые основные классы, например Integer, используют встроенные вычисления хеша и не вызывают метод hash при использовании в качестве ключа хеша.
При реализации собственного hash на основе нескольких значений рекомендуется объединять класс и любые значения, используя хеш-код массива:
Например:
def hash [self.class, a, b, c].hash end
Причина в том, что метод Array#hash уже умеет безопасно и эффективно объединять несколько хеш-значений.
static VALUE
rb_obj_inspect(VALUE obj)
{
if (rb_ivar_count(obj) > 0) {
VALUE str;
VALUE c = rb_class_name(CLASS_OF(obj));
str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj);
return rb_exec_recursive(inspect_obj, obj, str);
}
else {
return rb_any_to_s(obj);
}
} Возвращает строку с человекочитаемым представлением obj. Реализация inspect по умолчанию отображает имя класса объекта, кодированный адрес его памяти и список переменных экземпляра с их значениями (вызывая inspect для каждой из них). Пользовательским классам следует переопределить этот метод, чтобы обеспечить более подходящее представление obj. При переопределении этот метод должен возвращать строку с кодировкой, совместимой с кодировкой внешнего представления по умолчанию.
[ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]"
Time.new.inspect #=> "2008-03-08 19:43:39 +0900"
class Foo
end
Foo.new.inspect #=> "#<Foo:0x0300c868>"
class Bar
def initialize
@bar = 1
end
end
Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>"
VALUE
rb_obj_is_instance_of(VALUE obj, VALUE c)
{
c = class_or_module_required(c);
return RBOOL(rb_obj_class(obj) == c);
} Возвращает true, если obj является экземпляром указанного класса. См. также Object#kind_of?.
class A; end class B < A; end class C < B; end b = B.new b.instance_of? A #=> false b.instance_of? B #=> true b.instance_of? C #=> false
static VALUE
rb_obj_ivar_defined(VALUE obj, VALUE iv)
{
ID id = id_for_var(obj, iv, instance);
if (!id) {
return Qfalse;
}
return rb_ivar_defined(obj, id);
} Возвращает true, если указанная переменная экземпляра определена в obj. Аргументы типа String преобразуются в символы.
class Fred
def initialize(p1, p2)
@a, @b = p1, p2
end
end
fred = Fred.new('cat', 99)
fred.instance_variable_defined?(:@a) #=> true
fred.instance_variable_defined?("@b") #=> true
fred.instance_variable_defined?("@c") #=> false
static VALUE
rb_obj_ivar_get(VALUE obj, VALUE iv)
{
ID id = id_for_var(obj, iv, instance);
if (!id) {
return Qnil;
}
return rb_ivar_get(obj, id);
} Возвращает значение указанной переменной экземпляра или nil, если переменная экземпляра не задана. Для обычных переменных экземпляра необходимо указывать часть @ имени переменной. Вызывает исключение NameError, если переданный символ недопустим в качестве имени переменной экземпляра. Аргументы типа String преобразуются в символы.
class Fred
def initialize(p1, p2)
@a, @b = p1, p2
end
end
fred = Fred.new('cat', 99)
fred.instance_variable_get(:@a) #=> "cat"
fred.instance_variable_get("@b") #=> 99
static VALUE
rb_obj_ivar_set_m(VALUE obj, VALUE iv, VALUE val)
{
ID id = id_for_var(obj, iv, instance);
if (!id) id = rb_intern_str(iv);
return rb_ivar_set(obj, id, val);
} Присваивает переменной экземпляра с именем symbol указанный объект. Это может обойти инкапсуляцию, предусмотренную автором класса, поэтому использовать этот метод следует осторожно. Переменная не обязана существовать до вызова метода. Если имя переменной экземпляра передано в виде строки, эта строка преобразуется в символ.
class Fred
def initialize(p1, p2)
@a, @b = p1, p2
end
end
fred = Fred.new('cat', 99)
fred.instance_variable_set(:@a, 'dog') #=> "dog"
fred.instance_variable_set(:@c, 'cat') #=> "cat"
fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
VALUE
rb_obj_instance_variables(VALUE obj)
{
VALUE ary;
ary = rb_ary_new();
rb_ivar_foreach(obj, ivar_i, ary);
return ary;
} Возвращает массив имён переменных экземпляра получателя. Обратите внимание: простое определение метода доступа не создаёт соответствующую переменную экземпляра.
class Fred
attr_accessor :a1
def initialize
@iv = 3
end
end
Fred.new.instance_variables #=> [:@iv]
Возвращает true, если class является классом obj либо одним из суперклассов obj или модулей, подключённых к obj.
module M; end class A include M end class B < A; end class C < B; end b = B.new b.is_a? A #=> true b.is_a? B #=> true b.is_a? C #=> false b.is_a? M #=> true b.kind_of? A #=> true b.kind_of? B #=> true b.kind_of? C #=> false b.kind_of? M #=> true
static VALUE
rb_obj_itself(VALUE obj)
{
return obj;
} Возвращает получателя.
string = "my string" string.itself.object_id == string.object_id #=> true
VALUE
rb_obj_is_kind_of(VALUE obj, VALUE c)
{
VALUE cl = CLASS_OF(obj);
RUBY_ASSERT(RB_TYPE_P(cl, T_CLASS));
// Fastest path: If the object's class is an exact match we know `c` is a
// class without checking type and can return immediately.
if (cl == c) return Qtrue;
// Note: YJIT needs this function to never allocate and never raise when
// `c` is a class or a module.
if (LIKELY(RB_TYPE_P(c, T_CLASS))) {
// Fast path: Both are T_CLASS
return class_search_class_ancestor(cl, c);
}
else if (RB_TYPE_P(c, T_ICLASS)) {
// First check if we inherit the includer
// If we do we can return true immediately
VALUE includer = RCLASS_INCLUDER(c);
if (cl == includer) return Qtrue;
// Usually includer is a T_CLASS here, except when including into an
// already included Module.
// If it is a class, attempt the fast class-to-class check and return
// true if there is a match.
if (RB_TYPE_P(includer, T_CLASS) && class_search_class_ancestor(cl, includer))
return Qtrue;
// We don't include the ICLASS directly, so must check if we inherit
// the module via another include
return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
}
else if (RB_TYPE_P(c, T_MODULE)) {
// Slow path: check each ancestor in the linked list and its method table
return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
}
else {
rb_raise(rb_eTypeError, "class or module required");
UNREACHABLE_RETURN(Qfalse);
}
} Возвращает true, если class является классом obj либо одним из суперклассов obj или модулей, подключённых к obj.
module M; end class A include M end class B < A; end class C < B; end b = B.new b.is_a? A #=> true b.is_a? B #=> true b.is_a? C #=> false b.is_a? M #=> true b.kind_of? A #=> true b.kind_of? B #=> true b.kind_of? C #=> false b.kind_of? M #=> true
VALUE
rb_obj_method(VALUE obj, VALUE vid)
{
return obj_method(obj, vid, FALSE);
} Ищет в obj метод с указанным именем и возвращает объект Method (или вызывает исключение NameError). Объект Method действует как замыкание в экземпляре объекта obj, поэтому переменные экземпляра и значение self остаются доступными.
class Demo
def initialize(n)
@iv = n
end
def hello()
"Hello, @iv = #{@iv}"
end
end
k = Demo.new(99)
m = k.method(:hello)
m.call #=> "Hello, @iv = 99"
l = Demo.new('Fred')
m = l.method("hello")
m.call #=> "Hello, @iv = Fred"
Обратите внимание, что Method реализует метод to_proc, поэтому его можно использовать с итераторами.
[ 1, 2, 3 ].each(&method(:puts)) # => prints 3 lines to stdout
out = File.open('test.txt', 'w')
[ 1, 2, 3 ].each(&out.method(:puts)) # => prints 3 lines to file
require 'date'
%w[2017-03-01 2017-03-02].collect(&Date.method(:parse))
#=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
VALUE
rb_obj_methods(int argc, const VALUE *argv, VALUE obj)
{
rb_check_arity(argc, 0, 1);
if (argc > 0 && !RTEST(argv[0])) {
return rb_obj_singleton_methods(argc, argv, obj);
}
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_i);
} Возвращает список имён публичных и защищённых методов объекта obj. В него входят все методы, доступные в предках obj. Если необязательный параметр равен false, возвращается массив публичных и защищённых методов-синглтонов obj; методы модулей, подключённых к obj, в массив не включаются.
class Klass
def klass_method()
end
end
k = Klass.new
k.methods[0..9] #=> [:klass_method, :nil?, :===,
# :==~, :!, :eql?
# :hash, :<=>, :class, :singleton_class]
k.methods.length #=> 56
k.methods(false) #=> []
def k.singleton_method; end
k.methods(false) #=> [:singleton_method]
module M123; def m123; end end
k.extend M123
k.methods(false) #=> [:singleton_method]
VALUE
rb_false(VALUE obj)
{
return Qfalse;
} Только объект nil отвечает true на nil?.
Object.new.nil? #=> false nil.nil? #=> true
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, 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_obj_private_methods(int argc, const VALUE *argv, VALUE obj)
{
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_priv_i);
} Возвращает список закрытых методов, доступных для obj. Если параметр all установлен в false, будут перечислены только методы самого получателя.
VALUE
rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj)
{
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_prot_i);
} Возвращает список защищённых методов, доступных для obj. Если параметр all установлен в false, будут перечислены только методы самого получателя.
VALUE
rb_obj_public_method(VALUE obj, VALUE vid)
{
return obj_method(obj, vid, TRUE);
} Подобно method, ищет только публичные методы.
VALUE
rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj)
{
return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_pub_i);
} Возвращает список публичных методов, доступных для obj. Если параметр all установлен в false, будут перечислены только методы самого получателя.
static VALUE
rb_f_public_send(int argc, VALUE *argv, VALUE recv)
{
return send_internal_kw(argc, argv, recv, CALL_PUBLIC);
} Вызывает метод, указанный в symbol, передавая ему все заданные аргументы. В отличие от send, public_send вызывает только публичные методы. Если метод указан строкой, строка преобразуется в символ.
1.public_send(:puts, "hello") # causes NoMethodError
VALUE
rb_obj_remove_instance_variable(VALUE obj, VALUE name)
{
const ID id = id_for_var(obj, name, an, instance);
// Frozen check comes here because it's expected that we raise a
// NameError (from the id_for_var check) before we raise a FrozenError
rb_check_frozen(obj);
if (id) {
VALUE val = rb_ivar_delete(obj, id, Qundef);
if (!UNDEF_P(val)) return val;
}
rb_name_err_raise("instance variable %1$s not defined",
obj, name);
UNREACHABLE_RETURN(Qnil);
} Удаляет из obj именованную переменную экземпляра и возвращает её значение. Имя можно передать в виде символа или строки.
class Dummy
attr_reader :var
def initialize
@var = 99
end
def remove
remove_instance_variable(:@var)
end
end
d = Dummy.new
d.var #=> 99
d.remove #=> 99
d.var #=> nil
static VALUE
obj_respond_to(int argc, VALUE *argv, VALUE obj)
{
VALUE mid, priv;
ID id;
rb_execution_context_t *ec = GET_EC();
rb_scan_args(argc, argv, "11", &mid, &priv);
if (!(id = rb_check_id(&mid))) {
VALUE ret = basic_obj_respond_to_missing(ec, CLASS_OF(obj), obj,
rb_to_symbol(mid), priv);
if (UNDEF_P(ret)) ret = Qfalse;
return ret;
}
return RBOOL(basic_obj_respond_to(ec, obj, id, !RTEST(priv)));
} Возвращает true, если obj поддерживает указанный метод. Закрытые и защищённые методы включаются в поиск, только если необязательный второй параметр имеет значение true.
Если метод не реализован, как Process.fork в Windows, File.lchmod в GNU/Linux и т. д., возвращается false.
Если метод не определён, вызывается метод respond_to_missing? и возвращается результат.
Если имя метода задано строкой, она преобразуется в символ.
static VALUE
obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv)
{
return Qfalse;
} НЕ ВЫЗЫВАЙТЕ ЭТОТ МЕТОД НАПРЯМУЮ.
Метод-перехватчик, возвращающий информацию о том, может ли obj отвечать на вызов метода id.
Если имя метода задано строкой, она преобразуется в символ.
См. respond_to? и пример для BasicObject.
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"
static VALUE
rb_obj_singleton_class(VALUE obj)
{
return rb_singleton_class(obj);
} Возвращает класс-синглтон объекта obj. Если у obj нет класса-синглтона, этот метод создаёт его.
Если obj — nil, true или false, он возвращает соответственно NilClass, TrueClass или FalseClass. Если obj — Integer, Float или Symbol, метод вызывает исключение TypeError.
Object.new.singleton_class #=> #<Class:#<Object:0xb7ce1e24>> String.singleton_class #=> #<Class:String> nil.singleton_class #=> NilClass
VALUE
rb_obj_singleton_method(VALUE obj, VALUE vid)
{
VALUE sc = rb_singleton_class_get(obj);
VALUE klass;
ID id = rb_check_id(&vid);
if (NIL_P(sc) ||
NIL_P(klass = RCLASS_ORIGIN(sc)) ||
!NIL_P(rb_special_singleton_class(obj))) {
/* goto undef; */
}
else if (! id) {
VALUE m = mnew_missing_by_name(klass, obj, &vid, FALSE, rb_cMethod);
if (m) return m;
/* else goto undef; */
}
else {
VALUE args[2] = {obj, vid};
VALUE ruby_method = rb_rescue(rb_obj_singleton_method_lookup, (VALUE)args, rb_obj_singleton_method_lookup_fail, Qfalse);
if (ruby_method) {
struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(ruby_method);
VALUE lookup_class = RBASIC_CLASS(obj);
VALUE stop_class = rb_class_superclass(sc);
VALUE method_class = method->iclass;
/* Determine if method is in singleton class, or module included in or prepended to it */
do {
if (lookup_class == method_class) {
return ruby_method;
}
lookup_class = RCLASS_SUPER(lookup_class);
} while (lookup_class && lookup_class != stop_class);
}
}
/* undef: */
vid = ID2SYM(id);
rb_name_err_raise("undefined singleton method '%1$s' for '%2$s'",
obj, vid);
UNREACHABLE_RETURN(Qundef);
} Аналогично method, но выполняет поиск только среди методов-синглтонов.
class Demo
def initialize(n)
@iv = n
end
def hello()
"Hello, @iv = #{@iv}"
end
end
k = Demo.new(99)
def k.hi
"Hi, @iv = #{@iv}"
end
m = k.singleton_method(:hi)
m.call #=> "Hi, @iv = 99"
m = k.singleton_method(:hello) #=> NameError
VALUE
rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
{
VALUE ary, klass, origin;
struct method_entry_arg me_arg;
struct rb_id_table *mtbl;
int recur = TRUE;
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
if (RCLASS_SINGLETON_P(obj)) {
rb_singleton_class(obj);
}
klass = CLASS_OF(obj);
origin = RCLASS_ORIGIN(klass);
me_arg.list = st_init_numtable();
me_arg.recur = recur;
if (klass && RCLASS_SINGLETON_P(klass)) {
if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
if (recur) {
while (klass && (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS))) {
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
}
ary = rb_ary_new2(me_arg.list->num_entries);
st_foreach(me_arg.list, ins_methods_i, ary);
st_free_table(me_arg.list);
return ary;
} Возвращает массив имён методов-синглтонов объекта obj. Если необязательный параметр all равен true, список включает методы модулей, подключённых к obj. Возвращаются только открытые и защищённые методы-синглтоны.
module Other def three() end end class Single def Single.four() end end a = Single.new def a.one() end class << a include Other def two() end end Single.singleton_methods #=> [:four] a.singleton_methods(false) #=> [:two, :one] a.singleton_methods #=> [:two, :one, :three]
static VALUE
obj_to_enum(int argc, VALUE *argv, VALUE obj)
{
VALUE enumerator, meth = sym_each;
if (argc > 0) {
--argc;
meth = *argv++;
}
enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
if (rb_block_given_p()) {
RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc());
}
return enumerator;
} Создаёт новый Enumerator, который выполняет перебор, вызывая method для obj и передавая ему args, если они указаны. Значения, переданные в блок методом, становятся значениями перечислителя.
Если задан блок, он используется для вычисления размера перечислителя без необходимости его перебора (см. Enumerator#size).
Примеры
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
# protect an array from being modified by some_method
a = [1, 2, 3]
some_method(a.to_enum)
# String#split in block form is more memory-effective:
very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') }
# This could be rewritten more idiomatically with to_enum:
very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first
При определении методов для обобщённого Enumerable обычно вызывают to_enum на случай, если блок не передан.
Ниже приведён такой пример с передачей параметров и блоком для вычисления размера:
module Enumerable
# a generic method to repeat the values of any enumerable
def repeat(n)
raise ArgumentError, "#{n} is negative!" if n < 0
unless block_given?
return to_enum(__method__, n) do # __method__ is :repeat here
sz = size # Call size and multiply by n...
sz * n if sz # but return nil if size itself is nil
end
end
each do |*val|
n.times { yield *val }
end
end
end
%i[hello world].repeat(2) { |w| puts w }
# => Prints 'hello', 'hello', 'world', 'world'
enum = (1..14).repeat(3)
# => returns an Enumerator when called without a block
enum.first(4) # => [1, 1, 1, 2]
enum.size # => 42
VALUE
rb_any_to_s(VALUE obj)
{
VALUE str;
VALUE cname = rb_class_name(CLASS_OF(obj));
str = rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)obj);
return str;
} Возвращает строку, представляющую obj. Реализация to_s по умолчанию выводит класс объекта и представление его идентификатора. В особом случае объект верхнего уровня, являющийся начальным контекстом выполнения программ Ruby, возвращает «main».
# File ext/psych/lib/psych/core_ext.rb, line 12
def to_yaml options = {}
Psych.dump self, options
end Преобразует объект в YAML. Дополнительные сведения о доступных options см. в Psych.dump.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.