class Method
Method Objekte werden durch Object#method erstellt und sind mit einem bestimmten Objekt (nicht nur einer Klasse) verbunden. Sie können verwendet werden, um die Methode innerhalb des Objekts aufzurufen, und als Block, der mit einem Iterator verbunden ist. Sie können auch von einem Objekt gelöst werden (wodurch ein UnboundMethod erstellt wird) und an ein anderes gebunden werden.
class Thing def square(n) n*n end end thing = Thing.new meth = thing.method(:square) meth.call(9) #=> 81 [ 1, 2, 3 ].collect(&meth) #=> [1, 4, 9] [ 1, 2, 3 ].each(&method(:puts)) #=> prints 1, 2, 3 require 'date' %w[2017-03-01 2017-03-02].collect(&Date.method(:parse)) #=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
Öffentliche Instanzmethoden
Source
static VALUE
rb_method_compose_to_left(VALUE self, VALUE g)
{
g = to_callable(g);
self = method_to_proc(self);
return proc_compose_to_left(self, g);
}
Gibt einen Proc zurück, der die Komposition des gegebenen g und dieser Methode darstellt.
Der zurückgegebene Proc nimmt eine variable Anzahl von Argumenten. Er ruft zuerst g mit den Argumenten auf und dann self mit dem Rückgabewert von g.
def f(ary) = ary << 'in f' f = self.method(:f) g = proc { |ary| ary << 'in proc' } (f << g).call([]) # => ["in proc", "in f"]
Source
static VALUE
method_eq(VALUE method, VALUE other)
{
struct METHOD *m1, *m2;
VALUE klass1, klass2;
if (!rb_obj_is_method(other))
return Qfalse;
if (CLASS_OF(method) != CLASS_OF(other))
return Qfalse;
Check_TypedStruct(method, &method_data_type);
m1 = (struct METHOD *)RTYPEDDATA_GET_DATA(method);
m2 = (struct METHOD *)RTYPEDDATA_GET_DATA(other);
klass1 = method_entry_defined_class(m1->me);
klass2 = method_entry_defined_class(m2->me);
if (!rb_method_entry_eq(m1->me, m2->me) ||
klass1 != klass2 ||
m1->klass != m2->klass ||
m1->recv != m2->recv) {
return Qfalse;
}
return Qtrue;
}
Zwei Methodenobjekte sind gleich, wenn sie an dasselbe Objekt gebunden sind, sich auf dieselbe Methodendefinition beziehen und die Klassen, die die Methoden definieren, dieselbe Klasse oder dasselbe Modul sind.
Ruft die meth mit den angegebenen Argumenten auf und gibt den Rückgabewert der Methode zurück.
m = 12.method("+") m.call(3) #=> 15 m.call(20) #=> 32
Die Verwendung von Method#=== ermöglicht es einem Methodenobjekt, das Ziel einer when-Klausel in einer case-Anweisung zu sein.
require 'prime' case 1373 when Prime.method(:prime?) # ... end
Source
static VALUE
rb_method_compose_to_right(VALUE self, VALUE g)
{
g = to_callable(g);
self = method_to_proc(self);
return proc_compose_to_right(self, g);
}
Gibt einen Proc zurück, der die Komposition dieser Methode und des gegebenen g darstellt.
Der zurückgegebene Proc nimmt eine variable Anzahl von Argumenten. Er ruft zuerst self mit den Argumenten auf und dann g mit dem Rückgabewert von self.
def f(ary) = ary << 'in f' f = self.method(:f) g = proc { |ary| ary << 'in proc' } (f >> g).call([]) # => ["in f", "in proc"]
Ruft die meth mit den angegebenen Argumenten auf und gibt den Rückgabewert der Methode zurück.
m = 12.method("+") m.call(3) #=> 15 m.call(20) #=> 32
Die Verwendung von Method#=== ermöglicht es einem Methodenobjekt, das Ziel einer when-Klausel in einer case-Anweisung zu sein.
require 'prime' case 1373 when Prime.method(:prime?) # ... end
Source
static VALUE
method_arity_m(VALUE method)
{
int n = method_arity(method);
return INT2FIX(n);
}
Gibt einen Hinweis auf die Anzahl der von einer Methode akzeptierten Argumente zurück. Gibt eine nichtnegative Ganzzahl für Methoden zurück, die eine feste Anzahl von Argumenten haben. Für Ruby-Methoden, die eine variable Anzahl von Argumenten haben, wird -n-1 zurückgegeben, wobei n die Anzahl der erforderlichen Argumente ist. Schlüsselwortargumente werden als einzelnes zusätzliches Argument betrachtet, wobei dieses Argument obligatorisch ist, wenn ein Schlüsselwortargument obligatorisch ist. Für in C geschriebene Methoden wird -1 zurückgegeben, wenn der Aufruf eine variable Anzahl von Argumenten hat.
class C def one; end def two(a); end def three(*a); end def four(a, b); end def five(a, b, *c); end def six(a, b, *c, &d); end def seven(a, b, x:0); end def eight(x:, y:); end def nine(x:, y:, **z); end def ten(*a, x:, y:); end end c = C.new c.method(:one).arity #=> 0 c.method(:two).arity #=> 1 c.method(:three).arity #=> -1 c.method(:four).arity #=> 2 c.method(:five).arity #=> -3 c.method(:six).arity #=> -3 c.method(:seven).arity #=> -3 c.method(:eight).arity #=> 1 c.method(:nine).arity #=> 1 c.method(:ten).arity #=> -2 "cat".method(:size).arity #=> 0 "cat".method(:replace).arity #=> 1 "cat".method(:squeeze).arity #=> -1 "cat".method(:count).arity #=> -1
Source
static VALUE
method_box(VALUE obj)
{
struct METHOD *data;
const rb_box_t *box;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
box = data->me->def->box;
if (!box) return Qnil;
if (box->box_object) return box->box_object;
rb_bug("Unexpected box on the method definition: %p", (void*) box);
UNREACHABLE_RETURN(Qnil);
}
Gibt die Ruby::Box zurück, in der meth definiert ist.
Source
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
return rb_method_call_kw(argc, argv, method, RB_PASS_CALLED_KEYWORDS);
}
Ruft die meth mit den angegebenen Argumenten auf und gibt den Rückgabewert der Methode zurück.
m = 12.method("+") m.call(3) #=> 15 m.call(20) #=> 32
Die Verwendung von Method#=== ermöglicht es einem Methodenobjekt, das Ziel einer when-Klausel in einer case-Anweisung zu sein.
require 'prime' case 1373 when Prime.method(:prime?) # ... end
Source
static VALUE
method_clone(VALUE self)
{
VALUE clone;
struct METHOD *orig, *data;
TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
rb_obj_clone_setup(self, clone, Qnil);
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
RB_OBJ_WRITE(clone, &data->owner, orig->owner);
RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
return clone;
}
Gibt eine Kopie dieser Methode zurück.
class A def foo return "bar" end end m = A.new.method(:foo) m.call # => "bar" n = m.clone.call # => "bar"
Source
static VALUE
rb_method_curry(int argc, const VALUE *argv, VALUE self)
{
VALUE proc = method_to_proc(self);
return proc_curry(argc, argv, proc);
}
Gibt einen Curried-Proc basierend auf der Methode zurück. Wenn der Proc mit einer Anzahl von Argumenten aufgerufen wird, die niedriger ist als die Arity der Methode, wird ein weiterer Curried-Proc zurückgegeben. Erst wenn genügend Argumente geliefert wurden, um die Methodensignatur zu erfüllen, wird die Methode tatsächlich aufgerufen.
Das optionale Argument arity sollte bei der Currying von Methoden mit variablen Argumenten angegeben werden, um zu bestimmen, wie viele Argumente benötigt werden, bevor die Methode aufgerufen wird.
def foo(a,b,c) [a, b, c] end proc = self.method(:foo).curry proc2 = proc.call(1, 2) #=> #<Proc> proc2.call(3) #=> [1,2,3] def vararg(*args) args end proc = self.method(:vararg).curry(4) proc2 = proc.call(:x) #=> #<Proc> proc3 = proc2.call(:y, :z) #=> #<Proc> proc3.call(:a) #=> [:x, :y, :z, :a]
Zwei Methodenobjekte sind gleich, wenn sie an dasselbe Objekt gebunden sind, sich auf dieselbe Methodendefinition beziehen und die Klassen, die die Methoden definieren, dieselbe Klasse oder dasselbe Modul sind.
Source
static VALUE
method_hash(VALUE method)
{
struct METHOD *m;
st_index_t hash;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, m);
hash = rb_hash_start((st_index_t)m->recv);
hash = rb_hash_method_entry(hash, m->me);
hash = rb_hash_end(hash);
return ST2FIX(hash);
}
Gibt einen Hash-Wert zurück, der dem Methodenobjekt entspricht.
Siehe auch Object#hash.
Source
static VALUE
method_inspect(VALUE method)
{
struct METHOD *data;
VALUE str;
const char *sharp = "#";
VALUE mklass;
VALUE defined_class;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
str = rb_sprintf("#<% "PRIsVALUE": ", rb_obj_class(method));
mklass = data->iclass;
if (!mklass) mklass = data->klass;
if (RB_TYPE_P(mklass, T_ICLASS)) {
/* TODO: I'm not sure why mklass is T_ICLASS.
* UnboundMethod#bind() can set it as T_ICLASS at convert_umethod_to_method_components()
* but not sure it is needed.
*/
mklass = RBASIC_CLASS(mklass);
}
if (data->me->def->type == VM_METHOD_TYPE_ALIAS) {
defined_class = data->me->def->body.alias.original_me->owner;
}
else {
defined_class = method_entry_defined_class(data->me);
}
if (RB_TYPE_P(defined_class, T_ICLASS)) {
defined_class = RBASIC_CLASS(defined_class);
}
if (UNDEF_P(data->recv)) {
// UnboundMethod
rb_str_buf_append(str, rb_inspect(defined_class));
}
else if (RCLASS_SINGLETON_P(mklass)) {
VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
if (UNDEF_P(data->recv)) {
rb_str_buf_append(str, rb_inspect(mklass));
}
else if (data->recv == v) {
rb_str_buf_append(str, rb_inspect(v));
sharp = ".";
}
else {
rb_str_buf_append(str, rb_inspect(data->recv));
rb_str_buf_cat2(str, "(");
rb_str_buf_append(str, rb_inspect(v));
rb_str_buf_cat2(str, ")");
sharp = ".";
}
}
else {
mklass = data->klass;
if (RCLASS_SINGLETON_P(mklass)) {
VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) {
do {
mklass = RCLASS_SUPER(mklass);
} while (RB_TYPE_P(mklass, T_ICLASS));
}
}
rb_str_buf_append(str, rb_inspect(mklass));
if (defined_class != mklass) {
rb_str_catf(str, "(% "PRIsVALUE")", defined_class);
}
}
rb_str_buf_cat2(str, sharp);
rb_str_append(str, rb_id2str(data->me->called_id));
if (data->me->called_id != data->me->def->original_id) {
rb_str_catf(str, "(%"PRIsVALUE")",
rb_id2str(data->me->def->original_id));
}
if (data->me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
rb_str_buf_cat2(str, " (not-implemented)");
}
// parameter information
{
VALUE params = rb_method_parameters(method);
VALUE pair, name, kind;
const VALUE req = ID2SYM(rb_intern("req"));
const VALUE opt = ID2SYM(rb_intern("opt"));
const VALUE keyreq = ID2SYM(rb_intern("keyreq"));
const VALUE key = ID2SYM(rb_intern("key"));
const VALUE rest = ID2SYM(rb_intern("rest"));
const VALUE keyrest = ID2SYM(rb_intern("keyrest"));
const VALUE block = ID2SYM(rb_intern("block"));
const VALUE nokey = ID2SYM(rb_intern("nokey"));
int forwarding = 0;
rb_str_buf_cat2(str, "(");
if (RARRAY_LEN(params) == 3 &&
RARRAY_AREF(RARRAY_AREF(params, 0), 0) == rest &&
RARRAY_AREF(RARRAY_AREF(params, 0), 1) == ID2SYM('*') &&
RARRAY_AREF(RARRAY_AREF(params, 1), 0) == keyrest &&
RARRAY_AREF(RARRAY_AREF(params, 1), 1) == ID2SYM(idPow) &&
RARRAY_AREF(RARRAY_AREF(params, 2), 0) == block &&
RARRAY_AREF(RARRAY_AREF(params, 2), 1) == ID2SYM('&')) {
forwarding = 1;
}
for (int i = 0; i < RARRAY_LEN(params); i++) {
pair = RARRAY_AREF(params, i);
kind = RARRAY_AREF(pair, 0);
if (RARRAY_LEN(pair) > 1) {
name = RARRAY_AREF(pair, 1);
}
else {
// FIXME: can it be reduced to switch/case?
if (kind == req || kind == opt) {
name = rb_str_new2("_");
}
else if (kind == rest || kind == keyrest) {
name = rb_str_new2("");
}
else if (kind == block) {
name = rb_str_new2("block");
}
else if (kind == nokey) {
name = rb_str_new2("nil");
}
else {
name = Qnil;
}
}
if (kind == req) {
rb_str_catf(str, "%"PRIsVALUE, name);
}
else if (kind == opt) {
rb_str_catf(str, "%"PRIsVALUE"=...", name);
}
else if (kind == keyreq) {
rb_str_catf(str, "%"PRIsVALUE":", name);
}
else if (kind == key) {
rb_str_catf(str, "%"PRIsVALUE": ...", name);
}
else if (kind == rest) {
if (name == ID2SYM('*')) {
rb_str_cat_cstr(str, forwarding ? "..." : "*");
}
else {
rb_str_catf(str, "*%"PRIsVALUE, name);
}
}
else if (kind == keyrest) {
if (name != ID2SYM(idPow)) {
rb_str_catf(str, "**%"PRIsVALUE, name);
}
else if (i > 0) {
rb_str_set_len(str, RSTRING_LEN(str) - 2);
}
else {
rb_str_cat_cstr(str, "**");
}
}
else if (kind == block) {
if (name == ID2SYM('&')) {
if (forwarding) {
rb_str_set_len(str, RSTRING_LEN(str) - 2);
}
else {
rb_str_cat_cstr(str, "...");
}
}
else {
rb_str_catf(str, "&%"PRIsVALUE, name);
}
}
else if (kind == nokey) {
rb_str_buf_cat2(str, "**nil");
}
if (i < RARRAY_LEN(params) - 1) {
rb_str_buf_cat2(str, ", ");
}
}
rb_str_buf_cat2(str, ")");
}
{ // source location
VALUE loc = rb_method_location(method);
if (!NIL_P(loc)) {
rb_str_catf(str, " %"PRIsVALUE":%"PRIsVALUE,
RARRAY_AREF(loc, 0), RARRAY_AREF(loc, 1));
}
}
rb_str_buf_cat2(str, ">");
return str;
}
Gibt eine menschenlesbare Beschreibung der zugrunde liegenden Methode zurück.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>" (1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map()>"
Im letzteren Fall enthält die Methodenbeschreibung den "owner" der ursprünglichen Methode (Enumerable-Modul, das in Range eingebunden ist).
inspect bietet außerdem, wenn möglich, Methodennamen (Aufrufsequenz) und Quellcode-Speicherort.
require 'net/http' Net::HTTP.method(:get).inspect #=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
... in der Argumentdefinition bedeutet, dass das Argument optional ist (einen Standardwert hat).
Für in C definierte Methoden (Sprachkern und Erweiterungen) können Speicherort und Argumentnamen nicht extrahiert werden, und nur generische Informationen werden in Form von * (beliebige Anzahl von Argumenten) oder _ (ein positionsbezogenes Argument) bereitgestellt.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>" "cat".method(:+).inspect #=> "#<Method: String#+(_)>""
Source
static VALUE
method_name(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return ID2SYM(data->me->called_id);
}
Gibt den Namen der Methode zurück.
Source
static VALUE
method_original_name(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return ID2SYM(data->me->def->original_id);
}
Gibt den ursprünglichen Namen der Methode zurück.
class C def foo; end alias bar foo end C.instance_method(:bar).original_name # => :foo
Source
static VALUE
method_owner(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return data->owner;
}
Gibt die Klasse oder das Modul zurück, auf dem diese Methode definiert ist. Anders ausgedrückt,
meth.owner.instance_methods(false).include?(meth.name) # => true
gilt, solange die Methode nicht entfernt/undefined/ersetzt wird (mit private_instance_methods anstelle von instance_methods, wenn die Methode privat ist).
Siehe auch Method#receiver.
(1..3).method(:map).owner #=> Enumerable
Source
static VALUE
rb_method_parameters(VALUE method)
{
return method_def_parameters(rb_method_def(method));
}
Gibt die Parameterinformationen dieser Methode zurück.
def foo(bar); end method(:foo).parameters #=> [[:req, :bar]] def foo(bar, baz, bat, &blk); end method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:req, :bat], [:block, :blk]] def foo(bar, *args); end method(:foo).parameters #=> [[:req, :bar], [:rest, :args]] def foo(bar, baz, *args, &blk); end method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:rest, :args], [:block, :blk]]
Source
static VALUE
method_receiver(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return data->recv;
}
Gibt den gebundenen Empfänger des Methodenobjekts zurück.
(1..3).method(:map).receiver # => 1..3
Source
VALUE
rb_method_location(VALUE method)
{
return method_def_location(rb_method_def(method));
}
Gibt den Speicherort zurück, an dem die Methode definiert wurde. Das zurückgegebene Array enthält
(1) the Ruby source filename (2) the line number where the definition starts (3) the column number where the definition starts (4) the line number where the definition ends (5) the column number where the definitions ends
Diese Methode gibt nil zurück, wenn die Methode nicht in Ruby definiert wurde (d. h. nativ).
Source
static VALUE
method_super_method(VALUE method)
{
const struct METHOD *data;
VALUE super_class, iclass;
ID mid;
const rb_method_entry_t *me;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
iclass = data->iclass;
if (!iclass) return Qnil;
if (data->me->def->type == VM_METHOD_TYPE_ALIAS && data->me->defined_class) {
super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class,
data->me->def->body.alias.original_me->owner));
mid = data->me->def->body.alias.original_me->def->original_id;
}
else {
super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
mid = data->me->def->original_id;
}
if (!super_class) return Qnil;
me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass);
if (!me) return Qnil;
return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE);
}
Gibt eine Method der Superklasse zurück, die aufgerufen würde, wenn super verwendet wird, oder nil, wenn es keine Methode in der Superklasse gibt.
Source
static VALUE
method_to_proc(VALUE method)
{
VALUE procval;
rb_proc_t *proc;
/*
* class Method
* def to_proc
* lambda{|*args|
* self.call(*args)
* }
* end
* end
*/
procval = rb_block_call(rb_mRubyVMFrozenCore, idLambda, 0, 0, bmcall, method);
GetProcPtr(procval, proc);
proc->is_from_method = 1;
return procval;
}
Gibt ein Proc-Objekt zurück, das dieser Methode entspricht.
Gibt eine menschenlesbare Beschreibung der zugrunde liegenden Methode zurück.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>" (1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map()>"
Im letzteren Fall enthält die Methodenbeschreibung den "owner" der ursprünglichen Methode (Enumerable-Modul, das in Range eingebunden ist).
inspect bietet außerdem, wenn möglich, Methodennamen (Aufrufsequenz) und Quellcode-Speicherort.
require 'net/http' Net::HTTP.method(:get).inspect #=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
... in der Argumentdefinition bedeutet, dass das Argument optional ist (einen Standardwert hat).
Für in C definierte Methoden (Sprachkern und Erweiterungen) können Speicherort und Argumentnamen nicht extrahiert werden, und nur generische Informationen werden in Form von * (beliebige Anzahl von Argumenten) oder _ (ein positionsbezogenes Argument) bereitgestellt.
"cat".method(:count).inspect #=> "#<Method: String#count(*)>" "cat".method(:+).inspect #=> "#<Method: String#+(_)>""
Source
static VALUE
method_unbind(VALUE obj)
{
VALUE method;
struct METHOD *orig, *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig);
method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD,
&method_data_type, data);
RB_OBJ_WRITE(method, &data->recv, Qundef);
RB_OBJ_WRITE(method, &data->klass, Qundef);
RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
RB_OBJ_WRITE(method, &data->owner, orig->me->owner);
RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
return method;
}
Löst die Verbindung von meth mit seinem aktuellen Empfänger. Das resultierende UnboundMethod kann anschließend an ein neues Objekt derselben Klasse gebunden werden (siehe UnboundMethod).