mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
vm.c (mrb_f_public_send): define #public_send method
The method itself is available when mruby-metaprog is loaded.
This commit is contained in:
@@ -198,6 +198,7 @@ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
|
||||
mrb_value mrb_object_exec(mrb_state *mrb, mrb_value self, struct RClass *target_class);
|
||||
mrb_value mrb_mod_module_eval(mrb_state*, mrb_value);
|
||||
mrb_value mrb_f_send(mrb_state *mrb, mrb_value self);
|
||||
mrb_value mrb_f_public_send(mrb_state *mrb, mrb_value self);
|
||||
|
||||
#ifdef MRB_USE_BIGINT
|
||||
mrb_value mrb_bint_new_int(mrb_state *mrb, mrb_int x);
|
||||
|
||||
@@ -712,6 +712,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb)
|
||||
mrb_define_method_id(mrb, krn, MRB_SYM(singleton_methods), mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */
|
||||
mrb_define_method_id(mrb, krn, MRB_SYM(define_singleton_method), mod_define_singleton_method, MRB_ARGS_REQ(1)|MRB_ARGS_BLOCK());
|
||||
mrb_define_method_id(mrb, krn, MRB_SYM(send), mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.44 */
|
||||
mrb_define_method_id(mrb, krn, MRB_SYM(public_send), mrb_f_public_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK());
|
||||
|
||||
mrb_define_method_id(mrb, mod, MRB_SYM(class_variables), mrb_mod_class_variables, MRB_ARGS_OPT(1)); /* 15.2.2.4.19 */
|
||||
mrb_define_method_id(mrb, mod, MRB_SYM(remove_class_variable), mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
|
||||
|
||||
@@ -858,27 +858,14 @@ mrb_object_exec(mrb_state *mrb, mrb_value self, struct RClass *target_class)
|
||||
return mrb_exec_irep(mrb, self, mrb_proc_ptr(blk));
|
||||
}
|
||||
|
||||
/* 15.3.1.3.4 */
|
||||
/* 15.3.1.3.44 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.send(symbol [, args...]) -> obj
|
||||
* obj.__send__(symbol [, args...]) -> obj
|
||||
*
|
||||
* Invokes the method identified by _symbol_, passing it any
|
||||
* arguments specified. You can use <code>__send__</code> if the name
|
||||
* +send+ clashes with an existing method in _obj_.
|
||||
*
|
||||
* class Klass
|
||||
* def hello(*args)
|
||||
* "Hello " + args.join(' ')
|
||||
* end
|
||||
* end
|
||||
* k = Klass.new
|
||||
* k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
|
||||
*/
|
||||
mrb_value
|
||||
mrb_f_send(mrb_state *mrb, mrb_value self)
|
||||
static mrb_noreturn void
|
||||
vis_error(mrb_state *mrb, mrb_sym mid, mrb_value args, mrb_value recv, mrb_bool priv)
|
||||
{
|
||||
mrb_no_method_error(mrb, mid, args, "%s method '%n' called for %T", (priv ? "private" : "protected"), mid, recv);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
send_method(mrb_state *mrb, mrb_value self, mrb_bool public)
|
||||
{
|
||||
mrb_callinfo *ci = mrb->c->ci;
|
||||
int n = ci->n;
|
||||
@@ -914,6 +901,22 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
|
||||
goto funcall;
|
||||
}
|
||||
|
||||
if (public) {
|
||||
mrb_bool priv = TRUE;
|
||||
if (m.flags & MRB_METHOD_PRIVATE_FL) {
|
||||
vis_err:;
|
||||
if (n == 15) {
|
||||
n = RARRAY_LEN(regs[0]) - 1;
|
||||
regs = RARRAY_PTR(regs[0]);
|
||||
}
|
||||
vis_error(mrb, name, mrb_ary_new_from_values(mrb, n, regs+1), self, priv);
|
||||
}
|
||||
else if ((m.flags & MRB_METHOD_PROTECTED_FL) && mrb_obj_is_kind_of(mrb, self, ci->u.target_class)) {
|
||||
priv = FALSE;
|
||||
goto vis_err;
|
||||
}
|
||||
}
|
||||
|
||||
ci->mid = name;
|
||||
ci->u.target_class = c;
|
||||
/* remove first symbol from arguments */
|
||||
@@ -950,6 +953,48 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
|
||||
return exec_irep(mrb, self, p);
|
||||
}
|
||||
|
||||
/* 15.3.1.3.4 */
|
||||
/* 15.3.1.3.44 */
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.send(symbol [, args...]) -> obj
|
||||
* obj.__send__(symbol [, args...]) -> obj
|
||||
*
|
||||
* Invokes the method identified by _symbol_, passing it any
|
||||
* arguments specified. You can use <code>__send__</code> if the name
|
||||
* +send+ clashes with an existing method in _obj_.
|
||||
*
|
||||
* class Klass
|
||||
* def hello(*args)
|
||||
* "Hello " + args.join(' ')
|
||||
* end
|
||||
* end
|
||||
* k = Klass.new
|
||||
* k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
|
||||
*/
|
||||
mrb_value
|
||||
mrb_f_send(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return send_method(mrb, self, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.public_send(symbol [, args...]) -> obj
|
||||
*
|
||||
* Invokes the method identified by symbol, passing it any
|
||||
* arguments specified. Unlike send, public_send calls public methods only.
|
||||
* When the method is identified by a string, the string is converted to a
|
||||
* symbol.
|
||||
*
|
||||
* 1.public_send(:puts, "hello") # causes NoMethodError
|
||||
*/
|
||||
mrb_value
|
||||
mrb_f_public_send(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return send_method(mrb, self, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
check_block(mrb_state *mrb, mrb_value blk)
|
||||
{
|
||||
@@ -1911,13 +1956,15 @@ RETRY_TRY_BLOCK:
|
||||
ci->mid = mid;
|
||||
}
|
||||
if (insn == OP_SEND || insn == OP_SENDB) {
|
||||
mrb_bool priv = TRUE;
|
||||
if (m.flags & MRB_METHOD_PRIVATE_FL) {
|
||||
vis_err:;
|
||||
mrb_value args = (ci->n == 15) ? regs[1] : mrb_ary_new_from_values(mrb, ci->n, regs+1);
|
||||
mrb_no_method_error(mrb, mid, args, "private method '%n' called for %T", mid, recv);
|
||||
vis_error(mrb, mid, args, recv, priv);
|
||||
}
|
||||
else if ((m.flags & MRB_METHOD_PROTECTED_FL) && mrb_obj_is_kind_of(mrb, recv, ci->u.target_class)) {
|
||||
mrb_value args = (ci->n == 15) ? regs[1] : mrb_ary_new_from_values(mrb, ci->n, regs+1);
|
||||
mrb_no_method_error(mrb, mid, args, "protected method '%n' called for %T", mid, recv);
|
||||
priv = FALSE;
|
||||
goto vis_err;
|
||||
}
|
||||
}
|
||||
ci->cci = CINFO_NONE;
|
||||
|
||||
Reference in New Issue
Block a user