Class: Method

Inherits:
Object show all
Includes:
MethodAsCode, MethodAsExpression, MethodOrigin, MethodSig
Defined in:
lib/internal/method/origin.rb,
lib/internal/method/as_code.rb,
lib/internal/method/signature.rb,
lib/internal/method/as_expression.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MethodAsExpression

#as_expression

Methods included from MethodSig

#argument_names, #arguments, #block_arg, #local_vars, #rest_arg

Methods included from MethodAsCode

#as_code

Methods included from MethodOrigin

#origin

Class Method Details

.load(String) ⇒ Method

Load a Method from a String.

Returns:



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'ext/internal/method/method.c', line 248

static VALUE method_load(VALUE klass, VALUE str)
{
  struct METHOD * method;

  VALUE rarr = marshal_load(str);
  VALUE * arr;
  VALUE retval;

  if(   rb_safe_level() >= 4
     || (rb_safe_level() >= 1 && OBJ_TAINTED(str)))
  {
    /* no playing with knives in the sandbox */
    rb_raise(rb_eSecurityError, "Insecure: can't load method");
  }

  Check_Type(rarr, T_ARRAY);
  if(RARRAY_LEN(rarr) != 6)
  {
    rb_raise(rb_eArgError, "corrupt data");
  }

  /* Create a METHOD object -- doesn't matter which method we use */
  retval = rb_funcall(
      rb_cObject, rb_intern("method"), 1, ID2SYM(rb_intern("__id__")));
  UNWRAP_METHOD(retval, method);

  arr = RARRAY_PTR(rarr);
#if RUBY_VERSION_CODE >= 192
  METHOD_KLASS(method) =
    rb_funcall(lookup_module_proc, rb_intern("call"), 1, arr[0]);
  METHOD_DEF(method) = xmalloc(sizeof(*METHOD_DEF(method)));
  METHOD_DEF(method)->type = VM_METHOD_TYPE_ISEQ;
  METHOD_DEF(method)->original_id = SYM2ID(arr[4]);
  METHOD_DEF(method)->alias_count = 0;
  GetISeqPtr(arr[5], METHOD_DEF(method)->body.iseq);
#else
  METHOD_OCLASS(method) =
    rb_funcall(lookup_module_proc, rb_intern("call"), 1, arr[0]);
  METHOD_RCLASS(method) =
    rb_funcall(lookup_module_proc, rb_intern("call"), 1, arr[1]);
  method->oid = SYM2ID(arr[4]);
  {
    NODE * n;
    Data_Get_Struct(arr[5], NODE, n);
    method->body = n;
  }
#endif
  method->recv = arr[2];
  method->id = SYM2ID(arr[3]);

  if(klass == rb_cUnboundMethod)
  {
    retval = rb_funcall(retval, rb_intern("unbind"), 0);
  }

  return retval;
}

Instance Method Details

#dump(limit) ⇒ String

Dump a Method and the object to which it is bound to a String. The Method’s class will not be dumped, only the name of the class.

Unfortunately, this means that methods for anonymous classes can be dumped but cannot be loaded.

Returns:

  • (String)


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'ext/internal/method/method.c', line 200

static VALUE method_dump(VALUE self, VALUE limit)
{
  struct METHOD * method;
  VALUE arr;

  if(rb_safe_level() >= 4)
  {
    /* no access to potentially sensitive data from the sandbox */
    rb_raise(rb_eSecurityError, "Insecure: can't dump method");
  }

  arr = rb_ary_new();
  UNWRAP_METHOD(self, method);
#if RUBY_VERSION_CODE >= 193
  rb_ary_push(arr, rb_mod_name(method->me->klass));           /* [0] */
  rb_ary_push(arr, Qnil); /* TODO */                          /* [1] */
#elif RUBY_VERSION_CODE >= 192
  rb_ary_push(arr, rb_mod_name(method->me.klass));            /* [0] */
  rb_ary_push(arr, Qnil); /* TODO */                          /* [1] */
#else
  rb_ary_push(arr, rb_mod_name(METHOD_OCLASS(method)));       /* [2] */
  rb_ary_push(arr, rb_mod_name(METHOD_RCLASS(method)));       /* [3] */
#endif
  if(rb_class_of(self) == rb_cUnboundMethod)
  {
    rb_ary_push(arr, Qnil);                                   /* [4] */
  }
  else
  {
    rb_ary_push(arr, method->recv);                           /* [4] */
  }
  rb_ary_push(arr, ID2SYM(method->id));
#if RUBY_VERSION_CODE >= 192
  rb_ary_push(arr, ID2SYM(METHOD_DEF(method)->original_id));  /* [5] */
#else
  rb_ary_push(arr, ID2SYM(method->oid));                      /* [5] */
#endif
  rb_ary_push(arr, method_body(self));                        /* [6] */

  return marshal_dump(arr, limit);
}

#attached_classClass

Given a Method, returns the Class it is attached to.

Returns:

  • (Class)


159
160
161
162
163
164
# File 'ext/internal/method/method.c', line 159

static VALUE method_attached_class(VALUE method)
{
  struct METHOD * m;
  UNWRAP_METHOD(method, m);
  return CLASS_OF(m->recv);
}

#bodyNode

Given a Method, returns the Node for that Method’s body. This can be used to directly copy one class’s method to another (using add_method).

Returns:



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'ext/internal/method/method.c', line 174

static VALUE method_body(VALUE method)
{
  struct METHOD * m;
  if(rb_safe_level() >= 4)
  {
    /* no access to potentially sensitive data from the sandbox */
    rb_raise(rb_eSecurityError, "Insecure: can't get method body");
  }
  UNWRAP_METHOD(method, m);
#if RUBY_VERSION_CODE >= 192
  return METHOD_DEF(m)->body.iseq->self; /* TODO: body is a union; is this right? */
#else
  return wrap_node(m->body);
#endif
}

#method_idSymbol

Given a Method, returns the Symbol of the method it represents. If the method is an alias for another method, returns the Symbol of the new method, not the original. If the method changes name, returns the original name, not the new name.

Returns:

  • (Symbol)


104
105
106
107
108
109
# File 'ext/internal/method/method.c', line 104

static VALUE method_id(VALUE method)
{
  struct METHOD * m;
  UNWRAP_METHOD(method, m);
  return ID2SYM(m->id);
}

#method_oidSymbol

Given a Method, returns the Symbol of the method it represents. If the method is an alias for another method, returns the Symbol of the original method, not the alias. If the original method changes name, returns the original name.

Returns:

  • (Symbol)


120
121
122
123
124
125
126
127
128
129
# File 'ext/internal/method/method.c', line 120

static VALUE method_oid(VALUE method)
{
  struct METHOD * m;
  UNWRAP_METHOD(method, m);
#if RUBY_VERSION_CODE >= 192
  return ID2SYM(METHOD_DEF(m)->original_id);
#else
  return ID2SYM(m->oid);
#endif
}

#origin_classClass

Given a Method, returns the Class in which the method it represents was defined. If the method was defined in a base class and Object#method is called on a derived instance of that base class, this method returns the base class.

Returns:

  • (Class)


140
141
142
143
144
145
146
147
148
149
150
151
# File 'ext/internal/method/method.c', line 140

static VALUE method_origin_class(VALUE method)
{
  struct METHOD * m;
  UNWRAP_METHOD(method, m);
#if RUBY_VERSION_CODE >= 193
  return m->me->klass;
#elif RUBY_VERSION_CODE >= 192
  return m->me.klass;
#else
  return METHOD_OCLASS(m);
#endif
}

#receiverObject

Given a Method, returns the Object to which it is bound.

Returns:



88
89
90
91
92
93
# File 'ext/internal/method/method.c', line 88

static VALUE method_receiver(VALUE method)
{
  struct METHOD * m;
  UNWRAP_METHOD(method, m);
  return m->recv;
}

#signatureObject

Return a String representing the method’s signature.



84
85
86
87
88
89
90
# File 'lib/internal/method/signature.rb', line 84

def signature
  return Signature.new(
      attached_class(),
      method_oid().to_s,
      argument_names(),
      arguments())
end