класс Object
Object является корневым объектом всех объектов Ruby. Object наследуется от BasicObject, что позволяет создавать альтернативные иерархии объектов. Методы класса Object доступны для всех классов, если не переопределены явно.
Object смешивает модуль Kernel, делая встроенные функции ядра глобально доступными. Хотя методы экземпляров класса Object определены модулем Kernel, мы выбрали их документировать здесь для ясности.
При обращении к константам в классах, наследующих от Object, не нужно использовать полное имя пространства имён. Например, обращение к File внутри YourClass найдёт верхнеуровневый класс File.
В описаниях методов класса Object параметр символ относится к символу, который может быть строкой в кавычках или Symbol (например, :name).
Что здесь
Сначала, что находится где-то еще. Класс Object:
-
Наследуется от класса BasicObject.
-
Включает модуль Kernel.
Здесь класс Object предоставляет методы для:
Запросы
-
!~: Возвращаетtrueеслиselfне совпадает с данным объектом, иначеfalse. -
<=>: Возвращает 0, еслиselfи заданный объектobject— один и тот же объект или еслиself == object; в противном случае возвращаетnil. -
===: Реализует равенство по типу, что эффективно то же самое, что вызов==. -
eql?: Реализует равенство для хешей, что эффективно то же самое, что вызов==. -
kind_of?(псевдонимis_a?): Возвращает значение, определяющее, является ли заданный аргумент предком единственного классаself. -
instance_of?: Возвращает значение, определяющее, является лиselfэкземпляром данного класса. -
instance_variable_defined?: Возвращает значение, определяющее, задана ли данная переменная экземпляра в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: Возвращает единственный классself. -
singleton_method: Возвращает объектMethodдля данного одиночного метода вself. -
singleton_methods: Возвращает массив имён символов одиночных методов вself. -
define_singleton_method: Определяет одиночный метод вselfдля данного имени метода-символа и блока или proc. -
extend: Включает заданные модули в единственный классself. -
public_send: Вызывает данный публичный метод вselfс заданным аргументом. -
send: Вызывает данный метод вselfс заданным аргументом.
Переменные экземпляра
-
instance_variable_get: Возвращает значение заданной переменной экземпляра вself, илиnilесли переменная экземпляра не установлена. -
instance_variable_set: Устанавливает значение заданной переменной экземпляра вselfна заданный объект. -
instance_variables: Возвращает массив имён символов переменных экземпляра вself. -
remove_instance_variable: Удаляет именованную переменную экземпляра изself.
Другие
-
clone: Возвращает поверхностную копиюself, включая единственный класс и состояние замороженности. -
define_singleton_method: Определяет одиночный метод вselfдля данного имени метода-символа и блока или proc. -
dup: Возвращает поверхностную не замороженную копиюself. -
enum_for(псевдонимto_enum): ВозвращаетEnumeratorдляselfс использованием заданного метода, аргументов и блока. -
extend: Включает заданные модули в единственный классself. -
freeze: Запрещает дальнейшие изменения вself. -
hash: Возвращает целочисленное значение хеша дляself. -
inspect: Возвращает удобочитаемую строку представленияself. -
itself: Возвращаетself. -
method_missing:Methodвызывается, когда вызывается неопределённый метод для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 — это объект-подобный хэш для доступа к переменным среды.
См.
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
- RubyLex
- STDERR
-
Содержит исходный stderr
- STDIN
-
Содержит исходный stdin
- STDOUT
-
Содержит исходный stdout
- TOPLEVEL_BINDING
-
Bindingверхнего уровня - WIN32OLE_EVENT
- WIN32OLE_METHOD
- WIN32OLE_PARAM
- WIN32OLE_RECORD
- WIN32OLE_TYPE
- WIN32OLE_TYPELIB
- WIN32OLE_VARIABLE
- WIN32OLE_VARIANT
Открытые методы класса
# 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?.
# File lib/csv.rb, line 2876 def CSV(*args, **options, &block) CSV.instance(*args, **options, &block) end
Передает args в CSV::instance.
CSV("CSV,data").read
#=> [["CSV", "data"]]
Если указан блок, экземпляру передается блок, и возвращаемое значение становится возвращаемым значением блока.
CSV("CSV,data") { |c|
c.read.any? { |a| a.include?("data") }
} #=> true
CSV("CSV,data") { |c|
c.read.any? { |a| a.include?("zombies") }
} #=> false
CSV параметры также могут быть указаны.
io = StringIO.new
CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }
Этот API не является безопасным для Ractor.
# 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));
init_copy(dup, obj);
rb_funcall(dup, id_init_dup, 1, obj);
return dup;
} Создает неглубокую копию obj — переменные экземпляра obj копируются, но не объекты, на которые они ссылаются.
Этот метод может иметь специфичное для класса поведение. Если это так, это поведение будет задокументировано в методе #initialize_copy класса.
on dup vs 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
Обычно вызывается to_enum при определении методов для общего Enumerable, если блок не передан.
Вот такой пример с передачей параметров и блоком определения размера:
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, вам нужно сгенерировать его с помощью пользовательского метода.
Некоторые основные классы, такие как 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 или если class является одним из суперклассов 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, или если class является одним из суперклассов 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)
{
/*
* 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_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 (val != Qundef) return val;
}
rb_name_err_raise("instance variable %1$s not defined",
obj, name);
UNREACHABLE_RETURN(Qnil);
} Удаляет именованную локальную переменную из obj, возвращая значение этой переменной. Аргументы String преобразуются в символы.
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 klass = rb_singleton_class_get(obj);
ID id = rb_check_id(&vid);
if (NIL_P(klass) ||
NIL_P(klass = RCLASS_ORIGIN(klass)) ||
!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 {
const rb_method_entry_t *me = rb_method_entry_at(klass, id);
vid = ID2SYM(id);
if (UNDEFINED_METHOD_ENTRY_P(me)) {
/* goto undef; */
}
else if (UNDEFINED_REFINED_METHOD_P(me->def)) {
/* goto undef; */
}
else {
return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
}
}
/* undef: */
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 (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) {
rb_singleton_class(obj);
}
klass = CLASS_OF(obj);
origin = RCLASS_ORIGIN(klass);
me_arg.list = st_init_numtable();
me_arg.recur = recur;
if (klass && FL_TEST(klass, FL_SINGLETON)) {
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 && (FL_TEST(klass, FL_SINGLETON) || 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
Обычно метод to_enum вызывается при определении методов для универсального Enumerable, если не передаётся блок.
Вот пример с передачей параметров и блоком для определения размера:
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. См. Psych.dump для получения дополнительной информации об имеющихся options.
# File lib/irb/xmp.rb, line 159 def xmp(exps, bind = nil) bind = IRB::Frame.top(1) unless bind xmp = XMP.new(bind) xmp.puts exps xmp end
Удобный метод, доступный только при подключении стандартной библиотеки IRB::XMP.
Создаёт новый объект XMP, используя заданные выражения в качестве параметра exps, и необязательную привязку в качестве bind, или использует верхнеуровневую привязку. Затем оценивает заданные выражения, используя режим ввода :XMP.
Например:
require 'irb/xmp' ctx = binding xmp 'foo = "bar"', ctx #=> foo = "bar" #==>"bar" ctx.eval 'foo' #=> "bar"
См. XMP.new для получения дополнительной информации.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.