KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyMethod


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001-2002 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002 Anders Bengtsson <ndrsbngtssn@yahoo.se>
17  * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
18  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
19  *
20  * Alternatively, the contents of this file may be used under the terms of
21  * either of the GNU General Public License Version 2 or later (the "GPL"),
22  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23  * in which case the provisions of the GPL or the LGPL are applicable instead
24  * of those above. If you wish to allow use of your version of this file only
25  * under the terms of either the GPL or the LGPL, and not to allow others to
26  * use your version of this file under the terms of the CPL, indicate your
27  * decision by deleting the provisions above and replace them with the notice
28  * and other provisions required by the GPL or the LGPL. If you do not delete
29  * the provisions above, a recipient may use your version of this file under
30  * the terms of any one of the CPL, the GPL or the LGPL.
31  ***** END LICENSE BLOCK *****/

32 package org.jruby;
33
34 import org.jruby.exceptions.JumpException;
35 import org.jruby.internal.runtime.methods.DynamicMethod;
36 import org.jruby.internal.runtime.methods.IterateCallable;
37 import org.jruby.runtime.Block;
38 import org.jruby.runtime.CallbackFactory;
39 import org.jruby.runtime.ObjectAllocator;
40 import org.jruby.runtime.ThreadContext;
41 import org.jruby.runtime.builtin.IRubyObject;
42
43 /**
44  * The RubyMethod class represents a RubyMethod object.
45  *
46  * You can get such a method by calling the "method" method of an object.
47  *
48  * Note: This was renamed from Method.java
49  *
50  * @author jpetersen
51  * @since 0.2.3
52  */

53 public class RubyMethod extends RubyObject {
54     protected RubyModule implementationModule;
55     protected String JavaDoc methodName;
56     protected RubyModule originModule;
57     protected String JavaDoc originName;
58     protected DynamicMethod method;
59     protected IRubyObject receiver;
60
61     protected RubyMethod(Ruby runtime, RubyClass rubyClass) {
62         super(runtime, rubyClass);
63     }
64
65     /** Create the RubyMethod class and add it to the Ruby runtime.
66      *
67      */

68     public static RubyClass createMethodClass(Ruby runtime) {
69         // TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here. Confirm. JRUBY-415
70
RubyClass methodClass = runtime.defineClass("Method", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
71         
72         CallbackFactory callbackFactory = runtime.callbackFactory(RubyMethod.class);
73         
74         methodClass.defineFastMethod("arity", callbackFactory.getFastMethod("arity"));
75         methodClass.defineMethod("to_proc", callbackFactory.getMethod("to_proc"));
76         methodClass.defineMethod("unbind", callbackFactory.getMethod("unbind"));
77         methodClass.defineMethod("call", callbackFactory.getOptMethod("call"));
78         methodClass.defineMethod("[]", callbackFactory.getOptMethod("call"));
79         methodClass.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect"));
80         methodClass.defineFastMethod("to_s", callbackFactory.getFastMethod("inspect"));
81
82         return methodClass;
83     }
84
85     public static RubyMethod newMethod(
86         RubyModule implementationModule,
87         String JavaDoc methodName,
88         RubyModule originModule,
89         String JavaDoc originName,
90         DynamicMethod method,
91         IRubyObject receiver) {
92         Ruby runtime = implementationModule.getRuntime();
93         RubyMethod newMethod = new RubyMethod(runtime, runtime.getClass("Method"));
94
95         newMethod.implementationModule = implementationModule;
96         newMethod.methodName = methodName;
97         newMethod.originModule = originModule;
98         newMethod.originName = originName;
99         newMethod.method = method;
100         newMethod.receiver = receiver;
101
102         return newMethod;
103     }
104
105     /** Call the method.
106      *
107      */

108     public IRubyObject call(IRubyObject[] args, Block block) {
109         assert args != null;
110         ThreadContext tc = getRuntime().getCurrentContext();
111
112         method.getArity().checkArity(getRuntime(), args);
113         
114         // FIXME: should lastClass be implementation module for a Method?
115
return method.call(tc, receiver, implementationModule, methodName, args, false, block);
116     }
117
118     /** Returns the number of arguments a method accepted.
119      *
120      * @return the number of arguments of a method.
121      */

122     public RubyFixnum arity() {
123         return getRuntime().newFixnum(method.getArity().getValue());
124     }
125
126     /** Create a Proc object.
127      *
128      */

129     public IRubyObject to_proc(Block unusedBlock) {
130         CallbackFactory f = getRuntime().callbackFactory(RubyMethod.class);
131         Ruby r = getRuntime();
132         ThreadContext tc = r.getCurrentContext();
133         Block block = Block.createBlock(tc, null, tc.getCurrentScope().cloneScope(),
134                 new IterateCallable(f.getBlockMethod("bmcall"), this), r.getTopSelf());
135         
136         while (true) {
137             try {
138                 // FIXME: We should not be regenerating this over and over
139
return f.getSingletonMethod("mproc").execute(getRuntime().getNil(),
140                             IRubyObject.NULL_ARRAY, block);
141             } catch (JumpException je) {
142                 if (je.getJumpType() == JumpException.JumpType.BreakJump) {
143                     return (IRubyObject) je.getValue();
144                 } else if (je.getJumpType() == JumpException.JumpType.ReturnJump) {
145                     return (IRubyObject) je.getTarget();
146                 } else if (je.getJumpType() == JumpException.JumpType.RetryJump) {
147                     // Execute iterateMethod again.
148
} else {
149                     throw je;
150                 }
151             }
152         }
153     }
154
155     /** Create a Proc object which is called like a ruby method.
156      *
157      * Used by the RubyMethod#to_proc method.
158      *
159      */

160     public static IRubyObject mproc(IRubyObject recv, Block block) {
161         Ruby runtime = recv.getRuntime();
162         ThreadContext tc = runtime.getCurrentContext();
163         
164         tc.preMproc();
165         
166         try {
167             return RubyKernel.proc(recv, block);
168         } finally {
169             tc.postMproc();
170         }
171     }
172
173     /** Delegate a block call to a bound method call.
174      *
175      * Used by the RubyMethod#to_proc method.
176      *
177      */

178     public static IRubyObject bmcall(IRubyObject blockArg, IRubyObject arg1, IRubyObject self, Block unusedBlock) {
179         if (blockArg instanceof RubyArray) {
180             // ENEBO: Very wrong
181
return ((RubyMethod) arg1).call(((RubyArray) blockArg).toJavaArray(), Block.NULL_BLOCK);
182         }
183         // ENEBO: Very wrong
184
return ((RubyMethod) arg1).call(new IRubyObject[] { blockArg }, Block.NULL_BLOCK);
185     }
186
187     public RubyUnboundMethod unbind(Block unusedBlock) {
188         RubyUnboundMethod unboundMethod =
189             RubyUnboundMethod.newUnboundMethod(implementationModule, methodName, originModule, originName, method);
190         unboundMethod.receiver = this;
191         unboundMethod.infectBy(this);
192         
193         return unboundMethod;
194     }
195     
196     public IRubyObject inspect() {
197         String JavaDoc cname = getMetaClass().getRealClass().getName();
198         RubyString str = getRuntime().newString("#<" + cname + ": " + originModule.getName() + "#" + methodName + ">");
199         str.setTaint(isTaint());
200         return str;
201     }
202 }
203
204
Popular Tags