0001: /***** BEGIN LICENSE BLOCK *****
0002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
0003: *
0004: * The contents of this file are subject to the Common Public
0005: * License Version 1.0 (the "License"); you may not use this file
0006: * except in compliance with the License. You may obtain a copy of
0007: * the License at http://www.eclipse.org/legal/cpl-v10.html
0008: *
0009: * Software distributed under the License is distributed on an "AS
0010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0011: * implied. See the License for the specific language governing
0012: * rights and limitations under the License.
0013: *
0014: * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
0015: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
0016: * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
0017: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
0018: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
0019: * Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org>
0020: * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
0021: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
0022: * Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
0023: * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
0024: * Copyright (C) 2007 MenTaLguY <mental@rydia.net>
0025: *
0026: * Alternatively, the contents of this file may be used under the terms of
0027: * either of the GNU General Public License Version 2 or later (the "GPL"),
0028: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
0029: * in which case the provisions of the GPL or the LGPL are applicable instead
0030: * of those above. If you wish to allow use of your version of this file only
0031: * under the terms of either the GPL or the LGPL, and not to allow others to
0032: * use your version of this file under the terms of the CPL, indicate your
0033: * decision by deleting the provisions above and replace them with the notice
0034: * and other provisions required by the GPL or the LGPL. If you do not delete
0035: * the provisions above, a recipient may use your version of this file under
0036: * the terms of any one of the CPL, the GPL or the LGPL.
0037: ***** END LICENSE BLOCK *****/package org.jruby;
0038:
0039: import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
0040: import org.jruby.evaluator.EvaluationState;
0041: import org.jruby.exceptions.JumpException;
0042: import org.jruby.internal.runtime.methods.DynamicMethod;
0043: import org.jruby.lexer.yacc.ISourcePosition;
0044: import org.jruby.runtime.Arity;
0045: import org.jruby.runtime.Block;
0046: import org.jruby.runtime.CallType;
0047: import org.jruby.runtime.CallbackFactory;
0048: import org.jruby.runtime.ObjectAllocator;
0049: import org.jruby.runtime.ThreadContext;
0050: import org.jruby.runtime.Visibility;
0051: import org.jruby.runtime.builtin.IRubyObject;
0052: import org.jruby.runtime.callback.Callback;
0053: import org.jruby.util.IdUtil;
0054: import org.jruby.util.collections.SinglyLinkedList;
0055: import java.util.ArrayList;
0056: import java.util.Collections;
0057: import java.util.HashMap;
0058: import java.util.Iterator;
0059: import java.util.List;
0060: import java.util.Map;
0061: import org.jruby.ast.Node;
0062: import org.jruby.runtime.ClassIndex;
0063: import org.jruby.runtime.MethodIndex;
0064:
0065: /**
0066: *
0067: * @author jpetersen
0068: */
0069: public class RubyObject implements Cloneable, IRubyObject {
0070:
0071: private RubyObject() {
0072: };
0073:
0074: // An instance that never equals any other instance
0075: public static final IRubyObject NEVER = new RubyObject();
0076:
0077: // The class of this object
0078: protected RubyClass metaClass;
0079:
0080: // The instance variables of this object.
0081: protected Map instanceVariables;
0082:
0083: private transient Object dataStruct;
0084:
0085: // The two properties frozen and taint
0086: private boolean frozen;
0087: private boolean taint;
0088: protected boolean isTrue = true;
0089:
0090: private Finalizer finalizer;
0091:
0092: public class Finalizer implements Finalizable {
0093: private long id;
0094: private List finalizers;
0095: private AtomicBoolean finalized;
0096:
0097: public Finalizer(long id) {
0098: this .id = id;
0099: this .finalized = new AtomicBoolean(false);
0100: }
0101:
0102: public void addFinalizer(RubyProc finalizer) {
0103: if (finalizers == null) {
0104: finalizers = new ArrayList();
0105: }
0106: finalizers.add(finalizer);
0107: }
0108:
0109: public void removeFinalizers() {
0110: finalizers = null;
0111: }
0112:
0113: public void finalize() {
0114: if (finalized.compareAndSet(false, true)) {
0115: if (finalizers != null) {
0116: IRubyObject idFixnum = getRuntime().newFixnum(id);
0117: for (int i = 0; i < finalizers.size(); i++) {
0118: ((RubyProc) finalizers.get(i))
0119: .call(new IRubyObject[] { idFixnum });
0120: }
0121: }
0122: }
0123: }
0124: }
0125:
0126: public RubyObject(Ruby runtime, RubyClass metaClass) {
0127: this (runtime, metaClass, runtime.isObjectSpaceEnabled());
0128: }
0129:
0130: public RubyObject(Ruby runtime, RubyClass metaClass,
0131: boolean useObjectSpace) {
0132: this .metaClass = metaClass;
0133: this .frozen = false;
0134: this .taint = false;
0135:
0136: // Do not store any immediate objects into objectspace.
0137: if (useObjectSpace && !isImmediate()) {
0138: runtime.getObjectSpace().add(this );
0139: }
0140:
0141: // FIXME are there objects who shouldn't be tainted?
0142: // (mri: OBJSETUP)
0143: taint |= runtime.getSafeLevel() >= 3;
0144: }
0145:
0146: public static RubyClass createObjectClass(Ruby runtime,
0147: RubyClass objectClass) {
0148: CallbackFactory callbackFactory = runtime
0149: .callbackFactory(RubyObject.class);
0150: objectClass.index = ClassIndex.OBJECT;
0151:
0152: objectClass.definePrivateMethod("initialize", callbackFactory
0153: .getOptMethod("initialize"));
0154: objectClass.definePrivateMethod("inherited", callbackFactory
0155: .getMethod("inherited", IRubyObject.class));
0156:
0157: return objectClass;
0158: }
0159:
0160: public static ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() {
0161: public IRubyObject allocate(Ruby runtime, RubyClass klass) {
0162: IRubyObject instance = new RubyObject(runtime, klass);
0163: instance.setMetaClass(klass);
0164:
0165: return instance;
0166: }
0167: };
0168:
0169: public void attachToObjectSpace() {
0170: getRuntime().getObjectSpace().add(this );
0171: }
0172:
0173: /**
0174: * This is overridden in the other concrete Java builtins to provide a fast way
0175: * to determine what type they are.
0176: */
0177: public int getNativeTypeIndex() {
0178: return ClassIndex.OBJECT;
0179: }
0180:
0181: /*
0182: * Is object immediate (def: Fixnum, Symbol, true, false, nil?).
0183: */
0184: public boolean isImmediate() {
0185: return false;
0186: }
0187:
0188: /**
0189: * Create a new meta class.
0190: *
0191: * @since Ruby 1.6.7
0192: */
0193: public RubyClass makeMetaClass(RubyClass super Class,
0194: SinglyLinkedList parentCRef) {
0195: RubyClass klass = new MetaClass(getRuntime(), super Class,
0196: getMetaClass().getAllocator(), parentCRef);
0197: setMetaClass(klass);
0198:
0199: klass.setInstanceVariable("__attached__", this );
0200:
0201: if (this instanceof RubyClass && isSingleton()) { // could be pulled down to RubyClass in future
0202: klass.setMetaClass(klass);
0203: klass.setSuperClass(((RubyClass) this ).getSuperClass()
0204: .getRealClass().getMetaClass());
0205: } else {
0206: klass
0207: .setMetaClass(super Class.getRealClass()
0208: .getMetaClass());
0209: }
0210:
0211: // use same ClassIndex as metaclass, since we're technically still of that type
0212: klass.index = super Class.index;
0213: return klass;
0214: }
0215:
0216: public boolean isSingleton() {
0217: return false;
0218: }
0219:
0220: public Class getJavaClass() {
0221: return IRubyObject.class;
0222: }
0223:
0224: public static void puts(Object obj) {
0225: System.out.println(obj.toString());
0226: }
0227:
0228: /**
0229: * This method is just a wrapper around the Ruby "==" method,
0230: * provided so that RubyObjects can be used as keys in the Java
0231: * HashMap object underlying RubyHash.
0232: */
0233: public boolean equals(Object other) {
0234: return other == this
0235: || other instanceof IRubyObject
0236: && callMethod(getRuntime().getCurrentContext(),
0237: MethodIndex.EQUALEQUAL, "==",
0238: (IRubyObject) other).isTrue();
0239: }
0240:
0241: public String toString() {
0242: return callMethod(getRuntime().getCurrentContext(),
0243: MethodIndex.TO_S, "to_s", IRubyObject.NULL_ARRAY)
0244: .toString();
0245: }
0246:
0247: /** Getter for property ruby.
0248: * @return Value of property ruby.
0249: */
0250: public Ruby getRuntime() {
0251: return metaClass.getRuntime();
0252: }
0253:
0254: public boolean safeHasInstanceVariables() {
0255: return instanceVariables != null
0256: && instanceVariables.size() > 0;
0257: }
0258:
0259: public Map safeGetInstanceVariables() {
0260: return instanceVariables == null ? null
0261: : getInstanceVariablesSnapshot();
0262: }
0263:
0264: public IRubyObject removeInstanceVariable(String name) {
0265: return (IRubyObject) getInstanceVariables().remove(name);
0266: }
0267:
0268: /**
0269: * Returns an unmodifiable snapshot of the current state of instance variables.
0270: * This method synchronizes access to avoid deadlocks.
0271: */
0272: public Map getInstanceVariablesSnapshot() {
0273: synchronized (getInstanceVariables()) {
0274: return Collections.unmodifiableMap(new HashMap(
0275: getInstanceVariables()));
0276: }
0277: }
0278:
0279: public Map getInstanceVariables() {
0280: // TODO: double checking may or may not be safe enough here
0281: if (instanceVariables == null) {
0282: synchronized (this ) {
0283: if (instanceVariables == null) {
0284: instanceVariables = Collections
0285: .synchronizedMap(new HashMap());
0286: }
0287: }
0288: }
0289: return instanceVariables;
0290: }
0291:
0292: public void setInstanceVariables(Map instanceVariables) {
0293: this .instanceVariables = Collections
0294: .synchronizedMap(instanceVariables);
0295: }
0296:
0297: /**
0298: * if exist return the meta-class else return the type of the object.
0299: *
0300: */
0301: public final RubyClass getMetaClass() {
0302: return metaClass;
0303: }
0304:
0305: public void setMetaClass(RubyClass metaClass) {
0306: this .metaClass = metaClass;
0307: }
0308:
0309: /**
0310: * Gets the frozen.
0311: * @return Returns a boolean
0312: */
0313: public boolean isFrozen() {
0314: return frozen;
0315: }
0316:
0317: /**
0318: * Sets the frozen.
0319: * @param frozen The frozen to set
0320: */
0321: public void setFrozen(boolean frozen) {
0322: this .frozen = frozen;
0323: }
0324:
0325: /** rb_frozen_class_p
0326: *
0327: */
0328: protected void testFrozen(String message) {
0329: if (isFrozen()) {
0330: throw getRuntime().newFrozenError(
0331: message + getMetaClass().getName());
0332: }
0333: }
0334:
0335: protected void checkFrozen() {
0336: testFrozen("can't modify frozen ");
0337: }
0338:
0339: /**
0340: * Gets the taint.
0341: * @return Returns a boolean
0342: */
0343: public boolean isTaint() {
0344: return taint;
0345: }
0346:
0347: /**
0348: * Sets the taint.
0349: * @param taint The taint to set
0350: */
0351: public void setTaint(boolean taint) {
0352: this .taint = taint;
0353: }
0354:
0355: public boolean isNil() {
0356: return false;
0357: }
0358:
0359: public final boolean isTrue() {
0360: return isTrue;
0361: }
0362:
0363: public final boolean isFalse() {
0364: return !isTrue;
0365: }
0366:
0367: public boolean respondsTo(String name) {
0368: if (getMetaClass().searchMethod("respond_to?") == getRuntime()
0369: .getRespondToMethod()) {
0370: return getMetaClass().isMethodBound(name, false);
0371: } else {
0372: return callMethod(getRuntime().getCurrentContext(),
0373: "respond_to?", getRuntime().newSymbol(name))
0374: .isTrue();
0375: }
0376: }
0377:
0378: public boolean isKindOf(RubyModule type) {
0379: return getMetaClass().hasModuleInHierarchy(type);
0380: }
0381:
0382: /** rb_singleton_class
0383: *
0384: */
0385: public RubyClass getSingletonClass() {
0386: RubyClass klass;
0387:
0388: if (getMetaClass().isSingleton()
0389: && getMetaClass().getInstanceVariable("__attached__") == this ) {
0390: klass = getMetaClass();
0391: } else {
0392: klass = makeMetaClass(getMetaClass(), getMetaClass()
0393: .getCRef());
0394: }
0395:
0396: klass.setTaint(isTaint());
0397: klass.setFrozen(isFrozen());
0398:
0399: return klass;
0400: }
0401:
0402: /** rb_singleton_class_clone
0403: *
0404: */
0405: public RubyClass getSingletonClassClone() {
0406: RubyClass klass = getMetaClass();
0407:
0408: if (!klass.isSingleton()) {
0409: return klass;
0410: }
0411:
0412: MetaClass clone = new MetaClass(getRuntime(), klass
0413: .getSuperClass(), getMetaClass().getAllocator(),
0414: getMetaClass().getCRef());
0415: clone.setFrozen(klass.isFrozen());
0416: clone.setTaint(klass.isTaint());
0417:
0418: if (this instanceof RubyClass) {
0419: clone.setMetaClass(clone);
0420: } else {
0421: clone.setMetaClass(klass.getSingletonClassClone());
0422: }
0423:
0424: if (klass.safeHasInstanceVariables()) {
0425: clone.setInstanceVariables(new HashMap(klass
0426: .getInstanceVariables()));
0427: }
0428:
0429: klass.cloneMethods(clone);
0430:
0431: clone.getMetaClass().setInstanceVariable("__attached__", clone);
0432:
0433: return clone;
0434: }
0435:
0436: /** init_copy
0437: *
0438: */
0439: public static void initCopy(IRubyObject clone, IRubyObject original) {
0440: assert original != null;
0441: assert !clone.isFrozen() : "frozen object ("
0442: + clone.getMetaClass().getName() + ") allocated";
0443:
0444: if (original.safeHasInstanceVariables()) {
0445: clone.setInstanceVariables(new HashMap(original
0446: .getInstanceVariables()));
0447: }
0448:
0449: /* FIXME: finalizer should be dupped here */
0450: clone.callMethod(clone.getRuntime().getCurrentContext(),
0451: "initialize_copy", original);
0452: }
0453:
0454: /** OBJ_INFECT
0455: *
0456: */
0457: public IRubyObject infectBy(IRubyObject obj) {
0458: setTaint(isTaint() || obj.isTaint());
0459:
0460: return this ;
0461: }
0462:
0463: public IRubyObject callSuper(ThreadContext context,
0464: IRubyObject[] args, Block block) {
0465: RubyModule klazz = context.getFrameKlazz();
0466:
0467: RubyClass super Class = klazz.getSuperClass();
0468:
0469: assert super Class != null : "Superclass should always be something for "
0470: + klazz.getBaseName();
0471:
0472: return callMethod(context, super Class, context.getFrameName(),
0473: args, CallType.SUPER, block);
0474: }
0475:
0476: /**
0477: *
0478: */
0479: public IRubyObject callMethod(ThreadContext context, String name,
0480: IRubyObject[] args) {
0481: return callMethod(context, getMetaClass(), name, args,
0482: CallType.FUNCTIONAL, Block.NULL_BLOCK);
0483: }
0484:
0485: public IRubyObject callMethod(ThreadContext context, String name,
0486: IRubyObject[] args, Block block) {
0487: return callMethod(context, getMetaClass(), name, args,
0488: CallType.FUNCTIONAL, block);
0489: }
0490:
0491: /**
0492: *
0493: */
0494: public IRubyObject callMethod(ThreadContext context, String name,
0495: IRubyObject[] args, CallType callType) {
0496: return callMethod(context, getMetaClass(), name, args,
0497: callType, Block.NULL_BLOCK);
0498: }
0499:
0500: public IRubyObject callMethod(ThreadContext context, String name,
0501: IRubyObject[] args, CallType callType, Block block) {
0502: return callMethod(context, getMetaClass(), name, args,
0503: callType, block);
0504: }
0505:
0506: public IRubyObject callMethod(ThreadContext context,
0507: int methodIndex, String name, IRubyObject arg) {
0508: return callMethod(context, getMetaClass(), methodIndex, name,
0509: new IRubyObject[] { arg }, CallType.FUNCTIONAL,
0510: Block.NULL_BLOCK);
0511: }
0512:
0513: public IRubyObject callMethod(ThreadContext context,
0514: int methodIndex, String name, IRubyObject[] args) {
0515: return callMethod(context, getMetaClass(), methodIndex, name,
0516: args, CallType.FUNCTIONAL, Block.NULL_BLOCK);
0517: }
0518:
0519: public IRubyObject callMethod(ThreadContext context,
0520: int methodIndex, String name, IRubyObject[] args,
0521: CallType callType) {
0522: return callMethod(context, getMetaClass(), methodIndex, name,
0523: args, callType, Block.NULL_BLOCK);
0524: }
0525:
0526: /**
0527: * Used by the compiler to ease calling indexed methods, also to handle visibility.
0528: * NOTE: THIS IS NOT THE SAME AS THE SWITCHVALUE VERSIONS.
0529: */
0530: public IRubyObject compilerCallMethodWithIndex(
0531: ThreadContext context, int methodIndex, String name,
0532: IRubyObject[] args, IRubyObject self, CallType callType,
0533: Block block) {
0534: RubyModule module = getMetaClass();
0535:
0536: if (module.index != 0) {
0537: return callMethod(context, module, methodIndex, name, args,
0538: callType, block);
0539: }
0540:
0541: return compilerCallMethod(context, name, args, self, callType,
0542: block);
0543: }
0544:
0545: /**
0546: * Used by the compiler to handle visibility
0547: */
0548: public IRubyObject compilerCallMethod(ThreadContext context,
0549: String name, IRubyObject[] args, IRubyObject self,
0550: CallType callType, Block block) {
0551: assert args != null;
0552: DynamicMethod method = null;
0553: RubyModule rubyclass = getMetaClass();
0554: method = rubyclass.searchMethod(name);
0555:
0556: if (method.isUndefined()
0557: || (!name.equals("method_missing") && !method
0558: .isCallableFrom(self, callType))) {
0559: return callMethodMissing(context, this , method, name, args,
0560: self, callType, block);
0561: }
0562:
0563: return method.call(context, this , rubyclass, name, args, false,
0564: block);
0565: }
0566:
0567: public static IRubyObject callMethodMissing(ThreadContext context,
0568: IRubyObject receiver, DynamicMethod method, String name,
0569: int methodIndex, IRubyObject[] args, IRubyObject self,
0570: CallType callType, Block block) {
0571: // store call information so method_missing impl can use it
0572: context.setLastCallStatus(callType);
0573: context.setLastVisibility(method.getVisibility());
0574:
0575: if (methodIndex == MethodIndex.METHOD_MISSING) {
0576: return RubyKernel.method_missing(self, args, block);
0577: }
0578:
0579: IRubyObject[] newArgs = new IRubyObject[args.length + 1];
0580: System.arraycopy(args, 0, newArgs, 1, args.length);
0581: newArgs[0] = RubySymbol.newSymbol(self.getRuntime(), name);
0582:
0583: return receiver.callMethod(context, "method_missing", newArgs,
0584: block);
0585: }
0586:
0587: public static IRubyObject callMethodMissing(ThreadContext context,
0588: IRubyObject receiver, DynamicMethod method, String name,
0589: IRubyObject[] args, IRubyObject self, CallType callType,
0590: Block block) {
0591: // store call information so method_missing impl can use it
0592: context.setLastCallStatus(callType);
0593: context.setLastVisibility(method.getVisibility());
0594:
0595: if (name.equals("method_missing")) {
0596: return RubyKernel.method_missing(self, args, block);
0597: }
0598:
0599: IRubyObject[] newArgs = new IRubyObject[args.length + 1];
0600: System.arraycopy(args, 0, newArgs, 1, args.length);
0601: newArgs[0] = RubySymbol.newSymbol(self.getRuntime(), name);
0602:
0603: return receiver.callMethod(context, "method_missing", newArgs,
0604: block);
0605: }
0606:
0607: /**
0608: *
0609: */
0610: public IRubyObject callMethod(ThreadContext context,
0611: RubyModule rubyclass, int methodIndex, String name,
0612: IRubyObject[] args, CallType callType) {
0613: return callMethod(context, rubyclass, methodIndex, name, args,
0614: callType, Block.NULL_BLOCK);
0615: }
0616:
0617: /**
0618: *
0619: */
0620: public IRubyObject callMethod(ThreadContext context,
0621: RubyModule rubyclass, int methodIndex, String name,
0622: IRubyObject[] args, CallType callType, Block block) {
0623: return callMethod(context, rubyclass, name, args, callType,
0624: block);
0625: }
0626:
0627: /**
0628: *
0629: */
0630: public IRubyObject callMethod(ThreadContext context,
0631: RubyModule rubyclass, String name, IRubyObject[] args,
0632: CallType callType, Block block) {
0633: assert args != null;
0634: DynamicMethod method = null;
0635: method = rubyclass.searchMethod(name);
0636:
0637: if (method.isUndefined()
0638: || (!name.equals("method_missing") && !method
0639: .isCallableFrom(context.getFrameSelf(),
0640: callType))) {
0641: return callMethodMissing(context, this , method, name, args,
0642: context.getFrameSelf(), callType, block);
0643: }
0644:
0645: return method.call(context, this , rubyclass, name, args, false,
0646: block);
0647: }
0648:
0649: public IRubyObject callMethod(ThreadContext context, String name) {
0650: return callMethod(context, getMetaClass(), name,
0651: IRubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
0652: }
0653:
0654: public IRubyObject callMethod(ThreadContext context,
0655: int methodIndex, String name) {
0656: return callMethod(context, getMetaClass(), methodIndex, name,
0657: IRubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
0658: }
0659:
0660: public IRubyObject callMethod(ThreadContext context, String name,
0661: Block block) {
0662: return callMethod(context, getMetaClass(), name,
0663: IRubyObject.NULL_ARRAY, null, block);
0664: }
0665:
0666: /**
0667: * rb_funcall
0668: *
0669: */
0670: public IRubyObject callMethod(ThreadContext context, String name,
0671: IRubyObject arg) {
0672: return callMethod(context, name, new IRubyObject[] { arg });
0673: }
0674:
0675: public IRubyObject instance_variable_get(IRubyObject var) {
0676: String varName = var.asSymbol();
0677:
0678: if (!IdUtil.isInstanceVariable(varName)) {
0679: throw getRuntime()
0680: .newNameError(
0681: "`"
0682: + varName
0683: + "' is not allowable as an instance variable name",
0684: varName);
0685: }
0686:
0687: IRubyObject variable = getInstanceVariable(varName);
0688:
0689: // Pickaxe v2 says no var should show NameError, but ruby only sends back nil..
0690: return variable == null ? getRuntime().getNil() : variable;
0691: }
0692:
0693: public IRubyObject getInstanceVariable(String name) {
0694: return (IRubyObject) getInstanceVariables().get(name);
0695: }
0696:
0697: public IRubyObject instance_variable_set(IRubyObject var,
0698: IRubyObject value) {
0699: String varName = var.asSymbol();
0700:
0701: if (!IdUtil.isInstanceVariable(varName)) {
0702: throw getRuntime()
0703: .newNameError(
0704: "`"
0705: + varName
0706: + "' is not allowable as an instance variable name",
0707: varName);
0708: }
0709:
0710: return setInstanceVariable(var.asSymbol(), value);
0711: }
0712:
0713: public IRubyObject setInstanceVariable(String name,
0714: IRubyObject value, String taintError, String freezeError) {
0715: if (isTaint() && getRuntime().getSafeLevel() >= 4) {
0716: throw getRuntime().newSecurityError(taintError);
0717: }
0718: testFrozen(freezeError);
0719:
0720: getInstanceVariables().put(name, value);
0721:
0722: return value;
0723: }
0724:
0725: /** rb_iv_set / rb_ivar_set
0726: *
0727: */
0728: public IRubyObject setInstanceVariable(String name,
0729: IRubyObject value) {
0730: return setInstanceVariable(name, value,
0731: "Insecure: can't modify instance variable", "");
0732: }
0733:
0734: public Iterator instanceVariableNames() {
0735: return getInstanceVariables().keySet().iterator();
0736: }
0737:
0738: public void callInit(IRubyObject[] args, Block block) {
0739: callMethod(getRuntime().getCurrentContext(), "initialize",
0740: args, block);
0741: }
0742:
0743: /** rb_to_id
0744: *
0745: */
0746: public String asSymbol() {
0747: throw getRuntime().newTypeError(
0748: inspect().toString() + " is not a symbol");
0749: }
0750:
0751: public static String trueFalseNil(IRubyObject v) {
0752: return trueFalseNil(v.getMetaClass().getRealClass().getName());
0753: }
0754:
0755: public static String trueFalseNil(String v) {
0756: if ("TrueClass".equals(v)) {
0757: return "true";
0758: } else if ("FalseClass".equals(v)) {
0759: return "false";
0760: } else if ("NilClass".equals(v)) {
0761: return "nil";
0762: }
0763: return v;
0764: }
0765:
0766: public RubyArray convertToArray() {
0767: return (RubyArray) convertToType(getRuntime().getArray(),
0768: MethodIndex.TO_ARY, true);
0769: }
0770:
0771: public RubyHash convertToHash() {
0772: return (RubyHash) convertToType(getRuntime().getHash(),
0773: MethodIndex.TO_HASH, "to_hash", true, true, false);
0774: }
0775:
0776: public RubyFloat convertToFloat() {
0777: return (RubyFloat) convertToType(
0778: getRuntime().getClass("Float"), MethodIndex.TO_F, true);
0779: }
0780:
0781: public RubyInteger convertToInteger() {
0782: return (RubyInteger) convertToType(getRuntime().getClass(
0783: "Integer"), MethodIndex.TO_INT, true);
0784: }
0785:
0786: public RubyString convertToString() {
0787: return (RubyString) convertToType(getRuntime().getString(),
0788: MethodIndex.TO_STR, true);
0789: }
0790:
0791: /*
0792: * @see org.jruby.runtime.builtin.IRubyObject#convertToTypeWithCheck(java.lang.String, java.lang.String)
0793: */
0794: public IRubyObject convertToTypeWithCheck(RubyClass targetType,
0795: int convertMethodIndex, String convertMethod) {
0796: return convertToType(targetType, convertMethodIndex,
0797: convertMethod, false, true, true);
0798: }
0799:
0800: /*
0801: * @see org.jruby.runtime.builtin.IRubyObject#convertToType(java.lang.String, java.lang.String, boolean)
0802: */
0803: public IRubyObject convertToType(RubyClass targetType,
0804: int convertMethodIndex, String convertMethod, boolean raise) {
0805: return convertToType(targetType, convertMethodIndex,
0806: convertMethod, raise, false, false);
0807: }
0808:
0809: /*
0810: * @see org.jruby.runtime.builtin.IRubyObject#convertToType(java.lang.String, java.lang.String, boolean)
0811: */
0812: public IRubyObject convertToType(RubyClass targetType,
0813: int convertMethodIndex, boolean raise) {
0814: return convertToType(targetType, convertMethodIndex,
0815: MethodIndex.NAMES[convertMethodIndex], raise, true,
0816: false);
0817: }
0818:
0819: public IRubyObject convertToType(RubyClass targetType,
0820: int convertMethodIndex, String convertMethod,
0821: boolean raiseOnMissingMethod,
0822: boolean raiseOnWrongTypeResult, boolean allowNilThrough) {
0823: if (isKindOf(targetType)) {
0824: return this ;
0825: }
0826:
0827: if (!respondsTo(convertMethod)) {
0828: if (raiseOnMissingMethod) {
0829: throw getRuntime().newTypeError(
0830: "can't convert " + trueFalseNil(this )
0831: + " into "
0832: + trueFalseNil(targetType.getName()));
0833: }
0834:
0835: return getRuntime().getNil();
0836: }
0837:
0838: IRubyObject value = callMethod(
0839: getRuntime().getCurrentContext(), convertMethodIndex,
0840: convertMethod, IRubyObject.NULL_ARRAY);
0841:
0842: if (allowNilThrough && value.isNil()) {
0843: return value;
0844: }
0845:
0846: if (raiseOnWrongTypeResult && !value.isKindOf(targetType)) {
0847: throw getRuntime().newTypeError(
0848: getMetaClass().getName() + "#" + convertMethod
0849: + " should return " + targetType);
0850: }
0851:
0852: return value;
0853: }
0854:
0855: /** rb_obj_as_string
0856: */
0857: public RubyString asString() {
0858: if (this instanceof RubyString)
0859: return (RubyString) this ;
0860:
0861: IRubyObject str = this .callMethod(getRuntime()
0862: .getCurrentContext(), MethodIndex.TO_S, "to_s",
0863: IRubyObject.NULL_ARRAY);
0864:
0865: if (!(str instanceof RubyString))
0866: str = anyToString();
0867:
0868: return (RubyString) str;
0869: }
0870:
0871: /** rb_check_string_type
0872: *
0873: */
0874: public IRubyObject checkStringType() {
0875: IRubyObject str = convertToTypeWithCheck(getRuntime()
0876: .getString(), MethodIndex.TO_STR, "to_str");
0877: if (!str.isNil() && !(str instanceof RubyString)) {
0878: str = getRuntime().newString("");
0879: }
0880: return str;
0881: }
0882:
0883: /** rb_check_array_type
0884: *
0885: */
0886: public IRubyObject checkArrayType() {
0887: return convertToTypeWithCheck(getRuntime().getArray(),
0888: MethodIndex.TO_ARY, "to_ary");
0889: }
0890:
0891: /** specific_eval
0892: *
0893: */
0894: public IRubyObject specificEval(RubyModule mod, IRubyObject[] args,
0895: Block block) {
0896: if (block.isGiven()) {
0897: if (args.length > 0)
0898: throw getRuntime().newArgumentError(args.length, 0);
0899:
0900: return yieldUnder(mod, new IRubyObject[] { this }, block);
0901: }
0902: ThreadContext tc = getRuntime().getCurrentContext();
0903:
0904: if (args.length == 0) {
0905: throw getRuntime().newArgumentError("block not supplied");
0906: } else if (args.length > 3) {
0907: String lastFuncName = tc.getFrameName();
0908: throw getRuntime().newArgumentError(
0909: "wrong # of arguments: " + lastFuncName
0910: + "(src) or " + lastFuncName + "{..}");
0911: }
0912: /*
0913: if (ruby.getSecurityLevel() >= 4) {
0914: Check_Type(argv[0], T_STRING);
0915: } else {
0916: Check_SafeStr(argv[0]);
0917: }
0918: */
0919:
0920: // We just want the TypeError if the argument doesn't convert to a String (JRUBY-386)
0921: args[0].convertToString();
0922:
0923: IRubyObject file = args.length > 1 ? args[1] : getRuntime()
0924: .newString("(eval)");
0925: IRubyObject line = args.length > 2 ? args[2] : RubyFixnum
0926: .one(getRuntime());
0927:
0928: Visibility savedVisibility = tc.getCurrentVisibility();
0929: tc.setCurrentVisibility(Visibility.PUBLIC);
0930: try {
0931: return evalUnder(mod, args[0], file, line);
0932: } finally {
0933: tc.setCurrentVisibility(savedVisibility);
0934: }
0935: }
0936:
0937: public IRubyObject evalUnder(RubyModule under, IRubyObject src,
0938: IRubyObject file, IRubyObject line) {
0939: return under.executeUnder(new Callback() {
0940: public IRubyObject execute(IRubyObject self,
0941: IRubyObject[] args, Block block) {
0942: IRubyObject source = args[1];
0943: IRubyObject filename = args[2];
0944: // FIXME: lineNumber is not supported
0945: //IRubyObject lineNumber = args[3];
0946:
0947: return args[0].evalSimple(source.getRuntime()
0948: .getCurrentContext(), source, filename
0949: .convertToString().toString());
0950: }
0951:
0952: public Arity getArity() {
0953: return Arity.optional();
0954: }
0955: }, new IRubyObject[] { this , src, file, line },
0956: Block.NULL_BLOCK);
0957: }
0958:
0959: private IRubyObject yieldUnder(RubyModule under,
0960: IRubyObject[] args, Block block) {
0961: final IRubyObject selfInYield = this ;
0962: return under.executeUnder(new Callback() {
0963: public IRubyObject execute(IRubyObject self,
0964: IRubyObject[] args, Block block) {
0965: ThreadContext context = getRuntime()
0966: .getCurrentContext();
0967:
0968: Visibility savedVisibility = block.getVisibility();
0969:
0970: block.setVisibility(Visibility.PUBLIC);
0971: try {
0972: IRubyObject valueInYield;
0973: boolean aValue;
0974: if (args.length == 1) {
0975: valueInYield = args[0];
0976: aValue = false;
0977: } else {
0978: valueInYield = RubyArray.newArray(getRuntime(),
0979: args);
0980: aValue = true;
0981: }
0982: return block
0983: .yield(context, valueInYield, selfInYield,
0984: context.getRubyClass(), aValue);
0985: //TODO: Should next and return also catch here?
0986: } catch (JumpException je) {
0987: if (je.getJumpType() == JumpException.JumpType.BreakJump) {
0988: return (IRubyObject) je.getValue();
0989: }
0990:
0991: throw je;
0992: } finally {
0993: block.setVisibility(savedVisibility);
0994: }
0995: }
0996:
0997: public Arity getArity() {
0998: return Arity.optional();
0999: }
1000: }, args, block);
1001: }
1002:
1003: /* (non-Javadoc)
1004: * @see org.jruby.runtime.builtin.IRubyObject#evalWithBinding(org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject, java.lang.String)
1005: */
1006: public IRubyObject evalWithBinding(ThreadContext context,
1007: IRubyObject src, IRubyObject scope, String file,
1008: int lineNumber) {
1009: // both of these are ensured by the (very few) callers
1010: assert !scope.isNil();
1011: assert file != null;
1012:
1013: ThreadContext threadContext = getRuntime().getCurrentContext();
1014: ISourcePosition savedPosition = threadContext.getPosition();
1015:
1016: if (!(scope instanceof RubyBinding)) {
1017: if (scope instanceof RubyProc) {
1018: scope = ((RubyProc) scope).binding();
1019: } else {
1020: // bomb out, it's not a binding or a proc
1021: throw getRuntime().newTypeError(
1022: "wrong argument type " + scope.getMetaClass()
1023: + " (expected Proc/Binding)");
1024: }
1025: }
1026:
1027: Block blockOfBinding = ((RubyBinding) scope).getBlock();
1028: try {
1029: // Binding provided for scope, use it
1030: threadContext.preEvalWithBinding(blockOfBinding);
1031: IRubyObject newSelf = threadContext.getFrameSelf();
1032: Node node = getRuntime().parse(src.toString(), file,
1033: blockOfBinding.getDynamicScope(), lineNumber);
1034:
1035: return EvaluationState.eval(getRuntime(), threadContext,
1036: node, newSelf, blockOfBinding);
1037: } catch (JumpException je) {
1038: if (je.getJumpType() == JumpException.JumpType.BreakJump) {
1039: throw getRuntime()
1040: .newLocalJumpError("break",
1041: (IRubyObject) je.getValue(),
1042: "unexpected break");
1043: }
1044: throw je;
1045: } finally {
1046: threadContext.postEvalWithBinding(blockOfBinding);
1047:
1048: // restore position
1049: threadContext.setPosition(savedPosition);
1050: }
1051: }
1052:
1053: /* (non-Javadoc)
1054: * @see org.jruby.runtime.builtin.IRubyObject#evalSimple(org.jruby.runtime.builtin.IRubyObject, java.lang.String)
1055: */
1056: public IRubyObject evalSimple(ThreadContext context,
1057: IRubyObject src, String file) {
1058: // this is ensured by the callers
1059: assert file != null;
1060:
1061: ISourcePosition savedPosition = context.getPosition();
1062:
1063: // no binding, just eval in "current" frame (caller's frame)
1064: try {
1065: Node node = getRuntime().parse(src.toString(), file,
1066: context.getCurrentScope(), 0);
1067:
1068: return EvaluationState.eval(getRuntime(), context, node,
1069: this , Block.NULL_BLOCK);
1070: } catch (JumpException je) {
1071: if (je.getJumpType() == JumpException.JumpType.BreakJump) {
1072: throw getRuntime()
1073: .newLocalJumpError("break",
1074: (IRubyObject) je.getValue(),
1075: "unexpected break");
1076: }
1077: throw je;
1078: } finally {
1079: // restore position
1080: context.setPosition(savedPosition);
1081: }
1082: }
1083:
1084: // Methods of the Object class (rb_obj_*):
1085:
1086: /** rb_obj_equal
1087: *
1088: */
1089: public IRubyObject obj_equal(IRubyObject obj) {
1090: return this == obj ? getRuntime().getTrue() : getRuntime()
1091: .getFalse();
1092: }
1093:
1094: /** rb_equal
1095: *
1096: */
1097: public IRubyObject equal(IRubyObject other) {
1098: if (this == other
1099: || callMethod(getRuntime().getCurrentContext(),
1100: MethodIndex.EQUALEQUAL, "==", other).isTrue()) {
1101: return getRuntime().getTrue();
1102: }
1103:
1104: return getRuntime().getFalse();
1105: }
1106:
1107: public final IRubyObject equalInternal(final ThreadContext context,
1108: final IRubyObject other) {
1109: if (this == other)
1110: return getRuntime().getTrue();
1111: return callMethod(context, MethodIndex.EQUALEQUAL, "==", other);
1112: }
1113:
1114: /** rb_eql
1115: * this method is not defind for Ruby objects directly.
1116: * notably overriden by RubyFixnum, RubyString, RubySymbol - these do a short-circuit calls.
1117: * see: rb_any_cmp() in hash.c
1118: * do not confuse this method with eql_p methods (which it calls by default), eql is mainly used for hash key comparison
1119: */
1120: public boolean eql(IRubyObject other) {
1121: return callMethod(getRuntime().getCurrentContext(),
1122: MethodIndex.EQL_P, "eql?", other).isTrue();
1123: }
1124:
1125: public final boolean eqlInternal(final ThreadContext context,
1126: final IRubyObject other) {
1127: if (this == other)
1128: return true;
1129: return callMethod(context, MethodIndex.EQL_P, "eql?", other)
1130: .isTrue();
1131: }
1132:
1133: /** rb_obj_init_copy
1134: *
1135: */
1136: public IRubyObject initialize_copy(IRubyObject original) {
1137: if (this == original)
1138: return this ;
1139:
1140: checkFrozen();
1141:
1142: if (getMetaClass().getRealClass() != original.getMetaClass()
1143: .getRealClass()) {
1144: throw getRuntime().newTypeError(
1145: "initialize_copy should take same class object");
1146: }
1147:
1148: return this ;
1149: }
1150:
1151: /**
1152: * respond_to?( aSymbol, includePriv=false ) -> true or false
1153: *
1154: * Returns true if this object responds to the given method. Private
1155: * methods are included in the search only if the optional second
1156: * parameter evaluates to true.
1157: *
1158: * @return true if this responds to the given method
1159: */
1160: public RubyBoolean respond_to(IRubyObject[] args) {
1161: Arity.checkArgumentCount(getRuntime(), args, 1, 2);
1162:
1163: String name = args[0].asSymbol();
1164: boolean includePrivate = args.length > 1 ? args[1].isTrue()
1165: : false;
1166:
1167: return getRuntime().newBoolean(
1168: getMetaClass().isMethodBound(name, !includePrivate));
1169: }
1170:
1171: /** Return the internal id of an object.
1172: *
1173: * <i>CRuby function: rb_obj_id</i>
1174: *
1175: */
1176: public synchronized RubyFixnum id() {
1177: return getRuntime().newFixnum(
1178: getRuntime().getObjectSpace().idOf(this ));
1179: }
1180:
1181: public synchronized RubyFixnum id_deprecated() {
1182: getRuntime().getWarnings().warn(
1183: "Object#id will be deprecated; use Object#object_id");
1184: return getRuntime().newFixnum(
1185: getRuntime().getObjectSpace().idOf(this ));
1186: }
1187:
1188: public RubyFixnum hash() {
1189: return getRuntime().newFixnum(super .hashCode());
1190: }
1191:
1192: public int hashCode() {
1193: IRubyObject hashValue = callMethod(getRuntime()
1194: .getCurrentContext(), MethodIndex.HASH, "hash");
1195:
1196: if (hashValue instanceof RubyFixnum)
1197: return (int) RubyNumeric.fix2long(hashValue);
1198:
1199: return super .hashCode();
1200: }
1201:
1202: /** rb_obj_type
1203: *
1204: */
1205: public RubyClass type() {
1206: return getMetaClass().getRealClass();
1207: }
1208:
1209: public RubyClass type_deprecated() {
1210: getRuntime().getWarnings().warn(
1211: "Object#type is deprecated; use Object#class");
1212: return type();
1213: }
1214:
1215: /** rb_obj_clone
1216: * should be overriden only by: Proc, Method, UnboundedMethod, Binding
1217: */
1218: public IRubyObject rbClone(Block unusedBlock) {
1219: if (isImmediate()) { // rb_special_const_p(obj) equivalent
1220: throw getRuntime().newTypeError(
1221: "can't clone " + getMetaClass().getName());
1222: }
1223:
1224: IRubyObject clone = doClone();
1225: clone.setMetaClass(getSingletonClassClone());
1226: clone.setTaint(isTaint());
1227: initCopy(clone, this );
1228: clone.setFrozen(isFrozen());
1229: return clone;
1230: }
1231:
1232: // Hack: allow RubyModule and RubyClass to override the allocation and return the the correct Java instance
1233: // Cloning a class object doesn't work otherwise and I don't really understand why --sma
1234: protected IRubyObject doClone() {
1235: RubyClass realClass = getMetaClass().getRealClass();
1236: return realClass.getAllocator().allocate(getRuntime(),
1237: realClass);
1238: }
1239:
1240: public IRubyObject display(IRubyObject[] args) {
1241: IRubyObject port = args.length == 0 ? getRuntime()
1242: .getGlobalVariables().get("$>") : args[0];
1243:
1244: port
1245: .callMethod(getRuntime().getCurrentContext(), "write",
1246: this );
1247:
1248: return getRuntime().getNil();
1249: }
1250:
1251: /** rb_obj_dup
1252: * should be overriden only by: Proc
1253: */
1254: public IRubyObject dup() {
1255: if (isImmediate()) {
1256: throw getRuntime().newTypeError(
1257: "can't dup " + getMetaClass().getName());
1258: }
1259:
1260: IRubyObject dup = doClone();
1261:
1262: dup.setMetaClass(type());
1263: dup.setFrozen(false);
1264: dup.setTaint(isTaint());
1265:
1266: initCopy(dup, this );
1267:
1268: return dup;
1269: }
1270:
1271: /** rb_obj_tainted
1272: *
1273: */
1274: public RubyBoolean tainted() {
1275: return getRuntime().newBoolean(isTaint());
1276: }
1277:
1278: /** rb_obj_taint
1279: *
1280: */
1281: public IRubyObject taint() {
1282: getRuntime().secure(4);
1283: if (!isTaint()) {
1284: testFrozen("object");
1285: setTaint(true);
1286: }
1287: return this ;
1288: }
1289:
1290: /** rb_obj_untaint
1291: *
1292: */
1293: public IRubyObject untaint() {
1294: getRuntime().secure(3);
1295: if (isTaint()) {
1296: testFrozen("object");
1297: setTaint(false);
1298: }
1299: return this ;
1300: }
1301:
1302: /** Freeze an object.
1303: *
1304: * rb_obj_freeze
1305: *
1306: */
1307: public IRubyObject freeze() {
1308: if (getRuntime().getSafeLevel() >= 4 && isTaint()) {
1309: throw getRuntime().newSecurityError(
1310: "Insecure: can't freeze object");
1311: }
1312: setFrozen(true);
1313: return this ;
1314: }
1315:
1316: /** rb_obj_frozen_p
1317: *
1318: */
1319: public RubyBoolean frozen() {
1320: return getRuntime().newBoolean(isFrozen());
1321: }
1322:
1323: /** rb_obj_inspect
1324: *
1325: */
1326: public IRubyObject inspect() {
1327: if ((!isImmediate())
1328: &&
1329: // TYPE(obj) == T_OBJECT
1330: !(this instanceof RubyClass)
1331: && this != getRuntime().getObject()
1332: && this != getRuntime().getClass("Module")
1333: && !(this instanceof RubyModule)
1334: && safeHasInstanceVariables()) {
1335:
1336: StringBuffer part = new StringBuffer();
1337: String cname = getMetaClass().getRealClass().getName();
1338: part.append("#<").append(cname).append(":0x");
1339: part.append(Integer.toHexString(System
1340: .identityHashCode(this )));
1341: if (!getRuntime().registerInspecting(this )) {
1342: /* 6:tags 16:addr 1:eos */
1343: part.append(" ...>");
1344: return getRuntime().newString(part.toString());
1345: }
1346: try {
1347: String sep = "";
1348: Map iVars = getInstanceVariablesSnapshot();
1349: for (Iterator iter = iVars.keySet().iterator(); iter
1350: .hasNext();) {
1351: String name = (String) iter.next();
1352: if (IdUtil.isInstanceVariable(name)) {
1353: part.append(sep);
1354: part.append(" ");
1355: part.append(name);
1356: part.append("=");
1357: part
1358: .append(((IRubyObject) (iVars.get(name)))
1359: .callMethod(getRuntime()
1360: .getCurrentContext(),
1361: "inspect"));
1362: sep = ",";
1363: }
1364: }
1365: part.append(">");
1366: return getRuntime().newString(part.toString());
1367: } finally {
1368: getRuntime().unregisterInspecting(this );
1369: }
1370: }
1371:
1372: if (isNil())
1373: return RubyNil.inspect(this );
1374: return callMethod(getRuntime().getCurrentContext(),
1375: MethodIndex.TO_S, "to_s", IRubyObject.NULL_ARRAY);
1376: }
1377:
1378: /** rb_obj_is_instance_of
1379: *
1380: */
1381: public RubyBoolean instance_of(IRubyObject type) {
1382: return getRuntime().newBoolean(type() == type);
1383: }
1384:
1385: public RubyArray instance_variables() {
1386: ArrayList names = new ArrayList();
1387: for (Iterator iter = getInstanceVariablesSnapshot().keySet()
1388: .iterator(); iter.hasNext();) {
1389: String name = (String) iter.next();
1390:
1391: // Do not include constants which also get stored in instance var list in classes.
1392: if (IdUtil.isInstanceVariable(name)) {
1393: names.add(getRuntime().newString(name));
1394: }
1395: }
1396: return getRuntime().newArray(names);
1397: }
1398:
1399: /** rb_obj_is_kind_of
1400: *
1401: */
1402: public RubyBoolean kind_of(IRubyObject type) {
1403: // TODO: Generalize this type-checking code into IRubyObject helper.
1404: if (!type.isKindOf(getRuntime().getClass("Module"))) {
1405: // TODO: newTypeError does not offer enough for ruby error string...
1406: throw getRuntime().newTypeError(type,
1407: getRuntime().getClass("Module"));
1408: }
1409:
1410: return getRuntime().newBoolean(isKindOf((RubyModule) type));
1411: }
1412:
1413: /** rb_obj_methods
1414: *
1415: */
1416: public IRubyObject methods(IRubyObject[] args) {
1417: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1418:
1419: if (args.length == 0) {
1420: args = new IRubyObject[] { getRuntime().getTrue() };
1421: }
1422:
1423: return getMetaClass().instance_methods(args);
1424: }
1425:
1426: public IRubyObject public_methods(IRubyObject[] args) {
1427: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1428:
1429: if (args.length == 0) {
1430: args = new IRubyObject[] { getRuntime().getTrue() };
1431: }
1432:
1433: return getMetaClass().public_instance_methods(args);
1434: }
1435:
1436: /** rb_obj_protected_methods
1437: *
1438: */
1439: public IRubyObject protected_methods(IRubyObject[] args) {
1440: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1441:
1442: if (args.length == 0) {
1443: args = new IRubyObject[] { getRuntime().getTrue() };
1444: }
1445:
1446: return getMetaClass().protected_instance_methods(args);
1447: }
1448:
1449: /** rb_obj_private_methods
1450: *
1451: */
1452: public IRubyObject private_methods(IRubyObject[] args) {
1453: Arity.checkArgumentCount(getRuntime(), args, 0, 1);
1454:
1455: if (args.length == 0) {
1456: args = new IRubyObject[] { getRuntime().getTrue() };
1457: }
1458:
1459: return getMetaClass().private_instance_methods(args);
1460: }
1461:
1462: /** rb_obj_singleton_methods
1463: *
1464: */
1465: // TODO: This is almost RubyModule#instance_methods on the metaClass. Perhaps refactor.
1466: public RubyArray singleton_methods(IRubyObject[] args) {
1467: boolean all = true;
1468: if (Arity.checkArgumentCount(getRuntime(), args, 0, 1) == 1) {
1469: all = args[0].isTrue();
1470: }
1471:
1472: RubyArray result = getRuntime().newArray();
1473:
1474: for (RubyClass type = getMetaClass(); type != null
1475: && ((type instanceof MetaClass) || (all && type
1476: .isIncluded())); type = type.getSuperClass()) {
1477: for (Iterator iter = type.getMethods().entrySet()
1478: .iterator(); iter.hasNext();) {
1479: Map.Entry entry = (Map.Entry) iter.next();
1480: DynamicMethod method = (DynamicMethod) entry.getValue();
1481:
1482: // We do not want to capture cached methods
1483: if (method.getImplementationClass() != type
1484: && !(all && type.isIncluded())) {
1485: continue;
1486: }
1487:
1488: RubyString methodName = getRuntime().newString(
1489: (String) entry.getKey());
1490: if (method.getVisibility().isPublic()
1491: && !result.includes(methodName)) {
1492: result.append(methodName);
1493: }
1494: }
1495: }
1496:
1497: return result;
1498: }
1499:
1500: public IRubyObject method(IRubyObject symbol) {
1501: return getMetaClass().newMethod(this , symbol.asSymbol(), true);
1502: }
1503:
1504: public IRubyObject anyToString() {
1505: String cname = getMetaClass().getRealClass().getName();
1506: /* 6:tags 16:addr 1:eos */
1507: RubyString str = getRuntime().newString(
1508: "#<"
1509: + cname
1510: + ":0x"
1511: + Integer.toHexString(System
1512: .identityHashCode(this )) + ">");
1513: str.setTaint(isTaint());
1514: return str;
1515: }
1516:
1517: public IRubyObject to_s() {
1518: return anyToString();
1519: }
1520:
1521: public IRubyObject instance_eval(IRubyObject[] args, Block block) {
1522: return specificEval(getSingletonClass(), args, block);
1523: }
1524:
1525: public IRubyObject instance_exec(IRubyObject[] args, Block block) {
1526: if (!block.isGiven()) {
1527: throw getRuntime().newArgumentError("block not supplied");
1528: }
1529: return yieldUnder(getSingletonClass(), args, block);
1530: }
1531:
1532: public IRubyObject extend(IRubyObject[] args) {
1533: Arity.checkArgumentCount(getRuntime(), args, 1, -1);
1534:
1535: // Make sure all arguments are modules before calling the callbacks
1536: for (int i = 0; i < args.length; i++) {
1537: IRubyObject obj;
1538: if (!(((obj = args[i]) instanceof RubyModule) && ((RubyModule) obj)
1539: .isModule())) {
1540: throw getRuntime().newTypeError(obj,
1541: getRuntime().getClass("Module"));
1542: }
1543: }
1544:
1545: for (int i = 0; i < args.length; i++) {
1546: args[i].callMethod(getRuntime().getCurrentContext(),
1547: "extend_object", this );
1548: args[i].callMethod(getRuntime().getCurrentContext(),
1549: "extended", this );
1550: }
1551: return this ;
1552: }
1553:
1554: public IRubyObject inherited(IRubyObject arg, Block block) {
1555: return getRuntime().getNil();
1556: }
1557:
1558: public IRubyObject initialize(IRubyObject[] args, Block block) {
1559: Arity.checkArgumentCount(getRuntime(), args, 0, 0);
1560: return getRuntime().getNil();
1561: }
1562:
1563: /**
1564: * send( aSymbol [, args ]* ) -> anObject
1565: *
1566: * Invokes the method identified by aSymbol, passing it any arguments
1567: * specified. You can use __send__ if the name send clashes with an
1568: * existing method in this object.
1569: *
1570: * <pre>
1571: * class Klass
1572: * def hello(*args)
1573: * "Hello " + args.join(' ')
1574: * end
1575: * end
1576: *
1577: * k = Klass.new
1578: * k.send :hello, "gentle", "readers"
1579: * </pre>
1580: *
1581: * @return the result of invoking the method identified by aSymbol.
1582: */
1583: public IRubyObject send(IRubyObject[] args, Block block) {
1584: if (args.length < 1) {
1585: throw getRuntime().newArgumentError("no method name given");
1586: }
1587: String name = args[0].asSymbol();
1588:
1589: IRubyObject[] newArgs = new IRubyObject[args.length - 1];
1590: System.arraycopy(args, 1, newArgs, 0, newArgs.length);
1591:
1592: return callMethod(getRuntime().getCurrentContext(), name,
1593: newArgs, CallType.FUNCTIONAL, block);
1594: }
1595:
1596: public IRubyObject nil_p() {
1597: return getRuntime().getFalse();
1598: }
1599:
1600: public IRubyObject match(IRubyObject arg) {
1601: return getRuntime().getFalse();
1602: }
1603:
1604: public IRubyObject remove_instance_variable(IRubyObject name,
1605: Block block) {
1606: String id = name.asSymbol();
1607:
1608: if (!IdUtil.isInstanceVariable(id)) {
1609: throw getRuntime().newNameError(
1610: "wrong instance variable name " + id, id);
1611: }
1612: if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
1613: throw getRuntime().newSecurityError(
1614: "Insecure: can't remove instance variable");
1615: }
1616: testFrozen("class/module");
1617:
1618: IRubyObject variable = removeInstanceVariable(id);
1619: if (variable != null) {
1620: return variable;
1621: }
1622:
1623: throw getRuntime().newNameError(
1624: "instance variable " + id + " not defined", id);
1625: }
1626:
1627: /**
1628: * @see org.jruby.runtime.builtin.IRubyObject#getType()
1629: */
1630: public RubyClass getType() {
1631: return type();
1632: }
1633:
1634: /**
1635: * @see org.jruby.runtime.builtin.IRubyObject#dataWrapStruct()
1636: */
1637: public synchronized void dataWrapStruct(Object obj) {
1638: this .dataStruct = obj;
1639: }
1640:
1641: /**
1642: * @see org.jruby.runtime.builtin.IRubyObject#dataGetStruct()
1643: */
1644: public synchronized Object dataGetStruct() {
1645: return dataStruct;
1646: }
1647:
1648: public void addFinalizer(RubyProc finalizer) {
1649: if (this .finalizer == null) {
1650: this .finalizer = new Finalizer(getRuntime()
1651: .getObjectSpace().idOf(this ));
1652: getRuntime().addFinalizer(this .finalizer);
1653: }
1654: this .finalizer.addFinalizer(finalizer);
1655: }
1656:
1657: public void removeFinalizers() {
1658: if (finalizer != null) {
1659: finalizer.removeFinalizers();
1660: finalizer = null;
1661: getRuntime().removeFinalizer(this.finalizer);
1662: }
1663: }
1664: }
|