diff options
Diffstat (limited to 'trunk/proc.c')
-rw-r--r-- | trunk/proc.c | 1867 |
1 files changed, 0 insertions, 1867 deletions
diff --git a/trunk/proc.c b/trunk/proc.c deleted file mode 100644 index 710ab065d1..0000000000 --- a/trunk/proc.c +++ /dev/null @@ -1,1867 +0,0 @@ -/********************************************************************** - - proc.c - Proc, Binding, Env - - $Author$ - created at: Wed Jan 17 12:13:14 2007 - - Copyright (C) 2004-2007 Koichi Sasada - -**********************************************************************/ - -#include "eval_intern.h" -#include "gc.h" - -struct METHOD { - VALUE oclass; /* class that holds the method */ - VALUE rclass; /* class of the receiver */ - VALUE recv; - ID id, oid; - NODE *body; -}; - -VALUE rb_cUnboundMethod; -VALUE rb_cMethod; -VALUE rb_cBinding; -VALUE rb_cProc; - -static VALUE bmcall(VALUE, VALUE); -static int method_arity(VALUE); -static VALUE rb_obj_is_method(VALUE m); - -/* Proc */ - -static void -proc_free(void *ptr) -{ - RUBY_FREE_ENTER("proc"); - if (ptr) { - ruby_xfree(ptr); - } - RUBY_FREE_LEAVE("proc"); -} - -static void -proc_mark(void *ptr) -{ - rb_proc_t *proc; - RUBY_MARK_ENTER("proc"); - if (ptr) { - proc = ptr; - RUBY_MARK_UNLESS_NULL(proc->envval); - RUBY_MARK_UNLESS_NULL(proc->blockprocval); - RUBY_MARK_UNLESS_NULL(proc->block.proc); - RUBY_MARK_UNLESS_NULL(proc->block.self); - if (proc->block.iseq && RUBY_VM_IFUNC_P(proc->block.iseq)) { - RUBY_MARK_UNLESS_NULL((VALUE)(proc->block.iseq)); - } - } - RUBY_MARK_LEAVE("proc"); -} - -VALUE -rb_proc_alloc(VALUE klass) -{ - VALUE obj; - rb_proc_t *proc; - obj = Data_Make_Struct(klass, rb_proc_t, proc_mark, proc_free, proc); - MEMZERO(proc, rb_proc_t, 1); - return obj; -} - -VALUE -rb_obj_is_proc(VALUE proc) -{ - if (TYPE(proc) == T_DATA && - RDATA(proc)->dfree == (RUBY_DATA_FUNC) proc_free) { - return Qtrue; - } - else { - return Qfalse; - } -} - -static VALUE -proc_dup(VALUE self) -{ - VALUE procval = rb_proc_alloc(rb_cProc); - rb_proc_t *src, *dst; - GetProcPtr(self, src); - GetProcPtr(procval, dst); - - dst->block = src->block; - dst->block.proc = procval; - dst->envval = src->envval; - dst->safe_level = src->safe_level; - dst->is_lambda = src->is_lambda; - - return procval; -} - -static VALUE -proc_clone(VALUE self) -{ - VALUE procval = proc_dup(self); - CLONESETUP(procval, self); - return procval; -} - -/* - * call-seq: - * prc.lambda? => true or false - * - * Returns true for a Proc object which argument handling is rigid. - * Such procs are typically generated by lambda. - * - * A Proc object generated by proc ignore extra arguments. - * - * proc {|a,b| [a,b] }.call(1,2,3) => [1,2] - * - * It provides nil for lacked arguments. - * - * proc {|a,b| [a,b] }.call(1) => [1,nil] - * - * It expand single-array argument. - * - * proc {|a,b| [a,b] }.call([1,2]) => [1,2] - * - * A Proc object generated by lambda doesn't have such tricks. - * - * lambda {|a,b| [a,b] }.call(1,2,3) => ArgumentError - * lambda {|a,b| [a,b] }.call(1) => ArgumentError - * lambda {|a,b| [a,b] }.call([1,2]) => ArgumentError - * - * Proc#lambda? is a predicate for the tricks. - * It returns true if no tricks. - * - * lambda {}.lambda? => true - * proc {}.lambda? => false - * - * Proc.new is same as proc. - * - * Proc.new {}.lambda? => false - * - * lambda, proc and Proc.new preserves the tricks of - * a Proc object given by & argument. - * - * lambda(&lambda {}).lambda? => true - * proc(&lambda {}).lambda? => true - * Proc.new(&lambda {}).lambda? => true - * - * lambda(&proc {}).lambda? => false - * proc(&proc {}).lambda? => false - * Proc.new(&proc {}).lambda? => false - * - * A Proc object generated by & argument has the tricks - * - * def n(&b) b.lambda? end - * n {} => false - * - * The & argument preserves the tricks if a Proc object is given - * by & argument. - * - * n(&lambda {}) => true - * n(&proc {}) => false - * n(&Proc.new {}) => false - * - * A Proc object converted from a method has no tricks. - * - * def m() end - * method(:m).to_proc.lambda? => true - * - * n(&method(:m)) => true - * n(&method(:m).to_proc) => true - * - * define_method is treated same as method definition. - * The defined method has no tricks. - * - * class C - * define_method(:d) {} - * end - * C.new.e(1,2) => ArgumentError - * C.new.method(:d).to_proc.lambda? => true - * - * define_method always defines a method without the tricks, - * even if a non-lambda Proc object is given. - * This is the only exception which the tricks are not preserved. - * - * class C - * define_method(:e, &proc {}) - * end - * C.new.e(1,2) => ArgumentError - * C.new.method(:e).to_proc.lambda? => true - * - * This exception is for a wrapper of define_method. - * It eases defining a method defining method which defines a usual method which has no tricks. - * - * class << C - * def def2(name, &body) - * define_method(name, &body) - * end - * end - * class C - * def2(:f) {} - * end - * C.new.f(1,2) => ArgumentError - * - * The wrapper, def2, defines a method which has no tricks. - * - */ - -static VALUE -proc_lambda_p(VALUE procval) -{ - rb_proc_t *proc; - GetProcPtr(procval, proc); - - return proc->is_lambda ? Qtrue : Qfalse; -} - -/* Binding */ - -static void -binding_free(void *ptr) -{ - rb_binding_t *bind; - RUBY_FREE_ENTER("binding"); - if (ptr) { - bind = ptr; - ruby_xfree(ptr); - } - RUBY_FREE_LEAVE("binding"); -} - -static void -binding_mark(void *ptr) -{ - rb_binding_t *bind; - RUBY_MARK_ENTER("binding"); - if (ptr) { - bind = ptr; - RUBY_MARK_UNLESS_NULL(bind->env); - } - RUBY_MARK_LEAVE("binding"); -} - -static VALUE -binding_alloc(VALUE klass) -{ - VALUE obj; - rb_binding_t *bind; - obj = Data_Make_Struct(klass, rb_binding_t, binding_mark, binding_free, bind); - return obj; -} - -static VALUE -binding_dup(VALUE self) -{ - VALUE bindval = binding_alloc(rb_cBinding); - rb_binding_t *src, *dst; - GetBindingPtr(self, src); - GetBindingPtr(bindval, dst); - dst->env = src->env; - return bindval; -} - -static VALUE -binding_clone(VALUE self) -{ - VALUE bindval = binding_dup(self); - CLONESETUP(bindval, self); - return bindval; -} - -rb_control_frame_t *vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp); - -VALUE -rb_binding_new(void) -{ - rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = vm_get_ruby_level_next_cfp(th, th->cfp); - VALUE bindval = binding_alloc(rb_cBinding); - rb_binding_t *bind; - - if (cfp == 0) { - rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber."); - } - - GetBindingPtr(bindval, bind); - bind->env = vm_make_env_object(th, cfp); - return bindval; -} - -/* - * call-seq: - * binding -> a_binding - * - * Returns a +Binding+ object, describing the variable and - * method bindings at the point of call. This object can be used when - * calling +eval+ to execute the evaluated command in this - * environment. Also see the description of class +Binding+. - * - * def getBinding(param) - * return binding - * end - * b = getBinding("hello") - * eval("param", b) #=> "hello" - */ - -static VALUE -rb_f_binding(VALUE self) -{ - return rb_binding_new(); -} - -/* - * call-seq: - * binding.eval(string [, filename [,lineno]]) => obj - * - * Evaluates the Ruby expression(s) in <em>string</em>, in the - * <em>binding</em>'s context. If the optional <em>filename</em> and - * <em>lineno</em> parameters are present, they will be used when - * reporting syntax errors. - * - * def getBinding(param) - * return binding - * end - * b = getBinding("hello") - * b.eval("param") #=> "hello" - */ - -static VALUE -bind_eval(int argc, VALUE *argv, VALUE bindval) -{ - VALUE args[4]; - - rb_scan_args(argc, argv, "12", &args[0], &args[2], &args[3]); - args[1] = bindval; - return rb_f_eval(argc+1, args, Qnil /* self will be searched in eval */); -} - -static VALUE -proc_new(VALUE klass, int is_lambda) -{ - VALUE procval = Qnil; - rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = th->cfp; - rb_block_t *block; - - if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 && - !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) { - - block = GC_GUARDED_PTR_REF(cfp->lfp[0]); - cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); - } - else { - cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); - - if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 && - !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) { - - block = GC_GUARDED_PTR_REF(cfp->lfp[0]); - - if (block->proc) { - return block->proc; - } - - /* TODO: check more (cfp limit, called via cfunc, etc) */ - while (cfp->dfp != block->dfp) { - cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); - } - - if (is_lambda) { - rb_warn("tried to create Proc object without a block"); - } - } - else { - rb_raise(rb_eArgError, - "tried to create Proc object without a block"); - } - } - - procval = block->proc; - if (procval && RBASIC(procval)->klass == klass) { - return procval; - } - - procval = vm_make_proc(th, cfp, block, klass); - - if (is_lambda) { - rb_proc_t *proc; - GetProcPtr(procval, proc); - proc->is_lambda = Qtrue; - } - return procval; -} - -/* - * call-seq: - * Proc.new {|...| block } => a_proc - * Proc.new => a_proc - * - * Creates a new <code>Proc</code> object, bound to the current - * context. <code>Proc::new</code> may be called without a block only - * within a method with an attached block, in which case that block is - * converted to the <code>Proc</code> object. - * - * def proc_from - * Proc.new - * end - * proc = proc_from { "hello" } - * proc.call #=> "hello" - */ - -static VALUE -rb_proc_s_new(int argc, VALUE *argv, VALUE klass) -{ - VALUE block = proc_new(klass, Qfalse); - - rb_obj_call_init(block, argc, argv); - return block; -} - -/* - * call-seq: - * proc { |...| block } => a_proc - * - * Equivalent to <code>Proc.new</code>. - */ - -VALUE -rb_block_proc(void) -{ - return proc_new(rb_cProc, Qfalse); -} - -VALUE -rb_block_lambda(void) -{ - return proc_new(rb_cProc, Qtrue); -} - -VALUE -rb_f_lambda(void) -{ - rb_warn("rb_f_lambda() is deprecated; use rb_block_proc() instead"); - return rb_block_lambda(); -} - -/* - * call-seq: - * lambda { |...| block } => a_proc - * - * Equivalent to <code>Proc.new</code>, except the resulting Proc objects - * check the number of parameters passed when called. - */ - -static VALUE -proc_lambda(void) -{ - return rb_block_lambda(); -} - -/* CHECKME: are the argument checking semantics correct? */ - -/* - * call-seq: - * prc.call(params,...) => obj - * prc[params,...] => obj - * - * Invokes the block, setting the block's parameters to the values in - * <i>params</i> using something close to method calling semantics. - * Generates a warning if multiple values are passed to a proc that - * expects just one (previously this silently converted the parameters - * to an array). - * - * For procs created using <code>Kernel.proc</code>, generates an - * error if the wrong number of parameters - * are passed to a proc with multiple parameters. For procs created using - * <code>Proc.new</code>, extra parameters are silently discarded. - * - * Returns the value of the last expression evaluated in the block. See - * also <code>Proc#yield</code>. - * - * a_proc = Proc.new {|a, *b| b.collect {|i| i*a }} - * a_proc.call(9, 1, 2, 3) #=> [9, 18, 27] - * a_proc[9, 1, 2, 3] #=> [9, 18, 27] - * a_proc = Proc.new {|a,b| a} - * a_proc.call(1,2,3) - * - * <em>produces:</em> - * - * prog.rb:5: wrong number of arguments (3 for 2) (ArgumentError) - * from prog.rb:4:in `call' - * from prog.rb:5 - */ - -static VALUE -proc_call(int argc, VALUE *argv, VALUE procval) -{ - rb_proc_t *proc; - rb_block_t *blockptr = 0; - GetProcPtr(procval, proc); - - if (BUILTIN_TYPE(proc->block.iseq) == T_NODE || - proc->block.iseq->arg_block != -1) { - - if (rb_block_given_p()) { - rb_proc_t *proc; - VALUE procval; - procval = rb_block_proc(); - GetProcPtr(procval, proc); - blockptr = &proc->block; - } - } - - return vm_invoke_proc(GET_THREAD(), proc, proc->block.self, - argc, argv, blockptr); -} - -VALUE -rb_proc_call(VALUE self, VALUE args) -{ - rb_proc_t *proc; - GetProcPtr(self, proc); - return vm_invoke_proc(GET_THREAD(), proc, proc->block.self, - RARRAY_LEN(args), RARRAY_PTR(args), 0); -} - -VALUE -rb_proc_call_with_block(VALUE self, int argc, VALUE *argv, VALUE pass_procval) -{ - rb_proc_t *proc; - rb_block_t *block = 0; - GetProcPtr(self, proc); - - if (!NIL_P(pass_procval)) { - rb_proc_t *pass_proc; - GetProcPtr(pass_procval, pass_proc); - block = &pass_proc->block; - } - - return vm_invoke_proc(GET_THREAD(), proc, proc->block.self, - argc, argv, block); -} - -/* - * call-seq: - * prc.arity -> fixnum - * - * Returns the number of arguments that would not be ignored. If the block - * is declared to take no arguments, returns 0. If the block is known - * to take exactly n arguments, returns n. If the block has optional - * arguments, return -n-1, where n is the number of mandatory - * arguments. A <code>proc</code> with no argument declarations - * is the same a block declaring <code>||</code> as its arguments. - * - * Proc.new {}.arity #=> 0 - * Proc.new {||}.arity #=> 0 - * Proc.new {|a|}.arity #=> 1 - * Proc.new {|a,b|}.arity #=> 2 - * Proc.new {|a,b,c|}.arity #=> 3 - * Proc.new {|*a|}.arity #=> -1 - * Proc.new {|a,*b|}.arity #=> -2 - * Proc.new {|a,*b, c|}.arity #=> -3 - */ - -static VALUE -proc_arity(VALUE self) -{ - rb_proc_t *proc; - rb_iseq_t *iseq; - GetProcPtr(self, proc); - iseq = proc->block.iseq; - if (iseq) { - if (BUILTIN_TYPE(iseq) != T_NODE) { - if (iseq->arg_rest < 0) { - return INT2FIX(iseq->argc); - } - else { - return INT2FIX(-(iseq->argc + 1 + iseq->arg_post_len)); - } - } - else { - NODE *node = (NODE *)iseq; - if (nd_type(node) == NODE_IFUNC && node->nd_cfnc == bmcall) { - /* method(:foo).to_proc.arity */ - return INT2FIX(method_arity(node->nd_tval)); - } - } - } - return INT2FIX(-1); -} - -int -rb_proc_arity(VALUE proc) -{ - return FIX2INT(proc_arity(proc)); -} - -static rb_iseq_t * -get_proc_iseq(VALUE self) -{ - rb_proc_t *proc; - rb_iseq_t *iseq; - - GetProcPtr(self, proc); - iseq = proc->block.iseq; - if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) - return 0; - return iseq; -} - -VALUE -rb_proc_location(VALUE self) -{ - rb_iseq_t *iseq = get_proc_iseq(self); - VALUE loc[2]; - - if (!iseq) return Qnil; - loc[0] = iseq->filename; - if (iseq->insn_info_table) { - loc[1] = INT2FIX(iseq->insn_info_table[0].line_no); - } - else { - loc[1] = Qnil; - } - return rb_ary_new4(2, loc); -} - -/* - * call-seq: - * prc == other_proc => true or false - * - * Return <code>true</code> if <i>prc</i> is the same object as - * <i>other_proc</i>, or if they are both procs with the same body. - */ - -static VALUE -proc_eq(VALUE self, VALUE other) -{ - if (self == other) { - return Qtrue; - } - else { - if (TYPE(other) == T_DATA && - RBASIC(other)->klass == rb_cProc && - CLASS_OF(self) == CLASS_OF(other)) { - rb_proc_t *p1, *p2; - GetProcPtr(self, p1); - GetProcPtr(other, p2); - if (p1->block.iseq == p2->block.iseq && p1->envval == p2->envval) { - return Qtrue; - } - } - } - return Qfalse; -} - -/* - * call-seq: - * prc.hash => integer - * - * Return hash value corresponding to proc body. - */ - -static VALUE -proc_hash(VALUE self) -{ - int hash; - rb_proc_t *proc; - GetProcPtr(self, proc); - hash = (long)proc->block.iseq; - hash ^= (long)proc->envval; - hash ^= (long)proc->block.lfp >> 16; - return INT2FIX(hash); -} - -/* - * call-seq: - * prc.to_s => string - * - * Shows the unique identifier for this proc, along with - * an indication of where the proc was defined. - */ - -static VALUE -proc_to_s(VALUE self) -{ - VALUE str = 0; - rb_proc_t *proc; - const char *cname = rb_obj_classname(self); - rb_iseq_t *iseq; - const char *is_lambda; - - GetProcPtr(self, proc); - iseq = proc->block.iseq; - is_lambda = proc->is_lambda ? " (lambda)" : ""; - - if (RUBY_VM_NORMAL_ISEQ_P(iseq)) { - int line_no = 0; - - if (iseq->insn_info_table) { - line_no = iseq->insn_info_table[0].line_no; - } - str = rb_sprintf("#<%s:%p@%s:%d%s>", cname, (void *)self, - RSTRING_PTR(iseq->filename), - line_no, is_lambda); - } - else { - str = rb_sprintf("#<%s:%p%s>", cname, proc->block.iseq, - is_lambda); - } - - if (OBJ_TAINTED(self)) { - OBJ_TAINT(str); - } - return str; -} - -/* - * call-seq: - * prc.to_proc -> prc - * - * Part of the protocol for converting objects to <code>Proc</code> - * objects. Instances of class <code>Proc</code> simply return - * themselves. - */ - -static VALUE -proc_to_proc(VALUE self) -{ - return self; -} - -static void -bm_mark(struct METHOD *data) -{ - rb_gc_mark(data->rclass); - rb_gc_mark(data->oclass); - rb_gc_mark(data->recv); - rb_gc_mark((VALUE)data->body); -} - -NODE * -rb_method_body(VALUE method) -{ - struct METHOD *data; - - if (TYPE(method) == T_DATA && - RDATA(method)->dmark == (RUBY_DATA_FUNC) bm_mark) { - Data_Get_Struct(method, struct METHOD, data); - return data->body; - } - else { - return 0; - } -} - -NODE *rb_get_method_body(VALUE klass, ID id, ID *idp); - -static VALUE -mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) -{ - VALUE method; - NODE *body; - struct METHOD *data; - VALUE rclass = klass; - ID oid = id; - - again: - if ((body = rb_get_method_body(klass, id, 0)) == 0) { - rb_print_undef(rclass, oid, 0); - } - if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) { - rb_print_undef(rclass, oid, (body->nd_noex & NOEX_MASK)); - } - - klass = body->nd_clss; - body = body->nd_body; - - if (nd_type(body) == NODE_ZSUPER) { - klass = RCLASS_SUPER(klass); - goto again; - } - - while (rclass != klass && - (FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) { - rclass = RCLASS_SUPER(rclass); - } - if (TYPE(klass) == T_ICLASS) - klass = RBASIC(klass)->klass; - method = Data_Make_Struct(mclass, struct METHOD, bm_mark, -1, data); - data->oclass = klass; - data->recv = obj; - - data->id = id; - data->body = body; - data->rclass = rclass; - data->oid = oid; - OBJ_INFECT(method, klass); - - return method; -} - - -/********************************************************************** - * - * Document-class : Method - * - * Method objects are created by <code>Object#method</code>, and are - * associated with a particular object (not just with a class). They - * may be used to invoke the method within the object, and as a block - * associated with an iterator. They may also be unbound from one - * object (creating an <code>UnboundMethod</code>) and bound to - * another. - * - * 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] - * - */ - -/* - * call-seq: - * meth == other_meth => true or false - * - * Two method objects are equal if that are bound to the same - * object and contain the same body. - */ - - -static VALUE -method_eq(VALUE method, VALUE other) -{ - struct METHOD *m1, *m2; - - if (TYPE(other) != T_DATA - || RDATA(other)->dmark != (RUBY_DATA_FUNC) bm_mark) - return Qfalse; - if (CLASS_OF(method) != CLASS_OF(other)) - return Qfalse; - - Data_Get_Struct(method, struct METHOD, m1); - Data_Get_Struct(other, struct METHOD, m2); - - if (m1->oclass != m2->oclass || m1->rclass != m2->rclass || - m1->recv != m2->recv || m1->body != m2->body) - return Qfalse; - - return Qtrue; -} - -/* - * call-seq: - * meth.hash => integer - * - * Return a hash value corresponding to the method object. - */ - -static VALUE -method_hash(VALUE method) -{ - struct METHOD *m; - long hash; - - Data_Get_Struct(method, struct METHOD, m); - hash = (long)m->oclass; - hash ^= (long)m->rclass; - hash ^= (long)m->recv; - hash ^= (long)m->body; - - return INT2FIX(hash); -} - -/* - * call-seq: - * meth.unbind => unbound_method - * - * Dissociates <i>meth</i> from it's current receiver. The resulting - * <code>UnboundMethod</code> can subsequently be bound to a new object - * of the same class (see <code>UnboundMethod</code>). - */ - -static VALUE -method_unbind(VALUE obj) -{ - VALUE method; - struct METHOD *orig, *data; - - Data_Get_Struct(obj, struct METHOD, orig); - method = - Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, -1, data); - data->oclass = orig->oclass; - data->recv = Qundef; - data->id = orig->id; - data->body = orig->body; - data->rclass = orig->rclass; - data->oid = orig->oid; - OBJ_INFECT(method, obj); - - return method; -} - -/* - * call-seq: - * meth.receiver => object - * - * Returns the bound receiver of the method object. - */ - -static VALUE -method_receiver(VALUE obj) -{ - struct METHOD *data; - - Data_Get_Struct(obj, struct METHOD, data); - return data->recv; -} - -/* - * call-seq: - * meth.name => symbol - * - * Returns the name of the method. - */ - -static VALUE -method_name(VALUE obj) -{ - struct METHOD *data; - - Data_Get_Struct(obj, struct METHOD, data); - return ID2SYM(data->id); -} - -/* - * call-seq: - * meth.owner => class_or_module - * - * Returns the class or module that defines the method. - */ - -static VALUE -method_owner(VALUE obj) -{ - struct METHOD *data; - - Data_Get_Struct(obj, struct METHOD, data); - return data->oclass; -} - -/* - * call-seq: - * obj.method(sym) => method - * - * Looks up the named method as a receiver in <i>obj</i>, returning a - * <code>Method</code> object (or raising <code>NameError</code>). The - * <code>Method</code> object acts as a closure in <i>obj</i>'s object - * instance, so instance variables and the value of <code>self</code> - * remain available. - * - * class Demo - * def initialize(n) - * @iv = n - * end - * def hello() - * "Hello, @iv = #{@iv}" - * end - * end - * - * k = Demo.new(99) - * m = k.method(:hello) - * m.call #=> "Hello, @iv = 99" - * - * l = Demo.new('Fred') - * m = l.method("hello") - * m.call #=> "Hello, @iv = Fred" - */ - -VALUE -rb_obj_method(VALUE obj, VALUE vid) -{ - return mnew(CLASS_OF(obj), obj, rb_to_id(vid), rb_cMethod, Qfalse); -} - -VALUE -rb_obj_public_method(VALUE obj, VALUE vid) -{ - return mnew(CLASS_OF(obj), obj, rb_to_id(vid), rb_cMethod, Qtrue); -} - -/* - * call-seq: - * mod.instance_method(symbol) => unbound_method - * - * Returns an +UnboundMethod+ representing the given - * instance method in _mod_. - * - * class Interpreter - * def do_a() print "there, "; end - * def do_d() print "Hello "; end - * def do_e() print "!\n"; end - * def do_v() print "Dave"; end - * Dispatcher = { - * ?a => instance_method(:do_a), - * ?d => instance_method(:do_d), - * ?e => instance_method(:do_e), - * ?v => instance_method(:do_v) - * } - * def interpret(string) - * string.each_byte {|b| Dispatcher[b].bind(self).call } - * end - * end - * - * - * interpreter = Interpreter.new - * interpreter.interpret('dave') - * - * <em>produces:</em> - * - * Hello there, Dave! - */ - -static VALUE -rb_mod_instance_method(VALUE mod, VALUE vid) -{ - return mnew(mod, Qundef, rb_to_id(vid), rb_cUnboundMethod, Qfalse); -} - -static VALUE -rb_mod_public_instance_method(VALUE mod, VALUE vid) -{ - return mnew(mod, Qundef, rb_to_id(vid), rb_cUnboundMethod, Qtrue); -} - -/* - * call-seq: - * define_method(symbol, method) => new_method - * define_method(symbol) { block } => proc - * - * Defines an instance method in the receiver. The _method_ - * parameter can be a +Proc+ or +Method+ object. - * If a block is specified, it is used as the method body. This block - * is evaluated using <code>instance_eval</code>, a point that is - * tricky to demonstrate because <code>define_method</code> is private. - * (This is why we resort to the +send+ hack in this example.) - * - * class A - * def fred - * puts "In Fred" - * end - * def create_method(name, &block) - * self.class.send(:define_method, name, &block) - * end - * define_method(:wilma) { puts "Charge it!" } - * end - * class B < A - * define_method(:barney, instance_method(:fred)) - * end - * a = B.new - * a.barney - * a.wilma - * a.create_method(:betty) { p self } - * a.betty - * - * <em>produces:</em> - * - * In Fred - * Charge it! - * #<B:0x401b39e8> - */ - -static VALUE -rb_mod_define_method(int argc, VALUE *argv, VALUE mod) -{ - ID id; - VALUE body; - NODE *node; - int noex = NOEX_PUBLIC; - - if (argc == 1) { - id = rb_to_id(argv[0]); - body = rb_block_lambda(); - } - else if (argc == 2) { - id = rb_to_id(argv[0]); - body = argv[1]; - if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) { - rb_raise(rb_eTypeError, - "wrong argument type %s (expected Proc/Method)", - rb_obj_classname(body)); - } - } - else { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); - } - - if (RDATA(body)->dmark == (RUBY_DATA_FUNC) bm_mark) { - struct METHOD *method = (struct METHOD *)DATA_PTR(body); - VALUE rclass = method->rclass; - if (rclass != mod) { - if (FL_TEST(rclass, FL_SINGLETON)) { - rb_raise(rb_eTypeError, - "can't bind singleton method to a different class"); - } - if (!RTEST(rb_class_inherited_p(mod, rclass))) { - rb_raise(rb_eTypeError, - "bind argument must be a subclass of %s", - rb_class2name(rclass)); - } - } - node = method->body; - } - else if (rb_obj_is_proc(body)) { - rb_proc_t *proc; - body = proc_dup(body); - GetProcPtr(body, proc); - if (BUILTIN_TYPE(proc->block.iseq) != T_NODE) { - proc->block.iseq->defined_method_id = id; - proc->block.iseq->klass = mod; - proc->is_lambda = Qtrue; - proc->is_from_method = Qtrue; - } - node = NEW_BMETHOD(body); - } - else { - /* type error */ - rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)"); - } - - /* TODO: visibility */ - - rb_add_method(mod, id, node, noex); - return body; -} - -static VALUE -rb_obj_define_method(int argc, VALUE *argv, VALUE obj) -{ - VALUE klass = rb_singleton_class(obj); - - return rb_mod_define_method(argc, argv, klass); -} - - -/* - * MISSING: documentation - */ - -static VALUE -method_clone(VALUE self) -{ - VALUE clone; - struct METHOD *orig, *data; - - Data_Get_Struct(self, struct METHOD, orig); - clone = Data_Make_Struct(CLASS_OF(self), struct METHOD, bm_mark, -1, data); - CLONESETUP(clone, self); - *data = *orig; - - return clone; -} - -/* - * call-seq: - * meth.call(args, ...) => obj - * meth[args, ...] => obj - * - * Invokes the <i>meth</i> with the specified arguments, returning the - * method's return value. - * - * m = 12.method("+") - * m.call(3) #=> 15 - * m.call(20) #=> 32 - */ - -VALUE -rb_method_call(int argc, VALUE *argv, VALUE method) -{ - VALUE result = Qnil; /* OK */ - struct METHOD *data; - int state; - volatile int safe = -1; - - Data_Get_Struct(method, struct METHOD, data); - if (data->recv == Qundef) { - rb_raise(rb_eTypeError, "can't call unbound method; bind first"); - } - PUSH_TAG(); - if (OBJ_TAINTED(method)) { - safe = rb_safe_level(); - if (rb_safe_level() < 4) { - rb_set_safe_level_force(4); - } - } - if ((state = EXEC_TAG()) == 0) { - rb_thread_t *th = GET_THREAD(); - VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, - int argc, const VALUE *argv, const NODE *body, int nosuper); - - PASS_PASSED_BLOCK_TH(th); - result = rb_vm_call(th, data->oclass, data->recv, data->id, data->oid, - argc, argv, data->body, 0); - } - POP_TAG(); - if (safe >= 0) - rb_set_safe_level_force(safe); - if (state) - JUMP_TAG(state); - return result; -} - -/********************************************************************** - * - * Document-class: UnboundMethod - * - * Ruby supports two forms of objectified methods. Class - * <code>Method</code> is used to represent methods that are associated - * with a particular object: these method objects are bound to that - * object. Bound method objects for an object can be created using - * <code>Object#method</code>. - * - * Ruby also supports unbound methods; methods objects that are not - * associated with a particular object. These can be created either by - * calling <code>Module#instance_method</code> or by calling - * <code>unbind</code> on a bound method object. The result of both of - * these is an <code>UnboundMethod</code> object. - * - * Unbound methods can only be called after they are bound to an - * object. That object must be be a kind_of? the method's original - * class. - * - * class Square - * def area - * @side * @side - * end - * def initialize(side) - * @side = side - * end - * end - * - * area_un = Square.instance_method(:area) - * - * s = Square.new(12) - * area = area_un.bind(s) - * area.call #=> 144 - * - * Unbound methods are a reference to the method at the time it was - * objectified: subsequent changes to the underlying class will not - * affect the unbound method. - * - * class Test - * def test - * :original - * end - * end - * um = Test.instance_method(:test) - * class Test - * def test - * :modified - * end - * end - * t = Test.new - * t.test #=> :modified - * um.bind(t).call #=> :original - * - */ - -/* - * call-seq: - * umeth.bind(obj) -> method - * - * Bind <i>umeth</i> to <i>obj</i>. If <code>Klass</code> was the class - * from which <i>umeth</i> was obtained, - * <code>obj.kind_of?(Klass)</code> must be true. - * - * class A - * def test - * puts "In test, class = #{self.class}" - * end - * end - * class B < A - * end - * class C < B - * end - * - * - * um = B.instance_method(:test) - * bm = um.bind(C.new) - * bm.call - * bm = um.bind(B.new) - * bm.call - * bm = um.bind(A.new) - * bm.call - * - * <em>produces:</em> - * - * In test, class = C - * In test, class = B - * prog.rb:16:in `bind': bind argument must be an instance of B (TypeError) - * from prog.rb:16 - */ - -static VALUE -umethod_bind(VALUE method, VALUE recv) -{ - struct METHOD *data, *bound; - - Data_Get_Struct(method, struct METHOD, data); - if (data->rclass != CLASS_OF(recv)) { - if (FL_TEST(data->rclass, FL_SINGLETON)) { - rb_raise(rb_eTypeError, - "singleton method called for a different object"); - } - if (!rb_obj_is_kind_of(recv, data->rclass)) { - rb_raise(rb_eTypeError, "bind argument must be an instance of %s", - rb_class2name(data->rclass)); - } - } - - method = Data_Make_Struct(rb_cMethod, struct METHOD, bm_mark, -1, bound); - *bound = *data; - bound->recv = recv; - bound->rclass = CLASS_OF(recv); - - return method; -} - -int -rb_node_arity(NODE* body) -{ - switch (nd_type(body)) { - case NODE_CFUNC: - if (body->nd_argc < 0) - return -1; - return body->nd_argc; - case NODE_ZSUPER: - return -1; - case NODE_ATTRSET: - return 1; - case NODE_IVAR: - return 0; - case NODE_BMETHOD: - return rb_proc_arity(body->nd_cval); - case RUBY_VM_METHOD_NODE: - { - rb_iseq_t *iseq; - GetISeqPtr((VALUE)body->nd_body, iseq); - if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { - return iseq->argc; - } - else { - return -(iseq->argc + 1 + iseq->arg_post_len); - } - } - default: - rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); - } -} - -/* - * call-seq: - * meth.arity => fixnum - * - * Returns an indication of the number of arguments accepted by a - * method. Returns a nonnegative integer for methods that take a fixed - * number of arguments. For Ruby methods that take a variable number of - * arguments, returns -n-1, where n is the number of required - * arguments. For methods written in C, returns -1 if the call takes a - * variable number of arguments. - * - * 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 - * 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 - * - * "cat".method(:size).arity #=> 0 - * "cat".method(:replace).arity #=> 1 - * "cat".method(:squeeze).arity #=> -1 - * "cat".method(:count).arity #=> -1 - */ - -static VALUE -method_arity_m(VALUE method) -{ - int n = method_arity(method); - return INT2FIX(n); -} - -static int -method_arity(VALUE method) -{ - struct METHOD *data; - - Data_Get_Struct(method, struct METHOD, data); - return rb_node_arity(data->body); -} - -int -rb_mod_method_arity(VALUE mod, ID id) -{ - NODE *node = rb_method_node(mod, id); - return rb_node_arity(node); -} - -int -rb_obj_method_arity(VALUE obj, ID id) -{ - return rb_mod_method_arity(CLASS_OF(obj), id); -} - -/* - * call-seq: - * meth.to_s => string - * meth.inspect => string - * - * Show the name of the underlying method. - * - * "cat".method(:count).inspect #=> "#<Method: String#count>" - */ - -static VALUE -method_inspect(VALUE method) -{ - struct METHOD *data; - VALUE str; - const char *s; - const char *sharp = "#"; - - Data_Get_Struct(method, struct METHOD, data); - str = rb_str_buf_new2("#<"); - s = rb_obj_classname(method); - rb_str_buf_cat2(str, s); - rb_str_buf_cat2(str, ": "); - - if (FL_TEST(data->oclass, FL_SINGLETON)) { - VALUE v = rb_iv_get(data->oclass, "__attached__"); - - if (data->recv == Qundef) { - rb_str_buf_append(str, rb_inspect(data->oclass)); - } - 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 { - rb_str_buf_cat2(str, rb_class2name(data->rclass)); - if (data->rclass != data->oclass) { - rb_str_buf_cat2(str, "("); - rb_str_buf_cat2(str, rb_class2name(data->oclass)); - rb_str_buf_cat2(str, ")"); - } - } - rb_str_buf_cat2(str, sharp); - rb_str_append(str, rb_id2str(data->oid)); - rb_str_buf_cat2(str, ">"); - - return str; -} - -static VALUE -mproc(VALUE method) -{ - return rb_funcall(Qnil, rb_intern("proc"), 0); -} - -static VALUE -mlambda(VALUE method) -{ - return rb_funcall(Qnil, rb_intern("lambda"), 0); -} - -static VALUE -bmcall(VALUE args, VALUE method) -{ - volatile VALUE a; - - if (CLASS_OF(args) != rb_cArray) { - args = rb_ary_new3(1, args); - } - - a = args; - return rb_method_call(RARRAY_LEN(a), RARRAY_PTR(a), method); -} - -VALUE -rb_proc_new( - VALUE (*func)(ANYARGS), /* VALUE yieldarg[, VALUE procarg] */ - VALUE val) -{ - VALUE procval = rb_iterate(mproc, 0, func, val); - return procval; -} - -/* - * call-seq: - * meth.to_proc => prc - * - * Returns a <code>Proc</code> object corresponding to this method. - */ - -static VALUE -method_proc(VALUE method) -{ - VALUE procval; - rb_proc_t *proc; - /* - * class Method - * def to_proc - * proc{|*args| - * self.call(*args) - * } - * end - * end - */ - procval = rb_iterate(mlambda, 0, bmcall, method); - GetProcPtr(procval, proc); - proc->is_from_method = 1; - return procval; -} - -static VALUE -rb_obj_is_method(VALUE m) -{ - if (TYPE(m) == T_DATA && RDATA(m)->dmark == (RUBY_DATA_FUNC) bm_mark) { - return Qtrue; - } - return Qfalse; -} - -/* - * call_seq: - * local_jump_error.exit_value => obj - * - * Returns the exit value associated with this +LocalJumpError+. - */ -static VALUE -localjump_xvalue(VALUE exc) -{ - return rb_iv_get(exc, "@exit_value"); -} - -/* - * call-seq: - * local_jump_error.reason => symbol - * - * The reason this block was terminated: - * :break, :redo, :retry, :next, :return, or :noreason. - */ - -static VALUE -localjump_reason(VALUE exc) -{ - return rb_iv_get(exc, "@reason"); -} - -/* - * call-seq: - * prc.binding => binding - * - * Returns the binding associated with <i>prc</i>. Note that - * <code>Kernel#eval</code> accepts either a <code>Proc</code> or a - * <code>Binding</code> object as its second parameter. - * - * def fred(param) - * proc {} - * end - * - * b = fred(99) - * eval("param", b.binding) #=> 99 - */ -static VALUE -proc_binding(VALUE self) -{ - rb_proc_t *proc; - VALUE bindval = binding_alloc(rb_cBinding); - rb_binding_t *bind; - - GetProcPtr(self, proc); - GetBindingPtr(bindval, bind); - - if (TYPE(proc->block.iseq) == T_NODE) { - rb_raise(rb_eArgError, "Can't create Binding from C level Proc"); - } - - bind->env = proc->envval; - return bindval; -} - -static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc); - -static VALUE -make_curry_proc(VALUE proc, VALUE passed, VALUE arity) -{ - VALUE args = rb_ary_new2(3); - RARRAY_PTR(args)[0] = proc; - RARRAY_PTR(args)[1] = passed; - RARRAY_PTR(args)[2] = arity; - RARRAY_LEN(args) = 3; - rb_ary_freeze(passed); - rb_ary_freeze(args); - return rb_proc_new(curry, args); -} - -static VALUE -curry(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc) -{ - VALUE proc, passed, arity; - proc = RARRAY_PTR(args)[0]; - passed = RARRAY_PTR(args)[1]; - arity = RARRAY_PTR(args)[2]; - - passed = rb_ary_plus(passed, rb_ary_new4(argc, argv)); - rb_ary_freeze(passed); - - if(RARRAY_LEN(passed) < FIX2INT(arity)) { - if (!NIL_P(passed_proc)) { - rb_warn("given block not used"); - } - arity = make_curry_proc(proc, passed, arity); - return arity; - } - else { - return rb_proc_call_with_block(proc, RARRAY_LEN(passed), RARRAY_PTR(passed), passed_proc); - } -} - - /* - * call-seq: - * prc.curry => a_proc - * prc.curry(arity) => a_proc - * - * Returns a curried proc. If the optional <i>arity</i> argument is given, - * it determines the number of arguments. - * A curried proc receives some arguments. If a sufficient number of - * arguments are supplied, it passes the supplied arguments to the original - * proc and returns the result. Otherwise, returns another curried proc that - * takes the rest of arguments. - * - * b = proc {|x, y, z| (x||0) + (y||0) + (z||0) } - * p b.curry[1][2][3] #=> 6 - * p b.curry[1, 2][3, 4] #=> 6 - * p b.curry(5)[1][2][3][4][5] #=> 6 - * p b.curry(5)[1, 2][3, 4][5] #=> 6 - * p b.curry(1)[1] #=> 1 - * - * b = proc {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } - * p b.curry[1][2][3] #=> 6 - * p b.curry[1, 2][3, 4] #=> 10 - * p b.curry(5)[1][2][3][4][5] #=> 15 - * p b.curry(5)[1, 2][3, 4][5] #=> 15 - * p b.curry(1)[1] #=> 1 - * - * b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) } - * p b.curry[1][2][3] #=> 6 - * p b.curry[1, 2][3, 4] #=> wrong number of arguments (4 or 3) - * p b.curry(5) #=> wrong number of arguments (5 or 3) - * p b.curry(1) #=> wrong number of arguments (1 or 3) - * - * b = lambda {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.inject(0, &:+) } - * p b.curry[1][2][3] #=> 6 - * p b.curry[1, 2][3, 4] #=> 10 - * p b.curry(5)[1][2][3][4][5] #=> 15 - * p b.curry(5)[1, 2][3, 4][5] #=> 15 - * p b.curry(1) #=> wrong number of arguments (1 or 3) - * - * b = proc { :foo } - * p b.curry[] #=> :foo - */ -static VALUE -proc_curry(int argc, VALUE *argv, VALUE self) -{ - int sarity, marity = FIX2INT(proc_arity(self)); - VALUE arity, opt = Qfalse; - - if (marity < 0) { - marity = -marity - 1; - opt = Qtrue; - } - - rb_scan_args(argc, argv, "01", &arity); - if (NIL_P(arity)) { - arity = INT2FIX(marity); - } - else { - sarity = FIX2INT(arity); - if (proc_lambda_p(self) && (sarity < marity || (sarity > marity && !opt))) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", sarity, marity); - } - } - - return make_curry_proc(self, rb_ary_new(), arity); -} - -/* - * <code>Proc</code> objects are blocks of code that have been bound to - * a set of local variables. Once bound, the code may be called in - * different contexts and still access those variables. - * - * def gen_times(factor) - * return Proc.new {|n| n*factor } - * end - * - * times3 = gen_times(3) - * times5 = gen_times(5) - * - * times3.call(12) #=> 36 - * times5.call(5) #=> 25 - * times3.call(times5.call(4)) #=> 60 - * - */ - -void -Init_Proc(void) -{ - /* Proc */ - rb_cProc = rb_define_class("Proc", rb_cObject); - rb_undef_alloc_func(rb_cProc); - rb_define_singleton_method(rb_cProc, "new", rb_proc_s_new, -1); - rb_define_method(rb_cProc, "call", proc_call, -1); - rb_define_method(rb_cProc, "[]", proc_call, -1); - rb_define_method(rb_cProc, "yield", proc_call, -1); - rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0); - rb_define_method(rb_cProc, "arity", proc_arity, 0); - rb_define_method(rb_cProc, "clone", proc_clone, 0); - rb_define_method(rb_cProc, "dup", proc_dup, 0); - rb_define_method(rb_cProc, "==", proc_eq, 1); - rb_define_method(rb_cProc, "eql?", proc_eq, 1); - rb_define_method(rb_cProc, "hash", proc_hash, 0); - rb_define_method(rb_cProc, "to_s", proc_to_s, 0); - rb_define_method(rb_cProc, "lambda?", proc_lambda_p, 0); - rb_define_method(rb_cProc, "binding", proc_binding, 0); - rb_define_method(rb_cProc, "curry", proc_curry, -1); - - /* Exceptions */ - rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); - rb_define_method(rb_eLocalJumpError, "exit_value", localjump_xvalue, 0); - rb_define_method(rb_eLocalJumpError, "reason", localjump_reason, 0); - - rb_eSysStackError = rb_define_class("SystemStackError", rb_eException); - sysstack_error = rb_exc_new3(rb_eSysStackError, - rb_obj_freeze(rb_str_new2("stack level too deep"))); - OBJ_TAINT(sysstack_error); - OBJ_FREEZE(sysstack_error); - - /* utility functions */ - rb_define_global_function("proc", rb_block_proc, 0); - rb_define_global_function("lambda", proc_lambda, 0); - - /* Method */ - rb_cMethod = rb_define_class("Method", rb_cObject); - rb_undef_alloc_func(rb_cMethod); - rb_undef_method(CLASS_OF(rb_cMethod), "new"); - rb_define_method(rb_cMethod, "==", method_eq, 1); - rb_define_method(rb_cMethod, "eql?", method_eq, 1); - rb_define_method(rb_cMethod, "hash", method_hash, 0); - rb_define_method(rb_cMethod, "clone", method_clone, 0); - rb_define_method(rb_cMethod, "call", rb_method_call, -1); - rb_define_method(rb_cMethod, "[]", rb_method_call, -1); - rb_define_method(rb_cMethod, "arity", method_arity_m, 0); - rb_define_method(rb_cMethod, "inspect", method_inspect, 0); - rb_define_method(rb_cMethod, "to_s", method_inspect, 0); - rb_define_method(rb_cMethod, "to_proc", method_proc, 0); - rb_define_method(rb_cMethod, "receiver", method_receiver, 0); - rb_define_method(rb_cMethod, "name", method_name, 0); - rb_define_method(rb_cMethod, "owner", method_owner, 0); - rb_define_method(rb_cMethod, "unbind", method_unbind, 0); - rb_define_method(rb_mKernel, "method", rb_obj_method, 1); - rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1); - - /* UnboundMethod */ - rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject); - rb_undef_alloc_func(rb_cUnboundMethod); - rb_undef_method(CLASS_OF(rb_cUnboundMethod), "new"); - rb_define_method(rb_cUnboundMethod, "==", method_eq, 1); - rb_define_method(rb_cUnboundMethod, "eql?", method_eq, 1); - rb_define_method(rb_cUnboundMethod, "hash", method_hash, 0); - rb_define_method(rb_cUnboundMethod, "clone", method_clone, 0); - rb_define_method(rb_cUnboundMethod, "arity", method_arity_m, 0); - rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0); - rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0); - rb_define_method(rb_cUnboundMethod, "name", method_name, 0); - rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0); - rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); - - /* Module#*_method */ - rb_define_method(rb_cModule, "instance_method", rb_mod_instance_method, 1); - rb_define_method(rb_cModule, "public_instance_method", rb_mod_public_instance_method, 1); - rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1); - - /* Kernel */ - rb_define_method(rb_mKernel, "define_singleton_method", rb_obj_define_method, -1); -} - -/* - * Objects of class <code>Binding</code> encapsulate the execution - * context at some particular place in the code and retain this context - * for future use. The variables, methods, value of <code>self</code>, - * and possibly an iterator block that can be accessed in this context - * are all retained. Binding objects can be created using - * <code>Kernel#binding</code>, and are made available to the callback - * of <code>Kernel#set_trace_func</code>. - * - * These binding objects can be passed as the second argument of the - * <code>Kernel#eval</code> method, establishing an environment for the - * evaluation. - * - * class Demo - * def initialize(n) - * @secret = n - * end - * def getBinding - * return binding() - * end - * end - * - * k1 = Demo.new(99) - * b1 = k1.getBinding - * k2 = Demo.new(-3) - * b2 = k2.getBinding - * - * eval("@secret", b1) #=> 99 - * eval("@secret", b2) #=> -3 - * eval("@secret") #=> nil - * - * Binding objects have no class-specific methods. - * - */ - -void -Init_Binding(void) -{ - rb_cBinding = rb_define_class("Binding", rb_cObject); - rb_undef_alloc_func(rb_cBinding); - rb_undef_method(CLASS_OF(rb_cBinding), "new"); - rb_define_method(rb_cBinding, "clone", binding_clone, 0); - rb_define_method(rb_cBinding, "dup", binding_dup, 0); - rb_define_method(rb_cBinding, "eval", bind_eval, -1); - rb_define_global_function("binding", rb_f_binding, 0); -} - |