001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2002 Jan Arne Petersen <jpetersen@uni-bonn.de>
015: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
016: * Copyright (C) 2005 Thomas E Enebo <enebo@acm.org>
017: *
018: * Alternatively, the contents of this file may be used under the terms of
019: * either of the GNU General Public License Version 2 or later (the "GPL"),
020: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
021: * in which case the provisions of the GPL or the LGPL are applicable instead
022: * of those above. If you wish to allow use of your version of this file only
023: * under the terms of either the GPL or the LGPL, and not to allow others to
024: * use your version of this file under the terms of the CPL, indicate your
025: * decision by deleting the provisions above and replace them with the notice
026: * and other provisions required by the GPL or the LGPL. If you do not delete
027: * the provisions above, a recipient may use your version of this file under
028: * the terms of any one of the CPL, the GPL or the LGPL.
029: ***** END LICENSE BLOCK *****/package org.jruby.internal.runtime.methods;
030:
031: import org.jruby.RubyModule;
032: import org.jruby.runtime.Arity;
033: import org.jruby.runtime.Block;
034: import org.jruby.runtime.CallType;
035: import org.jruby.runtime.ThreadContext;
036: import org.jruby.runtime.Visibility;
037: import org.jruby.runtime.builtin.IRubyObject;
038:
039: /**
040: *
041: * @author jpetersen
042: */
043: public abstract class DynamicMethod {
044: protected RubyModule implementationClass;
045: protected Visibility visibility;
046: private boolean needsImplementer;
047:
048: protected DynamicMethod(RubyModule implementationClass,
049: Visibility visibility) {
050: this .visibility = visibility;
051: this .implementationClass = implementationClass;
052: if (implementationClass != null) {
053: boolean implIsClass = implementationClass.isClass();
054: boolean implIsKernel = implementationClass == implementationClass
055: .getRuntime().getKernel();
056: needsImplementer = !(implIsClass || implIsKernel);
057: }
058: }
059:
060: /**
061: * Call the method
062: * @param context is the thread-specific information that this method is being invoked on
063: * @param receiver
064: */
065: public IRubyObject call(ThreadContext context, IRubyObject self,
066: RubyModule clazz, String name, IRubyObject[] args,
067: boolean noSuper, Block block) {
068: // FIXME: this potentially should go in overridden call impls too, but so far it hasn't appeared to be necessary
069: RubyModule implementer = null;
070: if (needsImplementer) {
071: // modules are included with a shim class; we must find that shim to handle super() appropriately
072: implementer = clazz
073: .findImplementer(getImplementationClass());
074: } else {
075: // classes are directly in the hierarchy, so no special logic is necessary for implementer
076: implementer = getImplementationClass();
077: }
078:
079: preMethod(context, implementer, self, name, args, noSuper,
080: block);
081:
082: try {
083: return internalCall(context, implementer, self, name, args,
084: noSuper, block);
085: } finally {
086: postMethod(context);
087: }
088: }
089:
090: protected abstract void postMethod(ThreadContext context);
091:
092: protected abstract IRubyObject internalCall(ThreadContext context,
093: RubyModule clazz, IRubyObject self, String name,
094: IRubyObject[] args, boolean noSuper, Block block);
095:
096: protected abstract void preMethod(ThreadContext context,
097: RubyModule clazz, IRubyObject self, String name,
098: IRubyObject[] args, boolean noSuper, Block block);
099:
100: public abstract DynamicMethod dup();
101:
102: public boolean isCallableFrom(IRubyObject caller, CallType callType) {
103: if (getVisibility().isPrivate()
104: && (callType == CallType.NORMAL)) {
105: return false;
106: } else if (getVisibility().isProtected()) {
107: RubyModule defined = getImplementationClass();
108: while (defined.isIncluded()) {
109: defined = defined.getMetaClass();
110: }
111:
112: if (!caller.isKindOf(defined))
113: return false;
114: }
115:
116: return true;
117: }
118:
119: public RubyModule getImplementationClass() {
120: return implementationClass;
121: }
122:
123: public void setImplementationClass(RubyModule implClass) {
124: implementationClass = implClass;
125: }
126:
127: public Visibility getVisibility() {
128: return visibility;
129: }
130:
131: public void setVisibility(Visibility visibility) {
132: this .visibility = visibility;
133: }
134:
135: public boolean isUndefined() {
136: return false;
137: }
138:
139: public Arity getArity() {
140: return Arity.optional();
141: }
142: }
|