Spec-Zone.ru › Ruby 4.0

класс Module

Родительский класс:
Object

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

В последующих описаниях параметр sym обозначает символ, который представляет собой строку в кавычках или 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 → array Показать исходный код
constants(inherited) → array
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 → array Показать исходный код
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 → mod Показать исходный код
new {|mod| block } → 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 → array Показать исходный код
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 → array Показать исходный код
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>]

Открытые методы экземпляра

self < other → true, false, or nil Показать исходный код
static VALUE
rb_mod_lt(VALUE mod, VALUE arg)
{
    if (mod == arg) return Qfalse;
    return rb_class_inherited_p(mod, arg);
}

Возвращает, является ли self подклассом other, или nil, если эти классы не связаны:

Float < Numeric # => true
Numeric < Float # => false
Float < Float   # => false
Float < Hash    # => nil
mod <= other → true, false, or 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».)

self <=> other → -1, 0, 1, or 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);
}

Сравнивает self и other.

Возвращает:

  • -1, если self включает other, если или self является подклассом other.

  • 0, если self и other совпадают.

  • 1, если other включает self или если other является подклассом self.

  • nil, если ни одно из вышеперечисленных условий не выполняется.

Примеры:

# Class Array includes module Enumerable.
         Array <=> Enumerable # => -1
    Enumerable <=> Enumerable # =>  0
    Enumerable <=> Array      # =>  1
# Class File is a subclass of class IO.
          File <=> IO         # => -1
          File <=> File       # =>  0
            IO <=> File       # =>  1
# Class File has no relationship to class String.
          File <=> String     # => nil
obj == other → true or false Показать исходный код
equal?(other) → true or false
eql?(other) → true or false
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
    return RBOOL(obj1 == obj2);
}

Равенство — на уровне Object метод == возвращает true только в том случае, если obj и other являются одним и тем же объектом. Обычно этот метод переопределяется в классах-потомках, чтобы задать значение, специфичное для класса.

В отличие от ==, метод equal? никогда не следует переопределять в подклассах, поскольку он используется для определения идентичности объектов (то есть a.equal?(b) тогда и только тогда, когда a является тем же объектом, что и b):

obj = "a"
other = obj.dup

obj == other      #=> true
obj.equal? other  #=> false
obj.equal? obj    #=> true

Метод eql? возвращает true, если obj и other относятся к одному и тому же ключу хеша. Метод используется в Hash для проверки равенства элементов. Для любой пары объектов, для которой eql? возвращает true, значения hash обоих объектов должны быть равны. Поэтому любой подкласс, переопределяющий eql?, должен также соответствующим образом переопределить hash.

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

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

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

mod > other → true, false, or 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 или является потомком other. Возвращает nil, если эти классы не связаны. (Рассматривайте связь в терминах определения класса: «class A < B» подразумевает «B > A».)

mod >= other → true, false, or 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) → symbol Показать исходный код
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 → array Показать исходный код
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, ...) → array Показать исходный код
attr(name, true) → array
attr(name, false) → array
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(symbol, ...) → array Показать исходный код
attr_accessor(string, ...) → array
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;
}

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

module Mod
  attr_accessor(:one, :two) #=> [:one, :one=, :two, :two=]
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]
attr_reader(symbol, ...) → array Показать исходный код
attr(symbol, ...) → array
attr_reader(string, ...) → array
attr(string, ...) → array
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:name» для каждого имени. Аргументы типа String преобразуются в символы. Возвращает массив имен определенных методов в виде символов.

attr_writer(symbol, ...) → array Показать исходный код
attr_writer(string, ...) → array
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;
}

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

autoload(const, filename) → nil Показать исходный код
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;
}

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

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

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

Файлы, которые в данный момент загружаются, нельзя регистрировать для автозагрузки.

autoload?(name, inherit=true) → String or nil Показать исходный код
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);
}

Возвращает filename для загрузки, если name зарегистрировано как autoload в пространстве имен mod или одного из его предков.

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

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

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(string [, filename [, lineno]]) → obj
class_eval {|mod| block } → obj

Вычисляет строку или блок в контексте 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
Псевдоним для: module_eval
class_exec(arg...) {|var...| block } → obj

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

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

результат:

Hello there!
Псевдоним для: module_exec
class_variable_defined?(symbol) → true or false Показать исходный код
class_variable_defined?(string) → true or false
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, если данная переменная класса определена в obj. Аргументы типа String преобразуются в символы.

class Fred
  @@foo = 99
end
Fred.class_variable_defined?(:@@foo)    #=> true
Fred.class_variable_defined?(:@@bar)    #=> false
class_variable_get(symbol) → obj Показать исходный код
class_variable_get(string) → obj
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(symbol, obj) → obj Показать исходный код
class_variable_set(string, obj) → obj
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;
}

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

class Fred
  @@foo = 99
  def foo
    @@foo
  end
end
Fred.class_variable_set(:@@foo, 101)     #=> 101
Fred.new.foo                             #=> 101
class_variables(inherit=true) → array Показать исходный код
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);
}

Возвращает массив имен переменных класса в mod. В него входят имена переменных класса из всех включенных модулей, если только параметр inherit не установлен в 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]
const_defined?(sym, inherit=true) → true or false Показать исходный код
const_defined?(str, inherit=true) → true or 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 с сообщением «wrong constant name name»:

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 с предупреждением «wrong constant name».

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 с предупреждением «wrong constant name».

Object.const_set('foobar', 42) #=> NameError: wrong constant name foobar
const_source_location(sym, inherit=true) → [String, Integer] Показать исходный код
const_source_location(str, inherit=true) → [String, Integer]
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) → array Показать исходный код
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.

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 or 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 && !RICLASS_IS_ORIGIN_P(p)) {
            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 → array Показать исходный код
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) → array Показать исходный код
VALUE
rb_class_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
    return class_instance_method_list(argc, argv, mod, 0, ins_methods_i);
}

Возвращает массив, содержащий имена открытых и защищённых методов экземпляра получателя. Для модуля это открытые и защищённые методы; для класса — методы экземпляра (не singleton-методы). Если необязательный параметр равен 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 or false Показать исходный код
method_defined?(string, inherit=true) → true or 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 → string or 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) → array Показать исходный код
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]
private_method_defined?(symbol, inherit=true) → true or false Показать исходный код
private_method_defined?(string, inherit=true) → true or 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) → array Показать исходный код
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?(symbol, inherit=true) → true or false Показать исходный код
protected_method_defined?(string, inherit=true) → true or 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(symbol, ...) → mod Показать исходный код
public_class_method(string, ...) → mod
public_class_method(array) → 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(symbol, ...) → 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(symbol) → 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) → array Показать исходный код
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?(symbol, inherit=true) → true or false Показать исходный код
public_method_defined?(string, inherit=true) → true or 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 → array Показать исходный код
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(sym) → obj Показать исходный код
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(symbol) → self Показать исходный код
remove_method(string) → 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;
}

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

set_temporary_name(string) → self Показать исходный код
set_temporary_name(nil) → 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_PERMANENT_CLASSPATH_P(mod)) {
        rb_raise(rb_eRuntimeError, "can't change permanent name");
    }

    if (NIL_P(name)) {
        // Set the temporary classpath to NULL (anonymous):
        RB_VM_LOCKING() {
            set_sub_temporary_name(mod, 0);
        }
    }
    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");
        }

        name = rb_str_new_frozen(name);
        RB_OBJ_SET_SHAREABLE(name);

        // Set the temporary classpath to the given name:
        RB_VM_LOCKING() {
            set_sub_temporary_name(mod, name);
        }
    }

    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)") # => 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 or false Показать исходный код
static VALUE
rb_mod_singleton_p(VALUE klass)
{
    return RBOOL(RCLASS_SINGLETON_P(klass));
}

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

class C
end
C.singleton_class?                  #=> false
C.singleton_class.singleton_class?  #=> true
to_s → string Показать исходный код
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);
}

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

Также имеет псевдоним: inspect
undef_method(symbol) → self Показать исходный код
undef_method(string) → 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 → array Показать исходный код
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. Неопределённые методы предков не включаются.

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

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

Если определить класс с помощью ключевого слова class, const_added выполняется до inherited:

module M
  def self.const_added(const_name)
    super
    p :const_added
  end

  parent = Class.new do
    def self.inherited(subclass)
      super
      p :inherited
    end
  end

  class Child < parent
  end
end

результат:

:const_added
:inherited
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, ...) → array
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, ...) → array
private(array) → array
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(method_name) → method_name
protected(method_name, method_name, ...) → array
protected(array) → array
static VALUE
rb_mod_protected(int argc, VALUE *argv, VALUE module)
{
    return set_visibility(argc, argv, module, METHOD_VISI_PROTECTED);
}

Задаёт защищённую видимость для раздела или списка имён методов. Не принимает аргументов, набор имён методов (символов или строк) либо массив имён методов. Возвращает полученные аргументы.

Важное отличие от protected в других языках

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

Объявление метода защищённым позволяет разным объектам одного класса вызывать его.

Один из вариантов использования — методы сравнения, например ==, если нужно предоставить метод для сравнения объектов одного класса, не делая его общедоступным для объектов других классов.

Особенности производительности

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

Пример

class Account
  # Mark balance as protected, so that we can compare between accounts
  # without making it public.
  attr_reader :balance
  protected :balance

  def initialize(balance)
    @balance = balance
  end

  def >(other)
    # The invocation to `other.balance` is allowed because `other` is a
    # different object of the same class (Account).
    balance > other.balance
  end
end

account1 = Account.new(100)
account2 = Account.new(50)

account1 > account2  # => true (works)
account1.balance     # => NoMethodError (fails because balance is not public)

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

public → nil Показать исходный код
public(method_name) → method_name
public(method_name, method_name, ...) → array
public(array) → array
static VALUE
rb_mod_public(int argc, VALUE *argv, VALUE module)
{
    return set_visibility(argc, argv, module, METHOD_VISI_PUBLIC);
}

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

refine(mod) { block } → module Показать исходный код
static VALUE
rb_mod_refine(VALUE module, VALUE klass)
{
    /* module is the receiver of #refine, klass is a module to be refined (`mod` in the doc) */
    rb_thread_t *th = GET_THREAD();
    VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);
    struct rb_refinements_data data;

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

    rb_refinement_setup(&data, module, klass);

    rb_yield_refine_block(data.refinement, data.refinements);
    return data.refinement;
}

Уточняет mod в получателе.

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

remove_const(sym) → obj Показать исходный код
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(method_name, ...) → 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_post &&
                        !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 post arguments 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_post &&
                            !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 post arguments 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. Подробности о причинах существования ruby2_keywords, а также о том, когда и как его использовать, см. на странице www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/.

Вероятно, в какой-то момент этот метод будет удалён, поскольку он существует только для обеспечения обратной совместимости. Так как в версиях 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(module) → 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;
}

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

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

Spec-Zone.ru

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