class Module
Ein Modul ist eine Sammlung von Methoden und Konstanten. Die Methoden in einem Modul können Instanzmethoden oder Modulmethoden sein. Instanzmethoden erscheinen als Methoden in einer Klasse, wenn das Modul inkludiert wird, Modulmethoden nicht. Umgekehrt können Modulmethoden ohne Erstellung eines verkapselnden Objekts aufgerufen werden, Instanzmethoden nicht. (Siehe Module#module_function.)
In den folgenden Beschreibungen bezieht sich der Parameter sym auf ein Symbol, das entweder eine Anführungszeichen-Zeichenkette oder ein Symbol ist (wie z. B. :name).
module Mod include Math CONST = 1 def meth # ... end end Mod.class #=> Module Mod.constants #=> [:CONST, :PI, :E] Mod.instance_methods #=> [:meth]
Öffentliche Klassenmethoden
Source
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);
}
In der ersten Form wird ein Array der Namen aller Konstanten zurückgegeben, auf die vom Aufrufpunkt aus zugegriffen werden kann. Diese Liste enthält die Namen aller Module und Klassen, die im globalen Geltungsbereich definiert sind.
Module.constants.first(4) # => [:ARGF, :ARGV, :ArgumentError, :Array] Module.constants.include?(:SEEK_SET) # => false class IO Module.constants.include?(:SEEK_SET) # => true end
Die zweite Form ruft die Instanzmethode constants auf.
Source
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;
}
Gibt die Liste der im Aufrufpunkt verschachtelten Modules zurück.
module M1 module M2 $a = Module.nesting end end $a #=> [M1::M2, M1] $a[0].name #=> "M1::M2"
Source
static VALUE
rb_mod_initialize(VALUE module)
{
return rb_mod_initialize_exec(module);
}
Erstellt ein neues anonymes Modul. Wenn ein Block übergeben wird, wird ihm das Modulobjekt übergeben, und der Block wird im Kontext dieses Moduls ausgewertet, ähnlich wie bei 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"
Weisen Sie das Modul einer Konstanten zu (Name beginnt mit Großbuchstabe), wenn Sie es wie ein reguläres Modul behandeln möchten.
Source
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);
}
Gibt ein Array aller im aktuellen Geltungsbereich verwendeten Module zurück. Die Reihenfolge der Module im Ergebnisarray ist nicht definiert.
module A refine Object do end end module B refine Object do end end using A using B p Module.used_modules
ergibt
[B, A]
Source
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;
}
Gibt ein Array aller im aktuellen Geltungsbereich verwendeten Module zurück. Die Reihenfolge der Module im Ergebnisarray ist nicht definiert.
module A refine Object do end end module B refine Object do end end using A using B p Module.used_refinements
ergibt
[#<refinement:Object@B>, #<refinement:Object@A>]
Öffentliche Instanzmethoden
Source
static VALUE
rb_mod_lt(VALUE mod, VALUE arg)
{
if (mod == arg) return Qfalse;
return rb_class_inherited_p(mod, arg);
}
Gibt zurück, ob self eine Unterklasse von other ist, oder nil, wenn keine Beziehung zwischen beiden besteht
Float < Numeric # => true Numeric < Float # => false Float < Float # => false Float < Hash # => nil
Source
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;
}
}
Gibt true zurück, wenn mod eine Unterklasse von other ist oder gleich other ist. Gibt nil zurück, wenn keine Beziehung zwischen beiden besteht. (Denken Sie an die Beziehung in Bezug auf die Klassendefinition: „class A < B“ impliziert „A < B“.)
Source
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);
}
Vergleicht self und other.
Gibt zurück
-
-1, wennselfotherinkludiert, wenn oderselfeine Unterklasse vonotherist. -
0, wennselfundothergleich sind. -
1, wennotherselfinkludiert oder wennothereine Unterklasse vonselfist. -
nil, wenn keine der obigen Bedingungen zutrifft.
Beispiele
# 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
Source
VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
return RBOOL(obj1 == obj2);
}
Gleichheit — Auf der Ebene von Object gibt == nur dann true zurück, wenn obj und other dasselbe Objekt sind. Typischerweise wird diese Methode in abgeleiteten Klassen überschrieben, um eine klassenspezifische Bedeutung bereitzustellen.
Im Gegensatz zu == sollte die Methode equal? niemals von Unterklassen überschrieben werden, da sie zur Bestimmung der Objektidentität verwendet wird (d. h. a.equal?(b) genau dann, wenn a dasselbe Objekt wie b ist)
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
Die Methode eql? gibt true zurück, wenn obj und other auf denselben Hash-Schlüssel verweisen. Dies wird von Hash verwendet, um Elemente auf Gleichheit zu prüfen. Für jedes Paar von Objekten, für das eql? true zurückgibt, muss der hash-Wert beider Objekte gleich sein. Jede Unterklasse, die eql? überschreibt, sollte daher auch hash entsprechend überschreiben.
Für Objekte der Klasse Object ist eql? gleichbedeutend mit ==. Unterklassen setzen diese Tradition normalerweise fort, indem sie eql? mit ihrer überschriebenen ==-Methode verknüpfen, aber es gibt Ausnahmen. Numeric-Typen führen beispielsweise Typumwandlungen über == durch, aber nicht über eql?, daher
1 == 1.0 #=> true 1.eql? 1.0 #=> false
Source
static VALUE
rb_mod_eqq(VALUE mod, VALUE arg)
{
return rb_obj_is_kind_of(arg, mod);
}
Fallgleichheit — Gibt true zurück, wenn obj eine Instanz von mod oder eine Instanz eines Nachfolgers von mod ist. Von begrenztem Nutzen für Module, kann aber in case-Anweisungen verwendet werden, um Objekte nach Klasse zu klassifizieren.
Source
static VALUE
rb_mod_gt(VALUE mod, VALUE arg)
{
if (mod == arg) return Qfalse;
return rb_mod_ge(mod, arg);
}
Gibt true zurück, wenn mod ein Vorfahre von other ist. Gibt false zurück, wenn mod dasselbe wie other ist oder wenn mod ein Nachfolger von other ist. Gibt nil zurück, wenn keine Beziehung zwischen beiden besteht. (Denken Sie an die Beziehung in Bezug auf die Klassendefinition: „class A < B“ impliziert „B > A“.)
Source
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);
}
Gibt true zurück, wenn mod ein Vorfahre von other ist oder die beiden Module gleich sind. Gibt nil zurück, wenn keine Beziehung zwischen beiden besteht. (Denken Sie an die Beziehung in Bezug auf die Klassendefinition: „class A < B“ impliziert „B > A“.)
Source
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);
}
Macht new_name zu einer neuen Kopie der Methode old_name. Dies kann verwendet werden, um den Zugriff auf überschriebene Methoden beizubehalten.
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)
ergibt
Exiting with code 99
Source
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;
}
Gibt eine Liste der in mod inkludierten/vorangestellten Module zurück (einschließlich mod selbst).
module Mod include Math include Comparable prepend Enumerable end Mod.ancestors #=> [Enumerable, Mod, Comparable, Math] Math.ancestors #=> [Math] Enumerable.ancestors #=> [Enumerable]
Source
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);
}
Die erste Form ist äquivalent zu attr_reader. Die zweite Form ist äquivalent zu attr_accessor(name), aber veraltet. Die letzte Form ist äquivalent zu attr_reader(name), aber veraltet. Gibt ein Array definierter Methodennamen als Symbole zurück.
Source
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;
}
Definiert ein benanntes Attribut für dieses Modul, wobei der Name symbol.id2name ist, erstellt eine Instanzvariable (@name) und eine entsprechende Zugriffsmethode zum Lesen. Erstellt außerdem eine Methode namens name= zum Setzen des Attributs. String-Argumente werden in Symbole umgewandelt. Gibt ein Array definierter Methodennamen als Symbole zurück.
module Mod attr_accessor(:one, :two) #=> [:one, :one=, :two, :two=] end Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Source
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;
}
Erstellt Instanzvariablen und entsprechende Methoden, die den Wert jeder Instanzvariable zurückgeben. Äquivalent zum Aufruf von „attr:name“ für jeden Namen der Reihe nach. String-Argumente werden in Symbole umgewandelt. Gibt ein Array definierter Methodennamen als Symbole zurück.
Source
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;
}
Erstellt eine Zugriffsmethode, die das Setzen des Attributs symbol.id2name ermöglicht. String-Argumente werden in Symbole umgewandelt. Gibt ein Array definierter Methodennamen als Symbole zurück.
Source
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;
}
Registriert filename zur Ladung (mit Kernel::require) beim ersten Mal, wenn const (das eine String oder ein Symbol sein kann) im Namensraum von mod zugegriffen wird.
module A end A.autoload(:B, "b") A::B.doit # autoloads "b"
Wenn const in mod als autoload definiert ist, wird der zu ladende Dateiname durch filename ersetzt. Wenn const definiert ist, aber nicht als autoload, tut sich nichts.
Dateien, die gerade geladen werden, dürfen nicht für autoload registriert werden.
Source
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);
}
Gibt filename zurück, der geladen werden soll, wenn name im Namensraum von mod oder einem seiner Vorfahren als autoload registriert ist.
module A end A.autoload(:B, "b") A.autoload?(:B) #=> "b"
Wenn inherit false ist, prüft die Suche nur die autoloads im Empfänger.
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
wertet die Zeichenkette oder den Block im Kontext von mod aus, außer dass bei Übergabe eines Blocks die Suche nach Konstanten/Klassenvariablen nicht beeinflusst wird. Dies kann zum Hinzufügen von Methoden zu einer Klasse verwendet werden. module_eval gibt das Ergebnis der Auswertung seines Arguments zurück. Die optionalen Parameter filename und lineno legen den Text für Fehlermeldungen fest.
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)
ergibt
Hello there!
dummy:123:in `module_eval': undefined local variable
or method `code' for Thing:Class
wertet den gegebenen Block im Kontext der Klasse/des Moduls aus. Die im Block definierte Methode gehört dem Empfänger. An das Attribut übergebene Argumente werden an den Block übergeben. Dies kann verwendet werden, wenn der Block auf Instanzvariablen zugreifen muss.
class Thing end Thing.class_exec{ def hello() "Hello there!" end } puts Thing.new.hello()
ergibt
Hello there!
Source
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);
}
Gibt true zurück, wenn die gegebene Klassenvariable in obj definiert ist. String-Argumente werden in Symbole umgewandelt.
class Fred @@foo = 99 end Fred.class_variable_defined?(:@@foo) #=> true Fred.class_variable_defined?(:@@bar) #=> false
Source
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);
}
Source
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;
}
Setzt die durch symbol benannte Klassenvariable auf das gegebene Objekt. Wenn der Klassenvariablenname als Zeichenkette übergeben wird, wird diese Zeichenkette in ein Symbol umgewandelt.
class Fred @@foo = 99 def foo @@foo end end Fred.class_variable_set(:@@foo, 101) #=> 101 Fred.new.foo #=> 101
Source
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);
}
Gibt ein Array der Namen von Klassenvariablen in mod zurück. Dies schließt die Namen von Klassenvariablen in allen inkludierten Modulen ein, es sei denn, der Parameter inherit ist auf false gesetzt.
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]
Source
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);
}
Sagt, ob mod oder seine Vorfahren eine Konstante mit dem gegebenen Namen haben
Float.const_defined?(:EPSILON) #=> true, found in Float itself Float.const_defined?("String") #=> true, found in Object (ancestor) BasicObject.const_defined?(:Hash) #=> false
Wenn mod ein Module ist, werden zusätzlich Object und seine Vorfahren überprüft.
Math.const_defined?(:String) #=> true, found in Object
In jeder der überprüften Klassen oder Module, wenn die Konstante nicht vorhanden ist, aber eine autoload dafür existiert, wird true direkt zurückgegeben, ohne autoload auszulösen.
module Admin autoload :User, 'admin/user' end Admin.const_defined?(:User) #=> true
Wenn die Konstante nicht gefunden wird, wird der Callback const_missing **nicht** aufgerufen und die Methode gibt false zurück.
Wenn inherit false ist, prüft die Suche nur die Konstanten im Empfänger.
IO.const_defined?(:SYNC) #=> true, found in File::Constants (ancestor) IO.const_defined?(:SYNC, false) #=> false, not found in IO itself
In diesem Fall gilt die gleiche Logik für autoload.
Wenn das Argument kein gültiger Konstantenname ist, wird ein NameError mit der Meldung „wrong constant name name“ ausgelöst.
Hash.const_defined? 'foobar' #=> NameError: wrong constant name foobar
Source
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);
}
Prüft auf eine Konstante mit dem gegebenen Namen in mod. Wenn inherit gesetzt ist, durchsucht die Suche auch die Vorfahren von mod (und Object, wenn mod ein Module ist).
Der Wert der Konstante wird zurückgegeben, wenn eine Definition gefunden wird, andernfalls wird eine NameError ausgelöst.
Math.const_get(:PI) #=> 3.14159265358979
Diese Methode sucht rekursiv nach Konstantenamen, wenn ein benannter Klassennamen bereitgestellt wird. Zum Beispiel
module Foo; class Bar; end end Object.const_get 'Foo::Bar'
Das Flag inherit wird bei jeder Suche berücksichtigt. Zum Beispiel
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
Wenn das Argument kein gültiger Konstantenname ist, wird ein NameError mit der Warnung „wrong constant name“ ausgelöst.
Object.const_get 'foobar' #=> NameError: wrong constant name foobar
Source
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);
}
Wird aufgerufen, wenn auf eine undefinierte Konstante in mod verwiesen wird. Ihr wird ein Symbol für die undefinierte Konstante übergeben, und sie gibt einen Wert zurück, der für diese Konstante verwendet wird. Betrachten Sie zum Beispiel
def Foo.const_missing(name) name # return the constant name as Symbol end Foo::UNDEFINED_CONST #=> :UNDEFINED_CONST: symbol returned
Wie das obige Beispiel zeigt, ist const_missing nicht verpflichtet, die fehlende Konstante in mod zu erstellen, obwohl dies oft eine Nebenwirkung ist. Der Aufrufer erhält ihren Rückgabewert, wenn sie ausgelöst wird. Wenn die Konstante auch definiert ist, werden weitere Suchvorgänge const_missing nicht mehr auslösen und wie üblich den in der Konstante gespeicherten Wert zurückgeben. Andernfalls wird const_missing erneut aufgerufen.
Im folgenden Beispiel versucht const_missing beim Verweis auf eine undefinierte Konstante, eine Datei zu laden, deren Pfad die Kleinbuchstabenversion des Konstantennamens ist (wodurch die Klasse Fred in der Datei fred.rb angenommen wird). Wenn die Methode als Nebenwirkung des Ladens der Datei definiert ist, gibt sie den in der Konstante gespeicherten Wert zurück. Dies implementiert eine autoload-Funktionalität ähnlich wie Kernel#autoload und Module#autoload, unterscheidet sich jedoch in wichtigen Punkten.
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
Source
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;
}
Setzt die benannte Konstante auf das gegebene Objekt und gibt dieses Objekt zurück. Erstellt eine neue Konstante, wenn zuvor keine Konstante mit dem gegebenen Namen existierte.
Math.const_set("HIGH_SCHOOL_PI", 22.0/7.0) #=> 3.14285714285714 Math::HIGH_SCHOOL_PI - Math::PI #=> 0.00126448926734968
Wenn sym oder str kein gültiger Konstantenname ist, wird ein NameError mit der Warnung „wrong constant name“ ausgelöst.
Object.const_set('foobar', 42) #=> NameError: wrong constant name foobar
Source
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);
}
Gibt den Ruby-Quellcode-Dateinamen und die Zeilennummer zurück, die die Definition der angegebenen Konstante enthalten. Wenn die benannte Konstante nicht gefunden wird, wird nil zurückgegeben. Wenn die Konstante gefunden wird, aber ihre Quellcode-Position nicht extrahiert werden kann (die Konstante ist in C-Code definiert), wird ein leeres Array zurückgegeben.
inherit gibt an, ob in mod.ancestors gesucht werden soll (standardmäßig 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
Source
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);
}
}
Gibt ein Array der Namen der in mod zugänglichen Konstanten zurück. Dies schließt die Namen von Konstanten in allen inkludierten Modulen ein (Beispiel am Anfang des Abschnitts), es sei denn, der Parameter inherit ist auf false gesetzt.
Die Implementierung macht keine Garantien bezüglich der Reihenfolge, in der die Konstanten übergeben werden.
IO.constants.include?(:SYNC) #=> true IO.constants(false).include?(:SYNC) #=> false
Siehe auch Module#const_defined?.
Source
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);
}
Definiert eine Instanzmethode im Empfänger. Der Parameter method kann ein Proc, eine Method oder ein UnboundMethod-Objekt sein. Wenn ein Block angegeben ist, wird er als Methodenrumpf verwendet. Wenn ein Block oder der Parameter method Parameter hat, werden diese als Methodenparameter verwendet. Dieser Block wird mit instance_eval ausgewertet.
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
ergibt
In Fred Charge it! I'm Dino! #<B:0x401b39e8>
Source
VALUE
rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj)
{
set_const_visibility(obj, argc, argv, CONST_DEPRECATED, CONST_DEPRECATED);
return obj;
}
Macht eine Liste vorhandener Konstanten veraltet. Der Versuch, auf sie zuzugreifen, erzeugt eine Warnung.
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
Source
static VALUE
rb_mod_freeze(VALUE mod)
{
rb_class_name(mod);
return rb_obj_freeze(mod);
}
Verhindert weitere Änderungen an mod.
Diese Methode gibt self zurück.
Source
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;
}
Ruft Module.append_features für jeden Parameter in umgekehrter Reihenfolge auf.
Source
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;
}
Gibt true zurück, wenn module in mod oder einem der Vorfahren von mod inkludiert oder vorangestellt ist.
module A end class B include A end class C < B end B.include?(A) #=> true C.include?(A) #=> true A.include?(A) #=> false
Source
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;
}
Gibt die Liste der Module zurück, die in mod oder einem der Vorfahren von mod inkludiert oder vorangestellt sind.
module Sub end module Mixin prepend Sub end module Outer include Mixin end Mixin.included_modules #=> [Sub] Outer.included_modules #=> [Sub, Mixin]
Source
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);
}
Gibt eine UnboundMethod zurück, die die gegebene Instanzmethode in mod darstellt.
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')
ergibt
Hello there, Dave!
Source
VALUE
rb_class_instance_methods(int argc, const VALUE *argv, VALUE mod)
{
return class_instance_method_list(argc, argv, mod, 0, ins_methods_i);
}
Gibt ein Array zurück, das die Namen der öffentlichen und geschützten Instanzmethoden im Empfänger enthält. Für ein Modul sind dies die öffentlichen und geschützten Methoden; für eine Klasse sind es die Instanzmethoden (nicht Singleton-Methoden). Wenn der optionale Parameter false ist, werden die Methoden von Vorfahren nicht berücksichtigt.
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
Beachten Sie, dass Sichtbarkeitsänderungen von Methoden in der aktuellen Klasse sowie Aliase als Methoden der aktuellen Klasse von dieser Methode betrachtet werden.
class C < B alias method4 method2 protected :method2 end C.instance_methods(false).sort #=> [:method2, :method3, :method4]
Source
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);
}
Gibt true zurück, wenn die benannte Methode von mod definiert ist. Wenn inherit gesetzt ist, durchsucht die Suche auch die Vorfahren von mod. Öffentliche und geschützte Methoden werden abgeglichen. String-Argumente werden in Symbole umgewandelt.
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
Source
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);
}
wertet die Zeichenkette oder den Block im Kontext von mod aus, außer dass bei Übergabe eines Blocks die Suche nach Konstanten/Klassenvariablen nicht beeinflusst wird. Dies kann zum Hinzufügen von Methoden zu einer Klasse verwendet werden. module_eval gibt das Ergebnis der Auswertung seines Arguments zurück. Die optionalen Parameter filename und lineno legen den Text für Fehlermeldungen fest.
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)
ergibt
Hello there!
dummy:123:in `module_eval': undefined local variable
or method `code' for Thing:Class
Source
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);
}
wertet den gegebenen Block im Kontext der Klasse/des Moduls aus. Die im Block definierte Methode gehört dem Empfänger. An das Attribut übergebene Argumente werden an den Block übergeben. Dies kann verwendet werden, wenn der Block auf Instanzvariablen zugreifen muss.
class Thing end Thing.class_exec{ def hello() "Hello there!" end } puts Thing.new.hello()
ergibt
Hello there!
Source
VALUE
rb_mod_name(VALUE mod)
{
// YJIT needs this function to not allocate.
bool permanent;
return classname(mod, &permanent);
}
Gibt den Namen des Moduls mod zurück. Für anonyme Module wird nil zurückgegeben.
Source
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;
}
Ruft Module.prepend_features für jeden Parameter in umgekehrter Reihenfolge auf.
Source
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;
}
Macht vorhandene Klassenmethoden privat. Wird oft verwendet, um den Standardkonstruktor new zu verbergen.
String-Argumente werden in Symbole umgewandelt. Es wird auch ein Array von Symbolen und/oder Zeichenketten akzeptiert.
class SimpleSingleton # Not thread safe private_class_method :new def SimpleSingleton.create(*args, &block) @me = new(*args, &block) if ! @me @me end end
Source
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;
}
Macht eine Liste vorhandener Konstanten privat.
Source
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);
}
Gibt eine Liste der privaten Instanzmethoden zurück, die in mod definiert sind. Wenn der optionale Parameter false ist, werden die Methoden von Vorfahren nicht berücksichtigt.
module Mod def method1() end private :method1 def method2() end end Mod.instance_methods #=> [:method2] Mod.private_instance_methods #=> [:method1]
Source
static VALUE
rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
{
return check_definition(mod, argc, argv, METHOD_VISI_PRIVATE);
}
Gibt true zurück, wenn die benannte private Methode von mod definiert ist. Wenn inherit gesetzt ist, durchsucht die Suche auch die Vorfahren von mod. String-Argumente werden in Symbole umgewandelt.
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
Source
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);
}
Gibt eine Liste der geschützten Instanzmethoden zurück, die in mod definiert sind. Wenn der optionale Parameter false ist, werden die Methoden von Vorfahren nicht berücksichtigt.
Source
static VALUE
rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
{
return check_definition(mod, argc, argv, METHOD_VISI_PROTECTED);
}
Gibt true zurück, wenn die benannte geschützte Methode von mod definiert ist. Wenn inherit gesetzt ist, durchsucht die Suche auch die Vorfahren von mod. String-Argumente werden in Symbole umgewandelt.
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
Source
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;
}
Source
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;
}
Macht eine Liste vorhandener Konstanten öffentlich.
Source
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);
}
Ähnlich wie instance_method, durchsucht nur öffentliche Methoden.
Source
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);
}
Gibt eine Liste der öffentlichen Instanzmethoden zurück, die in mod definiert sind. Wenn der optionale Parameter false ist, werden die Methoden von Vorfahren nicht berücksichtigt.
Source
static VALUE
rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
{
return check_definition(mod, argc, argv, METHOD_VISI_PUBLIC);
}
Gibt true zurück, wenn die benannte öffentliche Methode von mod definiert ist. Wenn inherit gesetzt ist, durchsucht die Suche auch die Vorfahren von mod. String-Argumente werden in Symbole umgewandelt.
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
Source
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);
}
Gibt ein Array von Refinement zurück, die innerhalb des Empfängers definiert sind.
module A refine Integer do end refine String do end end p A.refinements
ergibt
[#<refinement:Integer@A>, #<refinement:String@A>]
Source
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);
}
Entfernt die benannte Klassenvariable aus dem Empfänger und gibt den Wert dieser Variablen zurück.
class Example @@var = 99 puts remove_class_variable(:@@var) p(defined? @@var) end
ergibt
99 nil
Source
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;
}
Entfernt die durch symbol identifizierte Methode aus der aktuellen Klasse. Ein Beispiel finden Sie unter Module#undef_method. String-Argumente werden in Symbole umgewandelt.
Source
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;
}
Setzt den temporären Namen des Moduls. Dieser Name spiegelt sich in der Introspektion des Moduls und den zugehörigen Werten wie Instanzen, Konstanten und Methoden wider.
Der Name sollte nil oder eine nicht leere Zeichenkette sein, die kein gültiger Pfad zu einer Konstanten ist (um Verwechslungen zwischen permanenten und temporären Namen zu vermeiden).
Die Methode kann nützlich sein, um dynamisch generierte Klassen und Module zu unterscheiden, ohne ihnen Konstanten zuzuweisen.
Wenn dem Modul durch Zuweisung zu einer Konstanten ein permanenter Name zugewiesen wird, wird der temporäre Name verworfen. Ein temporärer Name kann Modulen nicht zugewiesen werden, die einen permanenten Namen haben.
Wenn der angegebene Name nil ist, wird das Modul wieder anonym.
Beispiel
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....>
Source
static VALUE
rb_mod_singleton_p(VALUE klass)
{
return RBOOL(RCLASS_SINGLETON_P(klass));
}
Gibt true zurück, wenn mod eine Singleton-Klasse ist, oder false, wenn es sich um eine gewöhnliche Klasse oder ein Modul handelt.
class C end C.singleton_class? #=> false C.singleton_class.singleton_class? #=> true
Source
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);
}
Gibt eine Zeichenkette zurück, die dieses Modul oder diese Klasse darstellt. Für grundlegende Klassen und Module ist dies der Name. Für Singletons zeigen wir Informationen über das Ding an, an das sie angehängt sind.
Source
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;
}
Verhindert, dass die aktuelle Klasse auf Aufrufe der benannten Methode reagiert. Im Gegensatz zu remove_method, das die Methode aus der jeweiligen Klasse löscht; Ruby durchsucht weiterhin Oberklassen und gemischte Module nach einem möglichen Empfänger. String-Argumente werden in Symbole umgewandelt.
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
ergibt
In child In parent prog.rb:23: undefined method 'hello' for #<Child:0x401b3bb4> (NoMethodError)
Source
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);
}
Gibt eine Liste der undefinierten Instanzmethoden zurück, die in mod definiert sind. Die undefinierten Methoden von Vorfahren sind nicht enthalten.
Private Instanzmethoden
Source
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;
}
Wenn dieses Modul in ein anderes inkludiert wird, ruft Ruby append_features in diesem Modul auf und übergibt ihm das empfangende Modul in mod. Die Standardimplementierung von Ruby besteht darin, die Konstanten, Methoden und Modulvariablen dieses Moduls zu mod hinzuzufügen, wenn dieses Modul noch nicht zu mod oder einem seiner Vorfahren hinzugefügt wurde. Siehe auch Module#include.
Source
#define rb_obj_mod_const_added rb_obj_dummy1
Wird als Callback aufgerufen, wann immer eine Konstante auf dem Empfänger zugewiesen wird.
module Chatty def self.const_added(const_name) super puts "Added #{const_name.inspect}" end FOO = 1 end
ergibt
Added :FOO
Wenn wir eine Klasse mit dem Schlüsselwort class definieren, wird const_added vor inherited ausgeführt.
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
ergibt
:const_added :inherited
Source
static VALUE
rb_mod_extend_object(VALUE mod, VALUE obj)
{
rb_extend_object(obj, mod);
return obj;
}
Erweitert das angegebene Objekt, indem die Konstanten und Methoden dieses Moduls hinzugefügt werden (die als Singleton-Methoden hinzugefügt werden). Dies ist die Callback-Methode, die von Object#extend verwendet wird.
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
ergibt
Picky added to Array Can't add Picky to a String
Source
#define rb_obj_mod_extended rb_obj_dummy1
Das Äquivalent zu included, aber für erweiterte Module.
module A def self.extended(mod) puts "#{self} extended in #{mod}" end end module Enumerable extend A end # => prints "A extended in Enumerable"
Source
#define rb_obj_mod_included rb_obj_dummy1
Callback, der aufgerufen wird, wenn der Empfänger in ein anderes Modul oder eine andere Klasse inkludiert wird. Dies sollte bevorzugt vor Module.append_features verwendet werden, wenn Ihr Code eine Aktion ausführen möchte, wenn ein Modul in ein anderes inkludiert wird.
module A def A.included(mod) puts "#{self} included in #{mod}" end end module Enumerable include A end # => prints "A included in Enumerable"
Source
#define rb_obj_mod_method_added rb_obj_dummy1
Wird als Callback aufgerufen, wann immer eine Instanzmethode zum Empfänger hinzugefügt wird.
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
ergibt
Adding :some_instance_method
Source
#define rb_obj_mod_method_removed rb_obj_dummy1
Wird als Callback aufgerufen, wann immer eine Instanzmethode vom Empfänger entfernt wird.
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
ergibt
Removing :some_instance_method
Source
#define rb_obj_mod_method_undefined rb_obj_dummy1
Wird als Callback aufgerufen, wann immer eine Instanzmethode vom Empfänger undefiniert wird.
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
ergibt
Undefining :some_instance_method
Source
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);
}
Erzeugt Modulfunktionen für die benannten Methoden. Diese Funktionen können mit dem Modul als Empfänger aufgerufen werden und werden auch als Instanzmethoden für Klassen verfügbar, die das Modul mischen. Modulfunktionen sind Kopien des Originals und können daher unabhängig voneinander geändert werden. Die Instanzmethodenversionen werden privat gemacht. Wenn mit keinen Argumenten verwendet, werden nachfolgend definierte Methoden zu Modulfunktionen. String-Argumente werden in Symbole umgewandelt. Wenn ein einzelnes Argument übergeben wird, wird es zurückgegeben. Wenn kein Argument übergeben wird, wird nil zurückgegeben. Wenn mehrere Argumente übergeben werden, werden die Argumente als Array zurückgegeben.
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"
Source
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;
}
Wenn dieses Modul in ein anderes vorangestellt wird, ruft Ruby prepend_features in diesem Modul auf und übergibt ihm das empfangende Modul in mod. Die Standardimplementierung von Ruby besteht darin, die Konstanten, Methoden und Modulvariablen dieses Moduls zu mod zu überlagern, wenn dieses Modul noch nicht zu mod oder einem seiner Vorfahren hinzugefügt wurde. Siehe auch Module#prepend.
Source
#define rb_obj_mod_prepended rb_obj_dummy1
Das Äquivalent zu included, aber für vorangestellte Module.
module A def self.prepended(mod) puts "#{self} prepended to #{mod}" end end module Enumerable prepend A end # => prints "A prepended to Enumerable"
Source
static VALUE
rb_mod_private(int argc, VALUE *argv, VALUE module)
{
return set_visibility(argc, argv, module, METHOD_VISI_PRIVATE);
}
Ohne Argumente wird die Standard-Sichtbarkeit für nachfolgend definierte Methoden auf privat gesetzt. Mit Argumenten werden die benannten Methoden auf private Sichtbarkeit gesetzt. String-Argumente werden in Symbole umgewandelt. Es wird auch ein Array von Symbolen und/oder Zeichenketten akzeptiert. Wenn ein einzelnes Argument übergeben wird, wird es zurückgegeben. Wenn kein Argument übergeben wird, wird nil zurückgegeben. Wenn mehrere Argumente übergeben werden, werden die Argumente als Array zurückgegeben.
module Mod def a() end def b() end private def c() end private :a end Mod.private_instance_methods #=> [:a, :c]
Beachten Sie, dass zur Anzeige einer privaten Methode auf RDoc :doc: verwendet wird.
Source
static VALUE
rb_mod_protected(int argc, VALUE *argv, VALUE module)
{
return set_visibility(argc, argv, module, METHOD_VISI_PROTECTED);
}
Setzt die Sichtbarkeit eines Abschnitts oder einer Liste von Methodennamen als geschützt. Akzeptiert keine Argumente, eine Splat von Methodennamen (Symbole oder Zeichenketten) oder ein Array von Methodennamen. Gibt die empfangenen Argumente zurück.
Wichtiger Unterschied zu geschützten Methoden in anderen Sprachen
Geschützte Methoden in Ruby unterscheiden sich von denen in anderen Sprachen wie Java, wo Methoden als geschützt markiert werden, um Unterklassen Zugriff zu gewähren. In Ruby haben Unterklassen **bereits Zugriff auf alle Methoden, die in der übergeordneten Klasse definiert sind**, auch auf private.
Das Markieren einer Methode als geschützt erlaubt **anderen Objekten derselben Klasse**, sie aufzurufen.
Ein Anwendungsfall sind Vergleichsmethoden wie ==, wenn wir eine Methode zum Vergleich zwischen Objekten derselben Klasse verfügbar machen möchten, ohne die Methode für Objekte anderer Klassen öffentlich zu machen.
Leistungsüberlegungen
Geschützte Methoden sind langsamer als andere, da sie keinen Inline-Cache verwenden können.
Beispiel
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)
Zur Anzeige einer privaten Methode auf RDoc verwenden Sie stattdessen :doc:.
Source
static VALUE
rb_mod_public(int argc, VALUE *argv, VALUE module)
{
return set_visibility(argc, argv, module, METHOD_VISI_PUBLIC);
}
Ohne Argumente wird die Standard-Sichtbarkeit für nachfolgend definierte Methoden auf öffentlich gesetzt. Mit Argumenten werden die benannten Methoden auf öffentliche Sichtbarkeit gesetzt. String-Argumente werden in Symbole umgewandelt. Es wird auch ein Array von Symbolen und/oder Zeichenketten akzeptiert. Wenn ein einzelnes Argument übergeben wird, wird es zurückgegeben. Wenn kein Argument übergeben wird, wird nil zurückgegeben. Wenn mehrere Argumente übergeben werden, werden die Argumente als Array zurückgegeben.
Source
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;
}
Verfeinert mod im Empfänger.
Gibt ein Modul zurück, in dem verfeinerte Methoden definiert werden.
Source
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);
}
Entfernt die Definition der gegebenen Konstante und gibt den vorherigen Wert dieser Konstante zurück. Wenn sich diese Konstante auf ein Modul bezog, ändert dies nicht den Namen dieses Moduls und kann zu Verwirrung führen.
Source
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;
}
Markiert für die gegebenen Methodennamen die Methode als durchlaufende Schlüsselwörter über ein normales Argument-Splat. Dies sollte nur auf Methoden angewendet werden, die einen Argument-Splat (*args) akzeptieren, aber keine expliziten Schlüsselwörter oder einen Schlüsselwort-Splat. Es markiert die Methode so, dass, wenn die Methode mit Schlüsselwortargumenten aufgerufen wird, das letzte Hash-Argument mit einem speziellen Flag markiert wird, so dass, wenn es das letzte Element eines normalen Argument-Splats an einen anderen Methodenaufruf ist und dieser Methodenaufruf keine expliziten Schlüsselwörter oder einen Schlüsselwort-Splat enthält, das letzte Element als Schlüsselwörter interpretiert wird. Mit anderen Worten, Schlüsselwörter werden über die Methode an andere Methoden weitergegeben.
Dies sollte nur für Methoden verwendet werden, die Schlüsselwörter an eine andere Methode delegieren, und nur zur Abwärtskompatibilität mit Ruby-Versionen vor 3.0. Weitere Informationen darüber, warum ruby2_keywords existiert und wann und wie es verwendet werden sollte, finden Sie unter www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0.
Diese Methode wird wahrscheinlich irgendwann entfernt, da sie nur zur Abwärtskompatibilität existiert. Da sie in Ruby-Versionen vor 2.7 nicht existiert, prüfen Sie, ob das Modul auf diese Methode reagiert, bevor Sie sie aufrufen.
module Mod def foo(meth, *args, &block) send(:"do_#{meth}", *args, &block) end ruby2_keywords(:foo) if respond_to?(:ruby2_keywords, true) end
Beachten Sie jedoch, dass sich das Verhalten der Methode foo mit dem obigen Ansatz ändert, wenn die Methode ruby2_keywords entfernt wird, sodass die Methode keine Schlüsselwörter mehr durchlässt.
Source
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;
}
Importiert Klassenverfeinerungen aus module in die aktuelle Klassen- oder Moduldefinition.