Spec-Zone.ru › Ruby 3.4

класс Module

Родитель:
Объект

Модуль — это коллекция методов и констант. Методы модуля могут быть методами экземпляра или методами модуля. Методы экземпляра отображаются как методы класса, когда модуль включён, методы модуля — нет. Наоборот, методы модуля могут вызываться без создания объекта-оболочки, в то время как методы экземпляра — нет. (См. Module#module_function.)

В описаниях ниже параметр символ относится к символу, который является либо строкой в кавычках, либо Symbol (например, :name).

module Mod
  include Math
  CONST = 1
  def meth
    #  ...
  end
end
Mod.class              #=> Module
Mod.constants          #=> [:CONST, :PI, :E]
Mod.instance_methods   #=> [:meth]

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

constants → массив
constants(унаследованные) → массив
Исходный код
static VALUE
rb_mod_s_constants(int argc, VALUE *argv, VALUE mod)
{
    const rb_cref_t *cref = rb_vm_cref();
    VALUE klass;
    VALUE cbase = 0;
    void *data = 0;

    if (argc > 0 || mod != rb_cModule) {
        return rb_mod_constants(argc, argv, mod);
    }

    while (cref) {
        klass = CREF_CLASS(cref);
        if (!CREF_PUSHED_BY_EVAL(cref) &&
            !NIL_P(klass)) {
            data = rb_mod_const_at(CREF_CLASS(cref), data);
            if (!cbase) {
                cbase = klass;
            }
        }
        cref = CREF_NEXT(cref);
    }

    if (cbase) {
        data = rb_mod_const_of(cbase, data);
    }
    return rb_const_list(data);
}

В первом варианте возвращает массив имён всех констант, доступных из точки вызова. Этот список включает имена всех модулей и классов, определённых в глобальной области.

Module.constants.first(4)
   # => [:ARGF, :ARGV, :ArgumentError, :Array]

Module.constants.include?(:SEEK_SET)   # => false

class IO
  Module.constants.include?(:SEEK_SET) # => true
end

Второй вариант вызывает метод экземпляра constants.

nesting → массив
Исходный код
static VALUE
rb_mod_nesting(VALUE _)
{
    VALUE ary = rb_ary_new();
    const rb_cref_t *cref = rb_vm_cref();

    while (cref && CREF_NEXT(cref)) {
        VALUE klass = CREF_CLASS(cref);
        if (!CREF_PUSHED_BY_EVAL(cref) &&
            !NIL_P(klass)) {
            rb_ary_push(ary, klass);
        }
        cref = CREF_NEXT(cref);
    }
    return ary;
}

Возвращает список Modules модулей, вложенных в текущей точке вызова.

module M1
  module M2
    $a = Module.nesting
  end
end
$a           #=> [M1::M2, M1]
$a[0].name   #=> "M1::M2"
new → модуль
new {|mod| блок } → модуль
Исходный код
static VALUE
rb_mod_initialize(VALUE module)
{
    return rb_mod_initialize_exec(module);
}

Создаёт новый анонимный модуль. Если задан блок, он передаётся объекту модуля, и блок вычисляется в контексте этого модуля, как в module_eval.

fred = Module.new do
  def meth1
    "hello"
  end
  def meth2
    "bye"
  end
end
a = "my string"
a.extend(fred)   #=> "my string"
a.meth1          #=> "hello"
a.meth2          #=> "bye"

Присвойте модуль константе (имя, начинающееся с заглавной буквы), если хотите обрабатывать его как обычный модуль.

used_modules → массив
Исходный код
static VALUE
rb_mod_s_used_modules(VALUE _)
{
    const rb_cref_t *cref = rb_vm_cref();
    VALUE ary = rb_ary_new();

    while (cref) {
        if (!NIL_P(CREF_REFINEMENTS(cref))) {
            rb_hash_foreach(CREF_REFINEMENTS(cref), used_modules_i, ary);
        }
        cref = CREF_NEXT(cref);
    }

    return rb_funcall(ary, rb_intern("uniq"), 0);
}

Возвращает массив всех модулей, используемых в текущей области видимости. Порядок модулей в результирующем массиве не определён.

module A
  refine Object do
  end
end

module B
  refine Object do
  end
end

using A
using B
p Module.used_modules

результат:

[B, A]
used_refinements → массив
Исходный код
static VALUE
rb_mod_s_used_refinements(VALUE _)
{
    const rb_cref_t *cref = rb_vm_cref();
    VALUE ary = rb_ary_new();

    while (cref) {
        if (!NIL_P(CREF_REFINEMENTS(cref))) {
            rb_hash_foreach(CREF_REFINEMENTS(cref), used_refinements_i, ary);
        }
        cref = CREF_NEXT(cref);
    }

    return ary;
}

Возвращает массив всех модулей, используемых в текущей области видимости. Порядок модулей в результирующем массиве не определён.

module A
  refine Object do
  end
end

module B
  refine Object do
  end
end

using A
using B
p Module.used_refinements

результат:

[#<refinement:Object@B>, #<refinement:Object@A>]

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

mod < other → true, false или nil
Исходный код
static VALUE
rb_mod_lt(VALUE mod, VALUE arg)
{
    if (mod == arg) return Qfalse;
    return rb_class_inherited_p(mod, arg);
}

Возвращает true, если mod является подклассом other. Возвращает false если mod идентичен other или mod является предком other. Возвращает nil если между ними нет отношений. (Рассматривайте отношения с точки зрения определения класса: «class A < B» подразумевает «A < B».)

mod <= other → true, false или nil
Исходный код
VALUE
rb_class_inherited_p(VALUE mod, VALUE arg)
{
    if (mod == arg) return Qtrue;

    if (RB_TYPE_P(arg, T_CLASS) && RB_TYPE_P(mod, T_CLASS)) {
        // comparison between classes
        size_t mod_depth = RCLASS_SUPERCLASS_DEPTH(mod);
        size_t arg_depth = RCLASS_SUPERCLASS_DEPTH(arg);
        if (arg_depth < mod_depth) {
            // check if mod < arg
            return RCLASS_SUPERCLASSES(mod)[arg_depth] == arg ?
                Qtrue :
                Qnil;
        }
        else if (arg_depth > mod_depth) {
            // check if mod > arg
            return RCLASS_SUPERCLASSES(arg)[mod_depth] == mod ?
                Qfalse :
                Qnil;
        }
        else {
            // Depths match, and we know they aren't equal: no relation
            return Qnil;
        }
    }
    else {
        if (!CLASS_OR_MODULE_P(arg) && !RB_TYPE_P(arg, T_ICLASS)) {
            rb_raise(rb_eTypeError, "compared with non class/module");
        }
        if (class_search_ancestor(mod, RCLASS_ORIGIN(arg))) {
            return Qtrue;
        }
        /* not mod < arg; check if mod > arg */
        if (class_search_ancestor(arg, mod)) {
            return Qfalse;
        }
        return Qnil;
    }
}

Возвращает true, если mod является подклассом other или идентичен other. Возвращает nil если между ними нет отношений. (Рассматривайте отношения с точки зрения определения класса: «class A < B» подразумевает «A < B».)

module <=> other_module → -1, 0, +1 или nil
Исходный код
static VALUE
rb_mod_cmp(VALUE mod, VALUE arg)
{
    VALUE cmp;

    if (mod == arg) return INT2FIX(0);
    if (!CLASS_OR_MODULE_P(arg)) {
        return Qnil;
    }

    cmp = rb_class_inherited_p(mod, arg);
    if (NIL_P(cmp)) return Qnil;
    if (cmp) {
        return INT2FIX(-1);
    }
    return INT2FIX(1);
}

Сравнение — Возвращает -1, 0, +1 или nil, в зависимости от того, содержит ли module other_module, являются ли они одинаковыми или module включён в other_module.

Возвращает nil если module не имеет отношений с other_module, если other_module не является модулем или если два значения несравнимы.

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

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

1 == 1.0     #=> true
1.eql? 1.0   #=> false
mod === obj → true или false
Исходный код
static VALUE
rb_mod_eqq(VALUE mod, VALUE arg)
{
    return rb_obj_is_kind_of(arg, mod);
}

Равенство по типу — Возвращает true если obj является экземпляром mod или экземпляром одного из потомков mod. Имеет ограниченное применение для модулей, но может использоваться в операторах case для классификации объектов по классам.

mod > other → true, false или nil
Исходный код
static VALUE
rb_mod_gt(VALUE mod, VALUE arg)
{
    if (mod == arg) return Qfalse;
    return rb_mod_ge(mod, arg);
}

Возвращает true, если mod является предком other. Возвращает false если mod идентичен other или mod является потомком other. Возвращает nil если между ними нет отношений. (Рассматривайте отношения с точки зрения определения класса: «class A < B» подразумевает «B > A».)

mod >= other → true, false или nil
Исходный код
static VALUE
rb_mod_ge(VALUE mod, VALUE arg)
{
    if (!CLASS_OR_MODULE_P(arg)) {
        rb_raise(rb_eTypeError, "compared with non class/module");
    }

    return rb_class_inherited_p(arg, mod);
}

Возвращает true, если mod является предком other или они идентичны. Возвращает nil если между ними нет отношений. (Рассматривайте отношения с точки зрения определения класса: «class A < B» подразумевает «B > A».)

alias_method(new_name, old_name) → символ
Исходный код
static VALUE
rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
{
    ID oldid = rb_check_id(&oldname);
    if (!oldid) {
        rb_print_undef_str(mod, oldname);
    }
    VALUE id = rb_to_id(newname);
    rb_alias(mod, id, oldid);
    return ID2SYM(id);
}

Создаёт копию метода old_name под именем new_name. Это может использоваться для сохранения доступа к методам, которые переопределяются.

module Mod
  alias_method :orig_exit, :exit #=> :orig_exit
  def exit(code=0)
    puts "Exiting with code #{code}"
    orig_exit(code)
  end
end
include Mod
exit(99)

выводит:

Exiting with code 99
ancestors → массив
Исходный код
VALUE
rb_mod_ancestors(VALUE mod)
{
    VALUE p, ary = rb_ary_new();
    VALUE refined_class = Qnil;
    if (BUILTIN_TYPE(mod) == T_MODULE && FL_TEST(mod, RMODULE_IS_REFINEMENT)) {
        refined_class = rb_refinement_module_get_refined_class(mod);
    }

    for (p = mod; p; p = RCLASS_SUPER(p)) {
        if (p == refined_class) break;
        if (p != RCLASS_ORIGIN(p)) continue;
        if (BUILTIN_TYPE(p) == T_ICLASS) {
            rb_ary_push(ary, METACLASS_OF(p));
        }
        else {
            rb_ary_push(ary, p);
        }
    }
    return ary;
}

Возвращает список модулей, включённых/предоставленных в mod (включая сам mod).

module Mod
  include Math
  include Comparable
  prepend Enumerable
end

Mod.ancestors        #=> [Enumerable, Mod, Comparable, Math]
Math.ancestors       #=> [Math]
Enumerable.ancestors #=> [Enumerable]
attr(name, ...) → массив
attr(name, true) → массив
attr(name, false) → массив
Исходный код
VALUE
rb_mod_attr(int argc, VALUE *argv, VALUE klass)
{
    if (argc == 2 && (argv[1] == Qtrue || argv[1] == Qfalse)) {
        ID id = id_for_attr(klass, argv[0]);
        VALUE names = rb_ary_new();

        rb_category_warning(RB_WARN_CATEGORY_DEPRECATED, "optional boolean argument is obsoleted");
        rb_attr(klass, id, 1, RTEST(argv[1]), TRUE);
        rb_ary_push(names, ID2SYM(id));
        if (argv[1] == Qtrue) rb_ary_push(names, ID2SYM(rb_id_attrset(id)));
        return names;
    }
    return rb_mod_attr_reader(argc, argv, klass);
}

Первый вариант эквивалентен attr_reader. Второй вариант эквивалентен attr_accessor(name), но устарел. Последний вариант эквивалентен attr_reader(name), но устарел. Возвращает массив имён определённых методов в виде символов.

attr_accessor(символ, ...) → массив
attr_accessor(строка, ...) → массив
Исходный код
static VALUE
rb_mod_attr_accessor(int argc, VALUE *argv, VALUE klass)
{
    int i;
    VALUE names = rb_ary_new2(argc * 2);

    for (i=0; i<argc; i++) {
        ID id = id_for_attr(klass, argv[i]);

        rb_attr(klass, id, TRUE, TRUE, TRUE);
        rb_ary_push(names, ID2SYM(id));
        rb_ary_push(names, ID2SYM(rb_id_attrset(id)));
    }
    return names;
}

Определяет именованный атрибут для данного модуля, где имя — символ. Создаёт переменную экземпляра (@name) и соответствующий метод доступа для её чтения. Также создаёт метод под названием name= для установки атрибута. String аргументы преобразуются в символы. Возвращает массив имён определённых методов в виде символов.

module Mod
  attr_accessor(:one, :two) #=> [:one, :one=, :two, :two=]
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]
attr_reader(символ, ...) → массив
attr(символ, ...) → массив
attr_reader(строка, ...) → массив
attr(строка, ...) → массив
Исходный код
static VALUE
rb_mod_attr_reader(int argc, VALUE *argv, VALUE klass)
{
    int i;
    VALUE names = rb_ary_new2(argc);

    for (i=0; i<argc; i++) {
        ID id = id_for_attr(klass, argv[i]);
        rb_attr(klass, id, TRUE, FALSE, TRUE);
        rb_ary_push(names, ID2SYM(id));
    }
    return names;
}

Создаёт переменные экземпляра и соответствующие методы, возвращающие значение каждой переменной экземпляра. Эквивалентно вызову «attr:имя» для каждого имени по очереди. String аргументы преобразуются в символы. Возвращает массив имён определённых методов в виде символов.

attr_writer(символ, ...) → массив
attr_writer(строка, ...) → массив
Исходный код
static VALUE
rb_mod_attr_writer(int argc, VALUE *argv, VALUE klass)
{
    int i;
    VALUE names = rb_ary_new2(argc);

    for (i=0; i<argc; i++) {
        ID id = id_for_attr(klass, argv[i]);
        rb_attr(klass, id, FALSE, TRUE, TRUE);
        rb_ary_push(names, ID2SYM(rb_id_attrset(id)));
    }
    return names;
}

Создаёт метод доступа для присваивания значения атрибуту символ.id2name. String аргументы преобразуются в символы. Возвращает массив имён определённых методов в виде символов.

autoload(константа, имя_файла) → null
Исходный код
static VALUE
rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
{
    ID id = rb_to_id(sym);

    FilePathValue(file);
    rb_autoload_str(mod, id, file);
    return Qnil;
}

Регистрирует имя_файла для загрузки (с помощью Kernel::require) в первый раз, когда константа (которая может быть String или символом) обращается в пространстве имён модуля.

module A
end
A.autoload(:B, "b")
A::B.doit            # autoloads "b"

Если константа в модуле определена как autoload, имя файла для загрузки заменяется на имя_файла. Если константа определена, но не как autoload, ничего не происходит.

autoload?(имя, наследовать=истина) → Строка или null
Исходный код
static VALUE
rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
{
    int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
    VALUE sym = argv[0];

    ID id = rb_check_id(&sym);
    if (!id) {
        return Qnil;
    }
    return rb_autoload_at_p(mod, id, recur);
}

Возвращает имя_файла для загрузки, если имя зарегистрировано как autoload в пространстве имён модуля или в одном из его предков.

module A
end
A.autoload(:B, "b")
A.autoload?(:B)            #=> "b"

Если inherit ложно, поиск проверяет только autoload в получателе:

class A
  autoload :CONST, "const.rb"
end

class B < A
end

B.autoload?(:CONST)          #=> "const.rb", found in A (ancestor)
B.autoload?(:CONST, false)   #=> nil, not found in B itself
class_eval(строка [, имя_файла [, номер_строки]]) → объект
class_eval {|модуль| блок } → объект

Вычисляет строку или блок в контексте модуля, за исключением того, что при использовании блока поиск констант/классовых переменных не затрагивается. Это может быть использовано для добавления методов к классу. module_eval возвращает результат вычисления своего аргумента. Необязательные параметры имя_файла и номер_строки устанавливают текст для сообщений об ошибках.

class Thing
end
a = %q{def hello() "Hello there!" end}
Thing.module_eval(a)
puts Thing.new.hello()
Thing.module_eval("invalid code", "dummy", 123)

результат:

Hello there!
dummy:123:in `module_eval': undefined local variable
    or method `code' for Thing:Class
Псевдоним для: module_eval
class_exec(арг...) {|переменная...| блок } → объект

Вычисляет заданный блок в контексте класса/модуля. Метод, определённый в блоке, будет принадлежать получателю. Любые аргументы, переданные методу, будут переданы блоку. Это может быть использовано, если блоку нужно получить доступ к переменным экземпляра.

class Thing
end
Thing.class_exec{
  def hello() "Hello there!" end
}
puts Thing.new.hello()

результат:

Hello there!
Псевдоним для: module_exec
class_variable_defined?(символ) → истина или ложь
class_variable_defined?(строка) → истина или ложь
Исходный код
static VALUE
rb_mod_cvar_defined(VALUE obj, VALUE iv)
{
    ID id = id_for_var(obj, iv, class);

    if (!id) {
        return Qfalse;
    }
    return rb_cvar_defined(obj, id);
}

Возвращает true , если заданная переменная класса определена в объекте. String аргументы преобразуются в символы.

class Fred
  @@foo = 99
end
Fred.class_variable_defined?(:@@foo)    #=> true
Fred.class_variable_defined?(:@@bar)    #=> false
class_variable_get(символ) → объект
class_variable_get(строка) → объект
Исходный код
static VALUE
rb_mod_cvar_get(VALUE obj, VALUE iv)
{
    ID id = id_for_var(obj, iv, class);

    if (!id) {
        rb_name_err_raise("uninitialized class variable %1$s in %2$s",
                          obj, iv);
    }
    return rb_cvar_get(obj, id);
}

Возвращает значение заданной переменной класса (или вызывает исключение NameError). Часть имени переменной, относящаяся к классу, должна быть включена для обычных переменных класса. String аргументы преобразуются в символы.

class Fred
  @@foo = 99
end
Fred.class_variable_get(:@@foo)     #=> 99
class_variable_set(символ, объект) → объект
class_variable_set(строка, объект) → объект
Исходный код
static VALUE
rb_mod_cvar_set(VALUE obj, VALUE iv, VALUE val)
{
    ID id = id_for_var(obj, iv, class);
    if (!id) id = rb_intern_str(iv);
    rb_cvar_set(obj, id, val);
    return val;
}

Устанавливает переменную класса, названную символом, на заданный объект. Если имя переменной класса передано как строка, эта строка преобразуется в символ.

class Fred
  @@foo = 99
  def foo
    @@foo
  end
end
Fred.class_variable_set(:@@foo, 101)     #=> 101
Fred.new.foo                             #=> 101
class_variables(наследовать=истина) → массив
Исходный код
VALUE
rb_mod_class_variables(int argc, const VALUE *argv, VALUE mod)
{
    bool inherit = true;
    st_table *tbl;

    if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
    if (inherit) {
        tbl = mod_cvar_of(mod, 0);
    }
    else {
        tbl = mod_cvar_at(mod, 0);
    }
    return cvar_list(tbl);
}

Возвращает массив имён переменных класса в модуле. Включает имена переменных класса во всех включённых модулях, если параметр наследовать не установлен в false.

class One
  @@var1 = 1
end
class Two < One
  @@var2 = 2
end
One.class_variables          #=> [:@@var1]
Two.class_variables          #=> [:@@var2, :@@var1]
Two.class_variables(false)   #=> [:@@var2]
END_OF_DOCUMENT_MARKER
const_defined?(sym, inherit=true) → true или false
const_defined?(str, inherit=true) → true или false
Исходный код
static VALUE
rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)
{
    VALUE name, recur;
    rb_encoding *enc;
    const char *pbeg, *p, *path, *pend;
    ID id;

    rb_check_arity(argc, 1, 2);
    name = argv[0];
    recur = (argc == 1) ? Qtrue : argv[1];

    if (SYMBOL_P(name)) {
        if (!rb_is_const_sym(name)) goto wrong_name;
        id = rb_check_id(&name);
        if (!id) return Qfalse;
        return RTEST(recur) ? rb_const_defined(mod, id) : rb_const_defined_at(mod, id);
    }

    path = StringValuePtr(name);
    enc = rb_enc_get(name);

    if (!rb_enc_asciicompat(enc)) {
        rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
    }

    pbeg = p = path;
    pend = path + RSTRING_LEN(name);

    if (p >= pend || !*p) {
        goto wrong_name;
    }

    if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
        mod = rb_cObject;
        p += 2;
        pbeg = p;
    }

    while (p < pend) {
        VALUE part;
        long len, beglen;

        while (p < pend && *p != ':') p++;

        if (pbeg == p) goto wrong_name;

        id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
        beglen = pbeg-path;

        if (p < pend && p[0] == ':') {
            if (p + 2 >= pend || p[1] != ':') goto wrong_name;
            p += 2;
            pbeg = p;
        }

        if (!id) {
            part = rb_str_subseq(name, beglen, len);
            OBJ_FREEZE(part);
            if (!rb_is_const_name(part)) {
                name = part;
                goto wrong_name;
            }
            else {
                return Qfalse;
            }
        }
        if (!rb_is_const_id(id)) {
            name = ID2SYM(id);
            goto wrong_name;
        }

#if 0
        mod = rb_const_search(mod, id, beglen > 0 || !RTEST(recur), RTEST(recur), FALSE);
        if (UNDEF_P(mod)) return Qfalse;
#else
        if (!RTEST(recur)) {
            if (!rb_const_defined_at(mod, id))
                return Qfalse;
            if (p == pend) return Qtrue;
            mod = rb_const_get_at(mod, id);
        }
        else if (beglen == 0) {
            if (!rb_const_defined(mod, id))
                return Qfalse;
            if (p == pend) return Qtrue;
            mod = rb_const_get(mod, id);
        }
        else {
            if (!rb_const_defined_from(mod, id))
                return Qfalse;
            if (p == pend) return Qtrue;
            mod = rb_const_get_from(mod, id);
        }
#endif

        if (p < pend && !RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
            rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
                     QUOTE(name));
        }
    }

    return Qtrue;

  wrong_name:
    rb_name_err_raise(wrong_constant_name, mod, name);
    UNREACHABLE_RETURN(Qundef);
}

Определяет, содержит ли mod или его предки константу с заданным именем:

Float.const_defined?(:EPSILON)      #=> true, found in Float itself
Float.const_defined?("String")      #=> true, found in Object (ancestor)
BasicObject.const_defined?(:Hash)   #=> false

Если mod является Module, дополнительно проверяются Object и его предки:

Math.const_defined?(:String)   #=> true, found in Object

В каждом из проверяемых классов или модулей, если константа отсутствует, но для неё есть автоматическое подключение, true возвращается непосредственно без автоматического подключения:

module Admin
  autoload :User, 'admin/user'
end
Admin.const_defined?(:User)   #=> true

Если константа не найдена, обратный вызов const_missing не вызывается, и метод возвращает false.

Если inherit равно false, поиск выполняется только в получателе:

IO.const_defined?(:SYNC)          #=> true, found in File::Constants (ancestor)
IO.const_defined?(:SYNC, false)   #=> false, not found in IO itself

В этом случае применяется та же логика автоматической загрузки.

Если аргумент не является допустимым именем константы, генерируется NameError с сообщением «неверное имя константы имя»:

Hash.const_defined? 'foobar'   #=> NameError: wrong constant name foobar
const_get(sym, inherit=true) → obj
const_get(str, inherit=true) → obj
Исходный код
static VALUE
rb_mod_const_get(int argc, VALUE *argv, VALUE mod)
{
    VALUE name, recur;
    rb_encoding *enc;
    const char *pbeg, *p, *path, *pend;
    ID id;

    rb_check_arity(argc, 1, 2);
    name = argv[0];
    recur = (argc == 1) ? Qtrue : argv[1];

    if (SYMBOL_P(name)) {
        if (!rb_is_const_sym(name)) goto wrong_name;
        id = rb_check_id(&name);
        if (!id) return rb_const_missing(mod, name);
        return RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id);
    }

    path = StringValuePtr(name);
    enc = rb_enc_get(name);

    if (!rb_enc_asciicompat(enc)) {
        rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
    }

    pbeg = p = path;
    pend = path + RSTRING_LEN(name);

    if (p >= pend || !*p) {
        goto wrong_name;
    }

    if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
        mod = rb_cObject;
        p += 2;
        pbeg = p;
    }

    while (p < pend) {
        VALUE part;
        long len, beglen;

        while (p < pend && *p != ':') p++;

        if (pbeg == p) goto wrong_name;

        id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
        beglen = pbeg-path;

        if (p < pend && p[0] == ':') {
            if (p + 2 >= pend || p[1] != ':') goto wrong_name;
            p += 2;
            pbeg = p;
        }

        if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
            rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
                     QUOTE(name));
        }

        if (!id) {
            part = rb_str_subseq(name, beglen, len);
            OBJ_FREEZE(part);
            if (!rb_is_const_name(part)) {
                name = part;
                goto wrong_name;
            }
            else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) {
                part = rb_str_intern(part);
                mod = rb_const_missing(mod, part);
                continue;
            }
            else {
                rb_mod_const_missing(mod, part);
            }
        }
        if (!rb_is_const_id(id)) {
            name = ID2SYM(id);
            goto wrong_name;
        }
#if 0
        mod = rb_const_get_0(mod, id, beglen > 0 || !RTEST(recur), RTEST(recur), FALSE);
#else
        if (!RTEST(recur)) {
            mod = rb_const_get_at(mod, id);
        }
        else if (beglen == 0) {
            mod = rb_const_get(mod, id);
        }
        else {
            mod = rb_const_get_from(mod, id);
        }
#endif
    }

    return mod;

  wrong_name:
    rb_name_err_raise(wrong_constant_name, mod, name);
    UNREACHABLE_RETURN(Qundef);
}

Ищет константу с заданным именем в mod. Если inherit установлено, поиск также выполняется в предках (и Object, если mod является Module).

Значение константы возвращается, если определение найдено, иначе генерируется NameError.

Math.const_get(:PI)   #=> 3.14159265358979

Этот метод будет рекурсивно искать имена констант, если указано имя класса с именованным пространством. Например:

module Foo; class Bar; end end
Object.const_get 'Foo::Bar'

Флаг inherit учитывается при каждом поиске. Например:

module Foo
  class Bar
    VAL = 10
  end

  class Baz < Bar; end
end

Object.const_get 'Foo::Baz::VAL'         # => 10
Object.const_get 'Foo::Baz::VAL', false  # => NameError

Если аргумент не является допустимым именем константы, будет возбуждено исключение NameError с предупреждением «неверное имя константы».

Object.const_get 'foobar' #=> NameError: wrong constant name foobar
const_missing(sym) → obj
Исходный код
VALUE
rb_mod_const_missing(VALUE klass, VALUE name)
{
    rb_execution_context_t *ec = GET_EC();
    VALUE ref = ec->private_const_reference;
    rb_vm_pop_cfunc_frame();
    if (ref) {
        ec->private_const_reference = 0;
        rb_name_err_raise("private constant %2$s::%1$s referenced", ref, name);
    }
    uninitialized_constant(klass, name);

    UNREACHABLE_RETURN(Qnil);
}

Вызывается при ссылке на неопределённую константу в mod. Ему передаётся символ для неопределённой константы, и он возвращает значение, которое будет использоваться для этой константы. Например, рассмотрим:

def Foo.const_missing(name)
  name # return the constant name as Symbol
end

Foo::UNDEFINED_CONST    #=> :UNDEFINED_CONST: symbol returned

Как показывает пример выше, const_missing не обязан создавать недостающую константу в mod, хотя это часто побочный эффект. Вызывающая сторона получает возвращаемое значение при срабатывании. Если константа также определена, дальнейшие запросы не попадут в const_missing и вернут сохранённое в константе значение, как обычно. В противном случае const_missing будет вызван снова.

В следующем примере, когда делается ссылка на неопределённую константу, const_missing пытается загрузить файл, путь которого является строчным вариантом имени константы (поэтому предполагается, что класс Fred находится в файле fred.rb). Если он определён как побочный эффект загрузки файла, метод возвращает значение, хранящееся в константе. Это реализует функцию автоматической загрузки, похожую на Kernel#autoload и Module#autoload, хотя она отличается важными способами.

def Object.const_missing(name)
  @looked_for ||= {}
  str_name = name.to_s
  raise "Constant not found: #{name}" if @looked_for[str_name]
  @looked_for[str_name] = 1
  file = str_name.downcase
  require file
  const_get(name, false)
end
const_set(sym, obj) → obj
const_set(str, obj) → obj
Исходный код
static VALUE
rb_mod_const_set(VALUE mod, VALUE name, VALUE value)
{
    ID id = id_for_var(mod, name, const);
    if (!id) id = rb_intern_str(name);
    rb_const_set(mod, id, value);

    return value;
}

Устанавливает заданную константу в указанный объект, возвращая этот объект. Создаёт новую константу, если константа с данным именем ранее не существовала.

Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0)   #=> 3.14285714285714
Math::HIGH_SCHOOL_PI - Math::PI              #=> 0.00126448926734968

Если sym или str не являются допустимым именем константы, будет возбуждено исключение NameError с предупреждением «неверное имя константы».

Object.const_set('foobar', 42) #=> NameError: wrong constant name foobar
const_source_location(sym, inherit=true) → [Строка, Целое число]
const_source_location(str, inherit=true) → [Строка, Целое число]
Исходный код
static VALUE
rb_mod_const_source_location(int argc, VALUE *argv, VALUE mod)
{
    VALUE name, recur, loc = Qnil;
    rb_encoding *enc;
    const char *pbeg, *p, *path, *pend;
    ID id;

    rb_check_arity(argc, 1, 2);
    name = argv[0];
    recur = (argc == 1) ? Qtrue : argv[1];

    if (SYMBOL_P(name)) {
        if (!rb_is_const_sym(name)) goto wrong_name;
        id = rb_check_id(&name);
        if (!id) return Qnil;
        return RTEST(recur) ? rb_const_source_location(mod, id) : rb_const_source_location_at(mod, id);
    }

    path = StringValuePtr(name);
    enc = rb_enc_get(name);

    if (!rb_enc_asciicompat(enc)) {
        rb_raise(rb_eArgError, "invalid class path encoding (non ASCII)");
    }

    pbeg = p = path;
    pend = path + RSTRING_LEN(name);

    if (p >= pend || !*p) {
        goto wrong_name;
    }

    if (p + 2 < pend && p[0] == ':' && p[1] == ':') {
        mod = rb_cObject;
        p += 2;
        pbeg = p;
    }

    while (p < pend) {
        VALUE part;
        long len, beglen;

        while (p < pend && *p != ':') p++;

        if (pbeg == p) goto wrong_name;

        id = rb_check_id_cstr(pbeg, len = p-pbeg, enc);
        beglen = pbeg-path;

        if (p < pend && p[0] == ':') {
            if (p + 2 >= pend || p[1] != ':') goto wrong_name;
            p += 2;
            pbeg = p;
        }

        if (!id) {
            part = rb_str_subseq(name, beglen, len);
            OBJ_FREEZE(part);
            if (!rb_is_const_name(part)) {
                name = part;
                goto wrong_name;
            }
            else {
                return Qnil;
            }
        }
        if (!rb_is_const_id(id)) {
            name = ID2SYM(id);
            goto wrong_name;
        }
        if (p < pend) {
            if (RTEST(recur)) {
                mod = rb_const_get(mod, id);
            }
            else {
                mod = rb_const_get_at(mod, id);
            }
            if (!RB_TYPE_P(mod, T_MODULE) && !RB_TYPE_P(mod, T_CLASS)) {
                rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
                         QUOTE(name));
            }
        }
        else {
            if (RTEST(recur)) {
                loc = rb_const_source_location(mod, id);
            }
            else {
                loc = rb_const_source_location_at(mod, id);
            }
            break;
        }
        recur = Qfalse;
    }

    return loc;

  wrong_name:
    rb_name_err_raise(wrong_constant_name, mod, name);
    UNREACHABLE_RETURN(Qundef);
}

Возвращает имя файла Ruby и номер строки, содержащие определение указанной константы. Если константа с заданным именем не найдена, возвращается nil. Если константа найдена, но её местоположение в источнике не может быть извлечено (константа определена в коде C), возвращается пустой массив.

inherit указывает, следует ли искать в предках mod.ancestors (true по умолчанию).

# test.rb:
class A         # line 1
  C1 = 1
  C2 = 2
end

module M        # line 6
  C3 = 3
end

class B < A     # line 10
  include M
  C4 = 4
end

class A # continuation of A definition
  C2 = 8 # constant redefinition; warned yet allowed
end

p B.const_source_location('C4')           # => ["test.rb", 12]
p B.const_source_location('C3')           # => ["test.rb", 7]
p B.const_source_location('C1')           # => ["test.rb", 2]

p B.const_source_location('C3', false)    # => nil  -- don't lookup in ancestors

p A.const_source_location('C2')           # => ["test.rb", 16] -- actual (last) definition place

p Object.const_source_location('B')       # => ["test.rb", 10] -- top-level constant could be looked through Object
p Object.const_source_location('A')       # => ["test.rb", 1] -- class reopening is NOT considered new definition

p B.const_source_location('A')            # => ["test.rb", 1]  -- because Object is in ancestors
p M.const_source_location('A')            # => ["test.rb", 1]  -- Object is not ancestor, but additionally checked for modules

p Object.const_source_location('A::C1')   # => ["test.rb", 2]  -- nesting is supported
p Object.const_source_location('String')  # => []  -- constant is defined in C code
constants(inherit=true) → массив
Исходный код
VALUE
rb_mod_constants(int argc, const VALUE *argv, VALUE mod)
{
    bool inherit = true;

    if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);

    if (inherit) {
        return rb_const_list(rb_mod_const_of(mod, 0));
    }
    else {
        return rb_local_constants(mod);
    }
}

Возвращает массив имён констант, доступных в mod. Это включает имена констант во всех включённых модулях (пример в начале раздела), если параметр inherit не установлен в false.

Реализация не гарантирует порядок, в котором константы будут возвращены.

IO.constants.include?(:SYNC)        #=> true
IO.constants(false).include?(:SYNC) #=> false

См. также Module#const_defined?.

define_method(symbol, method) → symbol
define_method(symbol) { block } → symbol
Исходный код
static VALUE
rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
{
    const rb_cref_t *cref = rb_vm_cref_in_context(mod, mod);
    const rb_scope_visibility_t default_scope_visi = {METHOD_VISI_PUBLIC, FALSE};
    const rb_scope_visibility_t *scope_visi = &default_scope_visi;

    if (cref) {
        scope_visi = CREF_SCOPE_VISI(cref);
    }

    return rb_mod_define_method_with_visibility(argc, argv, mod, scope_visi);
}

Определяет метод экземпляра в получателе. Параметр method может быть Proc, Method или объектом UnboundMethod. Если указан блок, он используется в качестве тела метода. Если блок или параметр method имеют параметры, они используются как параметры метода. Этот блок оценивается с использованием instance_eval.

class A
  def fred
    puts "In Fred"
  end
  def create_method(name, &block)
    self.class.define_method(name, &block)
  end
  define_method(:wilma) { puts "Charge it!" }
  define_method(:flint) {|name| puts "I'm #{name}!"}
end
class B < A
  define_method(:barney, instance_method(:fred))
end
a = B.new
a.barney
a.wilma
a.flint('Dino')
a.create_method(:betty) { p self }
a.betty

результат:

In Fred
Charge it!
I'm Dino!
#<B:0x401b39e8>
deprecate_constant(symbol, ...) → mod
Исходный код
VALUE
rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj)
{
    set_const_visibility(obj, argc, argv, CONST_DEPRECATED, CONST_DEPRECATED);
    return obj;
}

Делает список существующих констант устаревшими. Попытка сослаться на них выведет предупреждение.

module HTTP
  NotFound = Exception.new
  NOT_FOUND = NotFound # previous version of the library used this name

  deprecate_constant :NOT_FOUND
end

HTTP::NOT_FOUND
# warning: constant HTTP::NOT_FOUND is deprecated
freeze → mod
Исходный код
static VALUE
rb_mod_freeze(VALUE mod)
{
    rb_class_name(mod);
    return rb_obj_freeze(mod);
}

Запрещает дальнейшие изменения в mod.

Этот метод возвращает self.

END_OF_DOCUMENT_MARKER
include(module, ...) → self
Исходный код
static VALUE
rb_mod_include(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id_append_features, id_included;

    CONST_ID(id_append_features, "append_features");
    CONST_ID(id_included, "included");

    if (BUILTIN_TYPE(module) == T_MODULE && FL_TEST(module, RMODULE_IS_REFINEMENT)) {
        rb_raise(rb_eTypeError, "Refinement#include has been removed");
    }

    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 include refinement");
        }
    }
    while (argc--) {
        rb_funcall(argv[argc], id_append_features, 1, module);
        rb_funcall(argv[argc], id_included, 1, module);
    }
    return module;
}

Вызывает Module.append_features для каждого параметра в обратном порядке.

include?(module) → true или false
Исходный код
VALUE
rb_mod_include_p(VALUE mod, VALUE mod2)
{
    VALUE p;

    Check_Type(mod2, T_MODULE);
    for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
        if (BUILTIN_TYPE(p) == T_ICLASS && !FL_TEST(p, RICLASS_IS_ORIGIN)) {
            if (METACLASS_OF(p) == mod2) return Qtrue;
        }
    }
    return Qfalse;
}

Возвращает true, если module включён или добавлен в начало в mod или одном из предков mod.

module A
end
class B
  include A
end
class C < B
end
B.include?(A)   #=> true
C.include?(A)   #=> true
A.include?(A)   #=> false
included_modules → массив
Исходный код
VALUE
rb_mod_included_modules(VALUE mod)
{
    VALUE ary = rb_ary_new();
    VALUE p;
    VALUE origin = RCLASS_ORIGIN(mod);

    for (p = RCLASS_SUPER(mod); p; p = RCLASS_SUPER(p)) {
        if (p != origin && RCLASS_ORIGIN(p) == p && BUILTIN_TYPE(p) == T_ICLASS) {
            VALUE m = METACLASS_OF(p);
            if (RB_TYPE_P(m, T_MODULE))
                rb_ary_push(ary, m);
        }
    }
    return ary;
}

Возвращает список модулей, включённых или добавленных в начало в mod или одном из предков mod.

module Sub
end

module Mixin
  prepend Sub
end

module Outer
  include Mixin
end

Mixin.included_modules   #=> [Sub]
Outer.included_modules   #=> [Sub, Mixin]
inspect
Псевдоним для: to_s
instance_method(symbol) → unbound_method
Исходный код
static VALUE
rb_mod_instance_method(VALUE mod, VALUE vid)
{
    ID id = rb_check_id(&vid);
    if (!id) {
        rb_method_name_error(mod, vid);
    }
    return mnew_unbound(mod, id, rb_cUnboundMethod, FALSE);
}

Возвращает UnboundMethod, представляющий заданный метод экземпляра в mod.

class Interpreter
  def do_a() print "there, "; end
  def do_d() print "Hello ";  end
  def do_e() print "!\n";     end
  def do_v() print "Dave";    end
  Dispatcher = {
    "a" => instance_method(:do_a),
    "d" => instance_method(:do_d),
    "e" => instance_method(:do_e),
    "v" => instance_method(:do_v)
  }
  def interpret(string)
    string.each_char {|b| Dispatcher[b].bind(self).call }
  end
end

interpreter = Interpreter.new
interpreter.interpret('dave')

выводит:

Hello there, Dave!
instance_methods(include_super=true) → массив
Исходный код
VALUE
rb_class_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
    return class_instance_method_list(argc, argv, mod, 0, ins_methods_i);
}

Возвращает массив, содержащий имена публичных и защищённых методов экземпляра в получателе. Для модуля это публичные и защищённые методы; для класса это методы экземпляра (не одиночные). Если необязательный параметр равен false, методы предков не включаются.

module A
  def method1()  end
end
class B
  include A
  def method2()  end
end
class C < B
  def method3()  end
end

A.instance_methods(false)                   #=> [:method1]
B.instance_methods(false)                   #=> [:method2]
B.instance_methods(true).include?(:method1) #=> true
C.instance_methods(false)                   #=> [:method3]
C.instance_methods.include?(:method2)       #=> true

Обратите внимание, что изменения видимости методов в текущем классе, а также псевдонимы, рассматриваются этим методом как методы текущего класса:

class C < B
  alias method4 method2
  protected :method2
end
C.instance_methods(false).sort               #=> [:method2, :method3, :method4]
method_defined?(symbol, inherit=true) → true или false
method_defined?(string, inherit=true) → true или false
Исходный код
static VALUE
rb_mod_method_defined(int argc, VALUE *argv, VALUE mod)
{
    rb_method_visibility_t visi = check_definition_visibility(mod, argc, argv);
    return RBOOL(visi == METHOD_VISI_PUBLIC || visi == METHOD_VISI_PROTECTED);
}

Возвращает true, если именованный метод определён mod. Если inherit установлено, поиск также будет производиться в предках mod. Соответствуют публичные и защищённые методы. Аргументы типа String преобразуются в символы.

module A
  def method1()  end
  def protected_method1()  end
  protected :protected_method1
end
class B
  def method2()  end
  def private_method2()  end
  private :private_method2
end
class C < B
  include A
  def method3()  end
end

A.method_defined? :method1              #=> true
C.method_defined? "method1"             #=> true
C.method_defined? "method2"             #=> true
C.method_defined? "method2", true       #=> true
C.method_defined? "method2", false      #=> false
C.method_defined? "method3"             #=> true
C.method_defined? "protected_method1"   #=> true
C.method_defined? "method4"             #=> false
C.method_defined? "private_method2"     #=> false
module_eval(string [, filename [, lineno]]) → obj
module_eval {|mod| block } → obj
Исходный код
static VALUE
rb_mod_module_eval_internal(int argc, const VALUE *argv, VALUE mod)
{
    return specific_eval(argc, argv, mod, FALSE, RB_PASS_CALLED_KEYWORDS);
}

Вычисляет строку или блок в контексте mod, за исключением случая, когда задан блок, поиск констант/переменных класса не влияет. Это может использоваться для добавления методов в класс. module_eval возвращает результат вычисления своего аргумента. Необязательные параметры filename и lineno задают текст для сообщений об ошибках.

class Thing
end
a = %q{def hello() "Hello there!" end}
Thing.module_eval(a)
puts Thing.new.hello()
Thing.module_eval("invalid code", "dummy", 123)

выводит:

Hello there!
dummy:123:in `module_eval': undefined local variable
    or method `code' for Thing:Class
Также алиасирован как: class_eval
module_exec(arg...) {|var...| block } → obj
Исходный код
static VALUE
rb_mod_module_exec_internal(int argc, const VALUE *argv, VALUE mod)
{
    return yield_under(mod, FALSE, argc, argv, RB_PASS_CALLED_KEYWORDS);
}

Вычисляет заданный блок в контексте класса/модуля. Метод, определённый в блоке, будет принадлежать получателю. Любые аргументы, переданные методу, будут переданы в блок. Это может использоваться, если блоку нужно получить доступ к переменным экземпляра.

class Thing
end
Thing.class_exec{
  def hello() "Hello there!" end
}
puts Thing.new.hello()

выводит:

Hello there!
Также алиасирован как: class_exec
name → строка или nil
Исходный код
VALUE
rb_mod_name(VALUE mod)
{
    // YJIT needs this function to not allocate.
    bool permanent;
    return classname(mod, &permanent);
}

Возвращает имя модуля mod. Возвращает nil для анонимных модулей.

prepend(module, ...) → self
Исходный код
static VALUE
rb_mod_prepend(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id_prepend_features, id_prepended;

    if (BUILTIN_TYPE(module) == T_MODULE && FL_TEST(module, RMODULE_IS_REFINEMENT)) {
        rb_raise(rb_eTypeError, "Refinement#prepend has been removed");
    }

    CONST_ID(id_prepend_features, "prepend_features");
    CONST_ID(id_prepended, "prepended");

    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 prepend refinement");
        }
    }
    while (argc--) {
        rb_funcall(argv[argc], id_prepend_features, 1, module);
        rb_funcall(argv[argc], id_prepended, 1, module);
    }
    return module;
}

Вызывает Module.prepend_features для каждого параметра в обратном порядке.

private_class_method(symbol, ...) → mod
private_class_method(string, ...) → mod
private_class_method(array) → mod
Исходный код
static VALUE
rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
{
    set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PRIVATE);
    return obj;
}

Делает существующие методы класса закрытыми. Часто используется для скрытия конструктора по умолчанию new.

String аргументы преобразуются в символы. Также принимается массив Array символов и/или строк.

class SimpleSingleton  # Not thread safe
  private_class_method :new
  def SimpleSingleton.create(*args, &block)
    @me = new(*args, &block) if ! @me
    @me
  end
end
private_constant(symbol, ...) → mod
Исходный код
VALUE
rb_mod_private_constant(int argc, const VALUE *argv, VALUE obj)
{
    set_const_visibility(obj, argc, argv, CONST_PRIVATE, CONST_VISIBILITY_MASK);
    return obj;
}

Делает список существующих констант закрытыми.

private_instance_methods(include_super=true) → массив
Исходный код
VALUE
rb_class_private_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
    return class_instance_method_list(argc, argv, mod, 0, ins_methods_priv_i);
}

Возвращает список закрытых методов экземпляра, определённых в mod. Если необязательный параметр равен false, методы предков не включаются.

module Mod
  def method1()  end
  private :method1
  def method2()  end
end
Mod.instance_methods           #=> [:method2]
Mod.private_instance_methods   #=> [:method1]
END_OF_DOCUMENT_MARKER
private_method_defined?(символ, inherit=true) → true или false
private_method_defined?(строка, inherit=true) → true или false
Исходный код
static VALUE
rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
{
    return check_definition(mod, argc, argv, METHOD_VISI_PRIVATE);
}

Возвращает значение true, если указанный закрытый метод определён в mod. Если inherit установлено, поиск также будет производиться в предках mod. String аргументы преобразуются в символы.

module A
  def method1()  end
end
class B
  private
  def method2()  end
end
class C < B
  include A
  def method3()  end
end

A.method_defined? :method1                   #=> true
C.private_method_defined? "method1"          #=> false
C.private_method_defined? "method2"          #=> true
C.private_method_defined? "method2", true    #=> true
C.private_method_defined? "method2", false   #=> false
C.method_defined? "method2"                  #=> false
protected_instance_methods(include_super=true) → массив
Исходный код
VALUE
rb_class_protected_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
    return class_instance_method_list(argc, argv, mod, 0, ins_methods_prot_i);
}

Возвращает список защищённых методов экземпляра, определённых в mod. Если необязательный параметр равен false, методы предков не включаются.

protected_method_defined?(символ, inherit=true) → true или false
protected_method_defined?(строка, inherit=true) → true или false
Исходный код
static VALUE
rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
{
    return check_definition(mod, argc, argv, METHOD_VISI_PROTECTED);
}

Возвращает true, если указанный защищённый метод определён в mod. Если inherit установлено, поиск также будет производиться в предках mod. String аргументы преобразуются в символы.

module A
  def method1()  end
end
class B
  protected
  def method2()  end
end
class C < B
  include A
  def method3()  end
end

A.method_defined? :method1                    #=> true
C.protected_method_defined? "method1"         #=> false
C.protected_method_defined? "method2"         #=> true
C.protected_method_defined? "method2", true   #=> true
C.protected_method_defined? "method2", false  #=> false
C.method_defined? "method2"                   #=> true
public_class_method(символ, ...) → mod
public_class_method(строка, ...) → mod
public_class_method(массив) → mod
Исходный код
static VALUE
rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
{
    set_method_visibility(rb_singleton_class(obj), argc, argv, METHOD_VISI_PUBLIC);
    return obj;
}

Делает список существующих методов класса публичными.

String аргументы преобразуются в символы. Также принимается Array символов и/или строк.

public_constant(символ, ...) → mod
Исходный код
VALUE
rb_mod_public_constant(int argc, const VALUE *argv, VALUE obj)
{
    set_const_visibility(obj, argc, argv, CONST_PUBLIC, CONST_VISIBILITY_MASK);
    return obj;
}

Делает список существующих констант публичными.

public_instance_method(символ) → unbound_method
Исходный код
static VALUE
rb_mod_public_instance_method(VALUE mod, VALUE vid)
{
    ID id = rb_check_id(&vid);
    if (!id) {
        rb_method_name_error(mod, vid);
    }
    return mnew_unbound(mod, id, rb_cUnboundMethod, TRUE);
}

Аналогично instance_method, ищет только публичные методы.

public_instance_methods(include_super=true) → массив
Исходный код
VALUE
rb_class_public_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
    return class_instance_method_list(argc, argv, mod, 0, ins_methods_pub_i);
}

Возвращает список публичных методов экземпляра, определённых в mod. Если необязательный параметр равен false, методы предков не включаются.

public_method_defined?(символ, inherit=true) → true или false
public_method_defined?(строка, inherit=true) → true или false
Исходный код
static VALUE
rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
{
    return check_definition(mod, argc, argv, METHOD_VISI_PUBLIC);
}

Возвращает true, если указанный публичный метод определён в mod. Если inherit установлено, поиск также будет производиться в предках mod. String аргументы преобразуются в символы.

module A
  def method1()  end
end
class B
  protected
  def method2()  end
end
class C < B
  include A
  def method3()  end
end

A.method_defined? :method1                 #=> true
C.public_method_defined? "method1"         #=> true
C.public_method_defined? "method1", true   #=> true
C.public_method_defined? "method1", false  #=> true
C.public_method_defined? "method2"         #=> false
C.method_defined? "method2"                #=> true
refinements → массив
Исходный код
static VALUE
mod_refinements(VALUE self)
{
    ID id_refinements;
    VALUE refinements;

    CONST_ID(id_refinements, "__refinements__");
    refinements = rb_attr_get(self, id_refinements);
    if (NIL_P(refinements)) {
        return rb_ary_new();
    }
    return rb_hash_values(refinements);
}

Возвращает массив Refinement определённых внутри получателя.

module A
  refine Integer do
  end

  refine String do
  end
end

p A.refinements

вывод:

[#<refinement:Integer@A>, #<refinement:String@A>]
remove_class_variable(символ) → обьект
Исходный код
VALUE
rb_mod_remove_cvar(VALUE mod, VALUE name)
{
    const ID id = id_for_var_message(mod, name, class, "wrong class variable name %1$s");
    st_data_t val;

    if (!id) {
        goto not_defined;
    }
    rb_check_frozen(mod);
    val = rb_ivar_delete(mod, id, Qundef);
    if (!UNDEF_P(val)) {
        return (VALUE)val;
    }
    if (rb_cvar_defined(mod, id)) {
        rb_name_err_raise("cannot remove %1$s for %2$s", mod, ID2SYM(id));
    }
  not_defined:
    rb_name_err_raise("class variable %1$s not defined for %2$s",
                      mod, name);
    UNREACHABLE_RETURN(Qundef);
}

Удаляет указанную переменную класса из получателя, возвращая значение этой переменной.

class Example
  @@var = 99
  puts remove_class_variable(:@@var)
  p(defined? @@var)
end

вывод:

99
nil
remove_method(символ) → self
remove_method(строка) → self
Исходный код
static VALUE
rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
{
    int i;

    for (i = 0; i < argc; i++) {
        VALUE v = argv[i];
        ID id = rb_check_id(&v);
        if (!id) {
            rb_name_err_raise("method '%1$s' not defined in %2$s",
                              mod, v);
        }
        remove_method(mod, id);
    }
    return mod;
}

Удаляет метод, идентифицируемый символом, из текущего класса. Пример см. в Module#undef_method. String аргументы преобразуются в символы.

set_temporary_name(строка) → self
set_temporary_name(null) → self
Исходный код
VALUE
rb_mod_set_temporary_name(VALUE mod, VALUE name)
{
    // We don't allow setting the name if the classpath is already permanent:
    if (RCLASS_EXT(mod)->permanent_classpath) {
        rb_raise(rb_eRuntimeError, "can't change permanent name");
    }

    if (NIL_P(name)) {
        // Set the temporary classpath to NULL (anonymous):
        RCLASS_SET_CLASSPATH(mod, 0, FALSE);
    }
    else {
        // Ensure the name is a string:
        StringValue(name);

        if (RSTRING_LEN(name) == 0) {
            rb_raise(rb_eArgError, "empty class/module name");
        }

        if (is_constant_path(name)) {
            rb_raise(rb_eArgError, "the temporary name must not be a constant path to avoid confusion");
        }

        // Set the temporary classpath to the given name:
        RCLASS_SET_CLASSPATH(mod, name, FALSE);
    }

    return mod;
}

Устанавливает временное имя модуля. Это имя отображается в интроспекции модуля и связанных с ним значениях, таких как экземпляры, константы и методы.

Имя должно быть nil или непустой строкой, которая не является допустимым путём для константы (чтобы избежать путаницы между постоянными и временными именами).

Метод может быть полезен для различения динамически генерируемых классов и модулей без их назначения константам.

Если модулю присвоено постоянное имя путём присваивания его константе, временное имя отбрасывается. Временное имя не может быть присвоено модулям, имеющим постоянное имя.

Если заданное имя равно nil, модуль снова становится анонимным.

Пример:

m = Module.new # => #<Module:0x0000000102c68f38>
m.name #=> nil

m.set_temporary_name("fake_name") # => fake_name
m.name #=> "fake_name"

m.set_temporary_name(nil) # => #<Module:0x0000000102c68f38>
m.name #=> nil

c = Class.new
c.set_temporary_name("MyClass(with description)")

c.new # => #<MyClass(with description):0x0....>

c::M = m
c::M.name #=> "MyClass(with description)::M"

# Assigning to a constant replaces the name with a permanent one
C = c

C.name #=> "C"
C::M.name #=> "C::M"
c.new # => #<C:0x0....>
singleton_class? → true или false
Исходный код
static VALUE
rb_mod_singleton_p(VALUE klass)
{
    return RBOOL(RCLASS_SINGLETON_P(klass));
}

Возвращает значение true, если mod — это синглтон-класс, или false, если это обычный класс или модуль.

class C
end
C.singleton_class?                  #=> false
C.singleton_class.singleton_class?  #=> true
to_s → строка
Исходный код
VALUE
rb_mod_to_s(VALUE klass)
{
    ID id_defined_at;
    VALUE refined_class, defined_at;

    if (RCLASS_SINGLETON_P(klass)) {
        VALUE s = rb_usascii_str_new2("#<Class:");
        VALUE v = RCLASS_ATTACHED_OBJECT(klass);

        if (CLASS_OR_MODULE_P(v)) {
            rb_str_append(s, rb_inspect(v));
        }
        else {
            rb_str_append(s, rb_any_to_s(v));
        }
        rb_str_cat2(s, ">");

        return s;
    }
    refined_class = rb_refinement_module_get_refined_class(klass);
    if (!NIL_P(refined_class)) {
        VALUE s = rb_usascii_str_new2("#<refinement:");

        rb_str_concat(s, rb_inspect(refined_class));
        rb_str_cat2(s, "@");
        CONST_ID(id_defined_at, "__defined_at__");
        defined_at = rb_attr_get(klass, id_defined_at);
        rb_str_concat(s, rb_inspect(defined_at));
        rb_str_cat2(s, ">");
        return s;
    }
    return rb_class_name(klass);
}

Возвращает строку, представляющую этот модуль или класс. Для базовых классов и модулей это имя. Для синглтонов отображается информация о том, к чему мы прикреплены.

Также алиасирован как: inspect
undef_method(символ) → self
undef_method(строка) → self
Исходный код
static VALUE
rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
{
    int i;
    for (i = 0; i < argc; i++) {
        VALUE v = argv[i];
        ID id = rb_check_id(&v);
        if (!id) {
            rb_method_name_error(mod, v);
        }
        rb_undef(mod, id);
    }
    return mod;
}

Предотвращает ответ текущего класса на вызовы именованного метода. В отличие от remove_method, который удаляет метод из конкретного класса; Ruby по-прежнему будет искать возможного получателя в суперклассах и смешанных модулях. String аргументы преобразуются в символы.

class Parent
  def hello
    puts "In parent"
  end
end
class Child < Parent
  def hello
    puts "In child"
  end
end

c = Child.new
c.hello

class Child
  remove_method :hello  # remove from child, still in parent
end
c.hello

class Child
  undef_method :hello   # prevent any calls to 'hello'
end
c.hello

результат:

In child
In parent
prog.rb:23: undefined method 'hello' for #<Child:0x401b3bb4> (NoMethodError)
undefined_instance_methods → массив
Исходный код
VALUE
rb_class_undefined_instance_methods(VALUE mod)
{
    VALUE include_super = Qfalse;
    return class_instance_method_list(1, &include_super, mod, 0, ins_methods_undef_i);
}

Возвращает список неопределённых методов экземпляров, определённых в mod. Неопределённые методы предков не включаются.

Методы экземпляра (private)

append_features(mod) → mod
Исходный код
static VALUE
rb_mod_append_features(VALUE module, VALUE include)
{
    if (!CLASS_OR_MODULE_P(include)) {
        Check_Type(include, T_CLASS);
    }
    rb_include_module(include, module);

    return module;
}

Когда этот модуль включается в другой, Ruby вызывает append_features в этом модуле, передавая ему получающий модуль в mod. По умолчанию Ruby добавляет константы, методы и переменные модуля этого модуля в mod, если этот модуль ещё не был добавлен в mod или один из его предков. См. также Module#include.

const_added(const_name)
Исходный код
#define rb_obj_mod_const_added rb_obj_dummy1

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

module Chatty
  def self.const_added(const_name)
    super
    puts "Added #{const_name.inspect}"
  end
  FOO = 1
end

возвращает:

Added :FOO
extend_object(obj) → obj
Исходный код
static VALUE
rb_mod_extend_object(VALUE mod, VALUE obj)
{
    rb_extend_object(obj, mod);
    return obj;
}

Расширяет указанный объект, добавляя константы и методы этого модуля (которые добавляются как методы-синглетоны). Это метод обратного вызова, используемый Object#extend.

module Picky
  def Picky.extend_object(o)
    if String === o
      puts "Can't add Picky to a String"
    else
      puts "Picky added to #{o.class}"
      super
    end
  end
end
(s = Array.new).extend Picky  # Call Object.extend
(s = "quick brown fox").extend Picky

возвращает:

Picky added to Array
Can't add Picky to a String
extended(othermod)
Исходный код
#define rb_obj_mod_extended rb_obj_dummy1

Эквивалент included, но для расширенных модулей.

module A
  def self.extended(mod)
    puts "#{self} extended in #{mod}"
  end
end
module Enumerable
  extend A
end
 # => prints "A extended in Enumerable"
included(othermod)
Исходный код
#define rb_obj_mod_included rb_obj_dummy1

Обратный вызов, вызываемый всякий раз, когда получатель включается в другой модуль или класс. Это следует использовать вместо Module.append_features, если ваш код хочет выполнить какое-либо действие, когда модуль включается в другой.

module A
  def A.included(mod)
    puts "#{self} included in #{mod}"
  end
end
module Enumerable
  include A
end
 # => prints "A included in Enumerable"
method_added(method_name)
Исходный код
#define rb_obj_mod_method_added rb_obj_dummy1

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

module Chatty
  def self.method_added(method_name)
    puts "Adding #{method_name.inspect}"
  end
  def self.some_class_method() end
  def some_instance_method() end
end

возвращает:

Adding :some_instance_method
method_removed(method_name)
Исходный код
#define rb_obj_mod_method_removed rb_obj_dummy1

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

module Chatty
  def self.method_removed(method_name)
    puts "Removing #{method_name.inspect}"
  end
  def self.some_class_method() end
  def some_instance_method() end
  class << self
    remove_method :some_class_method
  end
  remove_method :some_instance_method
end

возвращает:

Removing :some_instance_method
method_undefined(method_name)
Исходный код
#define rb_obj_mod_method_undefined rb_obj_dummy1

Вызывается как обратный вызов всякий раз, когда метод экземпляра не определён для получателя.

module Chatty
  def self.method_undefined(method_name)
    puts "Undefining #{method_name.inspect}"
  end
  def self.some_class_method() end
  def some_instance_method() end
  class << self
    undef_method :some_class_method
  end
  undef_method :some_instance_method
end

возвращает:

Undefining :some_instance_method
module_function → nil
module_function(method_name) → method_name
module_function(method_name, method_name, ...) → массив
Исходный код
static VALUE
rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
{
    int i;
    ID id;
    const rb_method_entry_t *me;

    if (!RB_TYPE_P(module, T_MODULE)) {
        rb_raise(rb_eTypeError, "module_function must be called for modules");
    }

    if (argc == 0) {
        rb_scope_module_func_set();
        return Qnil;
    }

    set_method_visibility(module, argc, argv, METHOD_VISI_PRIVATE);

    for (i = 0; i < argc; i++) {
        VALUE m = module;

        id = rb_to_id(argv[i]);
        for (;;) {
            me = search_method(m, id, 0);
            if (me == 0) {
                me = search_method(rb_cObject, id, 0);
            }
            if (UNDEFINED_METHOD_ENTRY_P(me)) {
                rb_print_undef(module, id, METHOD_VISI_UNDEF);
            }
            if (me->def->type != VM_METHOD_TYPE_ZSUPER) {
                break; /* normal case: need not to follow 'super' link */
            }
            m = RCLASS_SUPER(m);
            if (!m)
                break;
        }
        rb_method_entry_set(rb_singleton_class(module), id, me, METHOD_VISI_PUBLIC);
    }
    if (argc == 1) {
        return argv[0];
    }
    return rb_ary_new_from_values(argc, argv);
}

Создаёт методы модуля для указанных методов. Эти методы могут вызываться с модулем в качестве получателя, а также становятся доступными как методы экземпляров для классов, которые включают модуль. Методы модуля являются копиями оригинальных, и поэтому могут быть изменены независимо. Версии методов экземпляров становятся приватными. Если используется без аргументов, все последующие методы становятся методами модуля. Аргументы типа String конвертируются в символы. Если передан один аргумент, он возвращается. Если аргументов нет, возвращается nil. Если передано несколько аргументов, они возвращаются в виде массива.

module Mod
  def one
    "This is one"
  end
  module_function :one
end
class Cls
  include Mod
  def call_one
    one
  end
end
Mod.one     #=> "This is one"
c = Cls.new
c.call_one  #=> "This is one"
module Mod
  def one
    "This is the new one"
  end
end
Mod.one     #=> "This is one"
c.call_one  #=> "This is the new one"
prepend_features(mod) → mod
Исходный код
static VALUE
rb_mod_prepend_features(VALUE module, VALUE prepend)
{
    if (!CLASS_OR_MODULE_P(prepend)) {
        Check_Type(prepend, T_CLASS);
    }
    rb_prepend_module(prepend, module);

    return module;
}

Когда этот модуль предваряет другой, Ruby вызывает prepend_features в этом модуле, передавая ему получающий модуль в mod. По умолчанию Ruby накладывает константы, методы и переменные модуля этого модуля на mod, если этот модуль ещё не добавлен в mod или один из его предков. См. также Module#prepend.

prepended(othermod)
Исходный код
#define rb_obj_mod_prepended rb_obj_dummy1

Эквивалент included, но для предваряющих модулей.

module A
  def self.prepended(mod)
    puts "#{self} prepended to #{mod}"
  end
end
module Enumerable
  prepend A
end
 # => prints "A prepended to Enumerable"
private → nil
private(method_name) → method_name
private(method_name, method_name, ...) → массив
private(массив) → массив
Исходный код
static VALUE
rb_mod_private(int argc, VALUE *argv, VALUE module)
{
    return set_visibility(argc, argv, module, METHOD_VISI_PRIVATE);
}

Без аргументов устанавливает видимость последующих методов по умолчанию как приватные. С аргументами устанавливает приватную видимость для указанных методов. Аргументы типа String преобразуются в символы. Также принимается Array символов и/или строк. Если передан один аргумент, он возвращается. Если аргументов нет, возвращается nil. Если передано несколько аргументов, они возвращаются в виде массива.

module Mod
  def a()  end
  def b()  end
  private
  def c()  end
  private :a
end
Mod.private_instance_methods   #=> [:a, :c]

Для отображения приватного метода в RDoc используйте :doc:.

protected → nil
protected(имя_метода) → имя_метода
protected(имя_метода, имя_метода, ...) → массив
protected(массив) → массив
Исходный код
static VALUE
rb_mod_protected(int argc, VALUE *argv, VALUE module)
{
    return set_visibility(argc, argv, module, METHOD_VISI_PROTECTED);
}

Без аргументов устанавливает видимость по умолчанию для последующих методов как protected. С аргументами устанавливает видимость указанных методов как protected. Аргументы типа String преобразуются в символы. Также принимается Array символов и/или строк. Если передан один аргумент, он возвращается. Если аргументов нет, возвращается nil. Если передано несколько аргументов, они возвращаются в виде массива.

Если метод имеет protected видимость, он вызывается только там, где self контекста совпадает с методом. (определение метода или instance_eval). Это поведение отличается от protected метода в Java. Обычно self следует использовать.

Обратите внимание, что protected метод медленнее, потому что он не может использовать кэш.

Чтобы показать закрытый метод на RDoc, используйте :doc: вместо этого.

public → nil
public(имя_метода) → имя_метода
public(имя_метода, имя_метода, ...) → массив
public(массив) → массив
Исходный код
static VALUE
rb_mod_public(int argc, VALUE *argv, VALUE module)
{
    return set_visibility(argc, argv, module, METHOD_VISI_PUBLIC);
}

Без аргументов устанавливает видимость по умолчанию для последующих методов как public. С аргументами устанавливает видимость указанных методов как public. Аргументы типа String преобразуются в символы. Также принимается Array символов и/или строк. Если передан один аргумент, он возвращается. Если аргументов нет, возвращается nil. Если передано несколько аргументов, они возвращаются в виде массива.

refine(мод) { блок } → модуль
Исходный код
static VALUE
rb_mod_refine(VALUE module, VALUE klass)
{
    VALUE refinement;
    ID id_refinements, id_activated_refinements,
       id_refined_class, id_defined_at;
    VALUE refinements, activated_refinements;
    rb_thread_t *th = GET_THREAD();
    VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);

    if (block_handler == VM_BLOCK_HANDLER_NONE) {
        rb_raise(rb_eArgError, "no block given");
    }
    if (vm_block_handler_type(block_handler) != block_handler_type_iseq) {
        rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine");
    }

    ensure_class_or_module(klass);
    CONST_ID(id_refinements, "__refinements__");
    refinements = rb_attr_get(module, id_refinements);
    if (NIL_P(refinements)) {
        refinements = hidden_identity_hash_new();
        rb_ivar_set(module, id_refinements, refinements);
    }
    CONST_ID(id_activated_refinements, "__activated_refinements__");
    activated_refinements = rb_attr_get(module, id_activated_refinements);
    if (NIL_P(activated_refinements)) {
        activated_refinements = hidden_identity_hash_new();
        rb_ivar_set(module, id_activated_refinements,
                    activated_refinements);
    }
    refinement = rb_hash_lookup(refinements, klass);
    if (NIL_P(refinement)) {
        VALUE superclass = refinement_superclass(klass);
        refinement = rb_refinement_new();
        RCLASS_SET_SUPER(refinement, superclass);
        RUBY_ASSERT(BUILTIN_TYPE(refinement) == T_MODULE);
        FL_SET(refinement, RMODULE_IS_REFINEMENT);
        CONST_ID(id_refined_class, "__refined_class__");
        rb_ivar_set(refinement, id_refined_class, klass);
        CONST_ID(id_defined_at, "__defined_at__");
        rb_ivar_set(refinement, id_defined_at, module);
        rb_hash_aset(refinements, klass, refinement);
        add_activated_refinement(activated_refinements, klass, refinement);
    }
    rb_yield_refine_block(refinement, activated_refinements);
    return refinement;
}

Уточнить мод в приемнике.

Возвращает модуль, где определены уточнённые методы.

remove_const(символ) → обьект
Исходный код
VALUE
rb_mod_remove_const(VALUE mod, VALUE name)
{
    const ID id = id_for_var(mod, name, a, constant);

    if (!id) {
        undefined_constant(mod, name);
    }
    return rb_const_remove(mod, id);
}

Удаляет определение заданной константы, возвращая предыдущее значение этой константы. Если эта константа ссылалась на модуль, это не изменит имя этого модуля и может привести к путанице.

ruby2_keywords(имя_метода, ...) → nil
Исходный код
static VALUE
rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module)
{
    int i;
    VALUE origin_class = RCLASS_ORIGIN(module);

    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
    rb_check_frozen(module);

    for (i = 0; i < argc; i++) {
        VALUE v = argv[i];
        ID name = rb_check_id(&v);
        rb_method_entry_t *me;
        VALUE defined_class;

        if (!name) {
            rb_print_undef_str(module, v);
        }

        me = search_method(origin_class, name, &defined_class);
        if (!me && RB_TYPE_P(module, T_MODULE)) {
            me = search_method(rb_cObject, name, &defined_class);
        }

        if (UNDEFINED_METHOD_ENTRY_P(me) ||
            UNDEFINED_REFINED_METHOD_P(me->def)) {
            rb_print_undef(module, name, METHOD_VISI_UNDEF);
        }

        if (module == defined_class || origin_class == defined_class) {
            switch (me->def->type) {
              case VM_METHOD_TYPE_ISEQ:
                if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest &&
                        !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw &&
                        !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) {
                    ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1;
                    rb_clear_method_cache(module, name);
                }
                else {
                    rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
                }
                break;
              case VM_METHOD_TYPE_BMETHOD: {
                VALUE procval = me->def->body.bmethod.proc;
                if (vm_block_handler_type(procval) == block_handler_type_proc) {
                    procval = vm_proc_to_block_handler(VM_BH_TO_PROC(procval));
                }

                if (vm_block_handler_type(procval) == block_handler_type_iseq) {
                    const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval);
                    const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
                    if (ISEQ_BODY(iseq)->param.flags.has_rest &&
                            !ISEQ_BODY(iseq)->param.flags.has_kw &&
                            !ISEQ_BODY(iseq)->param.flags.has_kwrest) {
                        ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1;
                        rb_clear_method_cache(module, name);
                    }
                    else {
                        rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name));
                    }
                    break;
                }
              }
              /* fallthrough */
              default:
                rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method not defined in Ruby)", QUOTE_ID(name));
                break;
            }
        }
        else {
            rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (can only set in method defining module)", QUOTE_ID(name));
        }
    }
    return Qnil;
}

Для заданных имён методов помечает метод как передающий ключевые слова через обычное аргументное разброс. Это должно вызываться только для методов, которые принимают аргументное разброс (*args) но не явные ключевые слова или ключевое разброс. Он помечает метод так, что если метод вызывается с ключевыми аргументами, конечный аргумент-словарь отмечается специальным флагом, таким образом, если он является последним элементом обычного аргументного разброса другому вызову метода, и этот вызов метода не включает явные ключевые слова или ключевой разброс, последний элемент интерпретируется как ключевые слова. Другими словами, ключевые слова будут передаваться через метод другим методам.

Это следует использовать только для методов, которые делегируют ключевые слова другому методу, и только для обратной совместимости с версиями Ruby до 3.0. Смотрите www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/ для получения подробной информации о том, почему ruby2_keywords существует, когда и как его использовать.

Этот метод, вероятно, будет удалён в какой-то момент, так как он существует только для обратной совместимости. Так как он не существует в версиях Ruby до 2.7, убедитесь, что модуль отвечает на этот метод перед его вызовом:

module Mod
  def foo(meth, *args, &block)
    send(:"do_#{meth}", *args, &block)
  end
  ruby2_keywords(:foo) if respond_to?(:ruby2_keywords, true)
end

Однако, будьте осторожны, что если метод ruby2_keywords будет удалён, поведение метода foo с использованием вышеуказанного подхода изменится так, что метод не будет передавать ключевые слова.

using(модуль) → self
Исходный код
static VALUE
mod_using(VALUE self, VALUE module)
{
    rb_control_frame_t *prev_cfp = previous_frame(GET_EC());

    if (prev_frame_func()) {
        rb_raise(rb_eRuntimeError,
                 "Module#using is not permitted in methods");
    }
    if (prev_cfp && prev_cfp->self != self) {
        rb_raise(rb_eRuntimeError, "Module#using is not called on self");
    }
    if (rb_block_given_p()) {
        ignored_block(module, "Module#");
    }
    rb_using_module(rb_vm_cref_replace_with_duplicated_cref(), module);
    return self;
}

Импортирует уточнения классов из модуля в текущее определение класса или модуля.

Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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