KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyObject


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 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
16  * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
18  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
19  * Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org>
20  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
21  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
22  * Copyright (C) 2006 Ola Bini <ola.bini@ki.se>
23  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the CPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the CPL, the GPL or the LGPL.
36  ***** END LICENSE BLOCK *****/

37 package org.jruby;
38
39 import org.jruby.ast.Node;
40 import org.jruby.evaluator.EvaluationState;
41 import org.jruby.exceptions.JumpException;
42 import org.jruby.internal.runtime.methods.DynamicMethod;
43 import org.jruby.lexer.yacc.ISourcePosition;
44 import org.jruby.runtime.Arity;
45 import org.jruby.runtime.Block;
46 import org.jruby.runtime.CallType;
47 import org.jruby.runtime.ThreadContext;
48 import org.jruby.runtime.Visibility;
49 import org.jruby.runtime.builtin.IRubyObject;
50 import org.jruby.runtime.callback.Callback;
51 import org.jruby.util.IdUtil;
52 import org.jruby.util.PrintfFormat;
53 import org.jruby.util.collections.SinglyLinkedList;
54 import java.util.ArrayList JavaDoc;
55 import java.util.Collections JavaDoc;
56 import java.util.HashMap JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.Map JavaDoc;
59 import org.jruby.runtime.ClassIndex;
60
61 /**
62  *
63  * @author jpetersen
64  */

65 public class RubyObject implements Cloneable JavaDoc, IRubyObject {
66     
67     // The class of this object
68
private RubyClass metaClass;
69
70     // The instance variables of this object.
71
protected Map JavaDoc instanceVariables;
72
73     // The two properties frozen and taint
74
private boolean frozen;
75     private boolean taint;
76
77     public RubyObject(Ruby runtime, RubyClass metaClass) {
78         this(runtime, metaClass, runtime.isObjectSpaceEnabled());
79     }
80
81     public RubyObject(Ruby runtime, RubyClass metaClass, boolean useObjectSpace) {
82         this.metaClass = metaClass;
83         this.frozen = false;
84         this.taint = false;
85
86         // Do not store any immediate objects into objectspace.
87
if (useObjectSpace && !isImmediate()) {
88             runtime.getObjectSpace().add(this);
89         }
90
91         // FIXME are there objects who shouldn't be tainted?
92
// (mri: OBJSETUP)
93
taint |= runtime.getSafeLevel() >= 3;
94     }
95
96     public void attachToObjectSpace() {
97         getRuntime().getObjectSpace().add(this);
98     }
99     
100     /**
101      * This is overridden in the other concrete Java builtins to provide a fast way
102      * to determine what type they are.
103      */

104     public int getNativeTypeIndex() {
105         return ClassIndex.OBJECT;
106     }
107     
108     /*
109      * Is object immediate (def: Fixnum, Symbol, true, false, nil?).
110      */

111     public boolean isImmediate() {
112         return false;
113     }
114
115     /**
116      * Create a new meta class.
117      *
118      * @since Ruby 1.6.7
119      */

120     public RubyClass makeMetaClass(RubyClass superClass, SinglyLinkedList parentCRef) {
121         RubyClass klass = new MetaClass(getRuntime(), superClass, getMetaClass().getAllocator(), parentCRef);
122         setMetaClass(klass);
123         
124         klass.setInstanceVariable("__attached__", this);
125
126         if (this instanceof RubyClass && isSingleton()) { // could be pulled down to RubyClass in future
127
klass.setMetaClass(klass);
128             klass.setSuperClass(((RubyClass)this).getSuperClass().getRealClass().getMetaClass());
129         } else {
130             klass.setMetaClass(superClass.getRealClass().getMetaClass());
131         }
132         
133         // use same ClassIndex as metaclass, since we're technically still of that type
134
klass.index = superClass.index;
135         return klass;
136     }
137         
138     public boolean isSingleton() {
139         return false;
140     }
141
142     public Class JavaDoc getJavaClass() {
143         return IRubyObject.class;
144     }
145     
146     public static void puts(Object JavaDoc obj) {
147         System.out.println(obj.toString());
148     }
149
150     /**
151      * This method is just a wrapper around the Ruby "==" method,
152      * provided so that RubyObjects can be used as keys in the Java
153      * HashMap object underlying RubyHash.
154      */

155     public boolean equals(Object JavaDoc other) {
156         return other == this || other instanceof IRubyObject && callMethod(getRuntime().getCurrentContext(), "==", (IRubyObject) other).isTrue();
157     }
158
159     public String JavaDoc toString() {
160         return callMethod(getRuntime().getCurrentContext(), "to_s").toString();
161     }
162
163     /** Getter for property ruby.
164      * @return Value of property ruby.
165      */

166     public Ruby getRuntime() {
167         return metaClass.getRuntime();
168     }
169     
170     public boolean safeHasInstanceVariables() {
171         return instanceVariables != null && instanceVariables.size() > 0;
172     }
173     
174     public Map JavaDoc safeGetInstanceVariables() {
175         return instanceVariables == null ? null : getInstanceVariablesSnapshot();
176     }
177
178     public IRubyObject removeInstanceVariable(String JavaDoc name) {
179         return (IRubyObject) getInstanceVariables().remove(name);
180     }
181
182     /**
183      * Returns an unmodifiable snapshot of the current state of instance variables.
184      * This method synchronizes access to avoid deadlocks.
185      */

186     public Map JavaDoc getInstanceVariablesSnapshot() {
187         synchronized(getInstanceVariables()) {
188             return Collections.unmodifiableMap(new HashMap JavaDoc(getInstanceVariables()));
189         }
190     }
191
192     public Map JavaDoc getInstanceVariables() {
193         // TODO: double checking may or may not be safe enough here
194
if (instanceVariables == null) {
195             synchronized (this) {
196                 if (instanceVariables == null) {
197                             instanceVariables = Collections.synchronizedMap(new HashMap JavaDoc());
198                 }
199             }
200         }
201         return instanceVariables;
202     }
203
204     public void setInstanceVariables(Map JavaDoc instanceVariables) {
205         this.instanceVariables = Collections.synchronizedMap(instanceVariables);
206     }
207
208     /**
209      * if exist return the meta-class else return the type of the object.
210      *
211      */

212     public RubyClass getMetaClass() {
213         return metaClass;
214     }
215
216     public void setMetaClass(RubyClass metaClass) {
217         this.metaClass = metaClass;
218     }
219
220     /**
221      * Gets the frozen.
222      * @return Returns a boolean
223      */

224     public boolean isFrozen() {
225         return frozen;
226     }
227
228     /**
229      * Sets the frozen.
230      * @param frozen The frozen to set
231      */

232     public void setFrozen(boolean frozen) {
233         this.frozen = frozen;
234     }
235
236     /** rb_frozen_class_p
237     *
238     */

239    protected void testFrozen(String JavaDoc message) {
240        if (isFrozen()) {
241            throw getRuntime().newFrozenError(message + getMetaClass().getName());
242        }
243    }
244
245    protected void checkFrozen() {
246        testFrozen("can't modify frozen ");
247    }
248
249     /**
250      * Gets the taint.
251      * @return Returns a boolean
252      */

253     public boolean isTaint() {
254         return taint;
255     }
256
257     /**
258      * Sets the taint.
259      * @param taint The taint to set
260      */

261     public void setTaint(boolean taint) {
262         this.taint = taint;
263     }
264
265     public boolean isNil() {
266         return false;
267     }
268
269     public boolean isTrue() {
270         return !isNil();
271     }
272
273     public boolean isFalse() {
274         return isNil();
275     }
276
277     public boolean respondsTo(String JavaDoc name) {
278         return getMetaClass().isMethodBound(name, false);
279     }
280
281     // Some helper functions:
282

283     public int checkArgumentCount(IRubyObject[] args, int min, int max) {
284         if (args.length < min) {
285             throw getRuntime().newArgumentError("wrong number of arguments (" + args.length + " for " + min + ")");
286         }
287         if (max > -1 && args.length > max) {
288             throw getRuntime().newArgumentError("wrong number of arguments (" + args.length + " for " + max + ")");
289         }
290         return args.length;
291     }
292
293     public boolean isKindOf(RubyModule type) {
294         return getMetaClass().hasModuleInHierarchy(type);
295     }
296
297     /** rb_singleton_class
298      *
299      */

300     public RubyClass getSingletonClass() {
301         RubyClass klass;
302         
303         if (getMetaClass().isSingleton() && getMetaClass().getInstanceVariable("__attached__") == this) {
304             klass = getMetaClass();
305         } else {
306             klass = makeMetaClass(getMetaClass(), getMetaClass().getCRef());
307         }
308         
309         klass.setTaint(isTaint());
310         klass.setFrozen(isFrozen());
311         
312         return klass;
313     }
314     
315     /** rb_singleton_class_clone
316      *
317      */

318     public RubyClass getSingletonClassClone() {
319        RubyClass klass = getMetaClass();
320
321        if (!klass.isSingleton()) {
322            return klass;
323         }
324        
325        MetaClass clone = new MetaClass(getRuntime(), klass.getSuperClass(), getMetaClass().getAllocator(), getMetaClass().getCRef());
326        clone.setFrozen(klass.isFrozen());
327        clone.setTaint(klass.isTaint());
328
329        if (this instanceof RubyClass) {
330            clone.setMetaClass(clone);
331        } else {
332            clone.setMetaClass(klass.getSingletonClassClone());
333        }
334        
335        if (klass.safeHasInstanceVariables()) {
336            clone.setInstanceVariables(new HashMap JavaDoc(klass.getInstanceVariables()));
337        }
338
339        klass.cloneMethods(clone);
340
341        clone.getMetaClass().setInstanceVariable("__attached__", clone);
342
343        return clone;
344     }
345
346     /** rb_define_singleton_method
347      *
348      */

349     public void defineSingletonMethod(String JavaDoc name, Callback method) {
350         getSingletonClass().defineMethod(name, method);
351     }
352
353     /** init_copy
354      *
355      */

356     public void initCopy(IRubyObject original) {
357         assert original != null;
358         assert !isFrozen() : "frozen object (" + getMetaClass().getName() + ") allocated";
359
360         setInstanceVariables(new HashMap JavaDoc(original.getInstanceVariables()));
361         /* FIXME: finalizer should be dupped here */
362         callMethod(getRuntime().getCurrentContext(), "initialize_copy", original);
363     }
364
365     /** OBJ_INFECT
366      *
367      */

368     public IRubyObject infectBy(IRubyObject obj) {
369         setTaint(isTaint() || obj.isTaint());
370
371         return this;
372     }
373
374     /**
375      *
376      */

377     public IRubyObject callMethod(ThreadContext context, String JavaDoc name, IRubyObject[] args) {
378         return callMethod(context, getMetaClass(), name, args, CallType.FUNCTIONAL, Block.NULL_BLOCK);
379     }
380
381     public IRubyObject callMethod(ThreadContext context, String JavaDoc name, IRubyObject[] args, Block block) {
382         return callMethod(context, getMetaClass(), name, args, CallType.FUNCTIONAL, block);
383     }
384     
385     /**
386      *
387      */

388     public IRubyObject callMethod(ThreadContext context, String JavaDoc name,
389             IRubyObject[] args, CallType callType) {
390         return callMethod(context, getMetaClass(), name, args, callType, Block.NULL_BLOCK);
391     }
392     
393     public IRubyObject callMethod(ThreadContext context, String JavaDoc name,
394             IRubyObject[] args, CallType callType, Block block) {
395         return callMethod(context, getMetaClass(), name, args, callType, block);
396     }
397
398     public IRubyObject callMethod(ThreadContext context, byte methodIndex, String JavaDoc name,
399                                   IRubyObject arg) {
400         return callMethod(context,methodIndex,name,new IRubyObject[]{arg},CallType.FUNCTIONAL, Block.NULL_BLOCK);
401     }
402
403     public IRubyObject callMethod(ThreadContext context, byte methodIndex, String JavaDoc name,
404                                   IRubyObject[] args) {
405         return callMethod(context,methodIndex,name,args,CallType.FUNCTIONAL, Block.NULL_BLOCK);
406     }
407
408     public IRubyObject callMethod(ThreadContext context, byte methodIndex, String JavaDoc name,
409                                   IRubyObject[] args, CallType callType) {
410         return callMethod(context,methodIndex,name,args,callType, Block.NULL_BLOCK);
411     }
412     /**
413      * Used by the compiler to ease calling indexed methods
414      */

415     public IRubyObject callMethod(ThreadContext context, byte methodIndex, String JavaDoc name,
416             IRubyObject[] args, CallType callType, Block block) {
417         RubyModule module = getMetaClass();
418         
419         if (module.index != 0) {
420             return callMethod(context, module, getRuntime().getSelectorTable().table[module.index][methodIndex], name, args, callType, block);
421         }
422             
423         return callMethod(context, module, name, args, callType, block);
424     }
425
426     /**
427      *
428      */

429     public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, byte switchvalue, String JavaDoc name,
430             IRubyObject[] args, CallType callType) {
431         return callMethod(context, rubyclass, name, args, callType, Block.NULL_BLOCK);
432     }
433
434     /**
435      *
436      */

437     public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, byte switchvalue, String JavaDoc name,
438             IRubyObject[] args, CallType callType, Block block) {
439         return callMethod(context, rubyclass, name, args, callType, block);
440     }
441     
442     /**
443      *
444      */

445     public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, String JavaDoc name,
446             IRubyObject[] args, CallType callType, Block block) {
447         assert args != null;
448         DynamicMethod method = null;
449         method = rubyclass.searchMethod(name);
450         if (method.isUndefined() ||
451             !(name.equals("method_missing") ||
452               method.isCallableFrom(context.getFrameSelf(), callType))) {
453
454             if (callType == CallType.SUPER) {
455                 throw getRuntime().newNameError("super: no superclass method '" + name + "'", name);
456             }
457
458             // store call information so method_missing impl can use it
459
context.setLastCallStatus(method.getVisibility(), callType);
460
461             if (name.equals("method_missing")) {
462                 return RubyKernel.method_missing(this, args, block);
463             }
464
465
466             IRubyObject[] newArgs = new IRubyObject[args.length + 1];
467             System.arraycopy(args, 0, newArgs, 1, args.length);
468             newArgs[0] = RubySymbol.newSymbol(getRuntime(), name);
469
470             return callMethod(context, "method_missing", newArgs, block);
471         }
472
473         RubyModule implementer = null;
474         if (method.needsImplementer()) {
475             // modules are included with a shim class; we must find that shim to handle super() appropriately
476
implementer = rubyclass.findImplementer(method.getImplementationClass());
477         } else {
478             // classes are directly in the hierarchy, so no special logic is necessary for implementer
479
implementer = method.getImplementationClass();
480         }
481
482         String JavaDoc originalName = method.getOriginalName();
483         if (originalName != null) {
484             name = originalName;
485         }
486
487         return method.call(context, this, implementer, name, args, false, block);
488     }
489
490     public IRubyObject callMethod(ThreadContext context, String JavaDoc name) {
491         return callMethod(context, name, IRubyObject.NULL_ARRAY, null, Block.NULL_BLOCK);
492     }
493
494     public IRubyObject callMethod(ThreadContext context, String JavaDoc name, Block block) {
495         return callMethod(context, name, IRubyObject.NULL_ARRAY, null, block);
496     }
497
498     /**
499      * rb_funcall
500      *
501      */

502     public IRubyObject callMethod(ThreadContext context, String JavaDoc name, IRubyObject arg) {
503         return callMethod(context, name, new IRubyObject[] { arg });
504     }
505
506     public IRubyObject instance_variable_get(IRubyObject var) {
507         String JavaDoc varName = var.asSymbol();
508
509         if (!IdUtil.isInstanceVariable(varName)) {
510             throw getRuntime().newNameError("`" + varName + "' is not allowable as an instance variable name", varName);
511         }
512
513         IRubyObject variable = getInstanceVariable(varName);
514
515         // Pickaxe v2 says no var should show NameError, but ruby only sends back nil..
516
return variable == null ? getRuntime().getNil() : variable;
517     }
518
519     public IRubyObject getInstanceVariable(String JavaDoc name) {
520         return (IRubyObject) getInstanceVariables().get(name);
521     }
522
523     public IRubyObject instance_variable_set(IRubyObject var, IRubyObject value) {
524         String JavaDoc varName = var.asSymbol();
525
526         if (!IdUtil.isInstanceVariable(varName)) {
527             throw getRuntime().newNameError("`" + varName + "' is not allowable as an instance variable name", varName);
528         }
529
530         return setInstanceVariable(var.asSymbol(), value);
531     }
532
533     public IRubyObject setInstanceVariable(String JavaDoc name, IRubyObject value,
534             String JavaDoc taintError, String JavaDoc freezeError) {
535         if (isTaint() && getRuntime().getSafeLevel() >= 4) {
536             throw getRuntime().newSecurityError(taintError);
537         }
538         testFrozen(freezeError);
539
540         getInstanceVariables().put(name, value);
541
542         return value;
543     }
544
545     /** rb_iv_set / rb_ivar_set
546      *
547      */

548     public IRubyObject setInstanceVariable(String JavaDoc name, IRubyObject value) {
549         return setInstanceVariable(name, value,
550                 "Insecure: can't modify instance variable", "");
551     }
552
553     public Iterator JavaDoc instanceVariableNames() {
554         return getInstanceVariables().keySet().iterator();
555     }
556
557     /** rb_eval
558      *
559      */

560     public IRubyObject eval(Node n) {
561         //return new EvaluationState(getRuntime(), this).begin(n);
562
// need to continue evaluation with a new self, so save the old one (should be a stack?)
563
return EvaluationState.eval(getRuntime(), getRuntime().getCurrentContext(), n, this, Block.NULL_BLOCK);
564     }
565
566     public void callInit(IRubyObject[] args, Block block) {
567         callMethod(getRuntime().getCurrentContext(), "initialize", args, block);
568     }
569
570     public void extendObject(RubyModule module) {
571         getSingletonClass().includeModule(module);
572     }
573
574     /** rb_to_id
575      *
576      */

577     public String JavaDoc asSymbol() {
578         throw getRuntime().newTypeError(inspect().toString() + " is not a symbol");
579     }
580
581     /*
582      * @see org.jruby.runtime.builtin.IRubyObject#convertToTypeWithCheck(java.lang.String, java.lang.String)
583      */

584     public IRubyObject convertToTypeWithCheck(String JavaDoc targetType, String JavaDoc convertMethod) {
585         if (targetType.equals(getMetaClass().getName())) {
586             return this;
587         }
588
589         IRubyObject value = convertToType(targetType, convertMethod, false);
590         if (value.isNil()) {
591             return value;
592         }
593
594         if (!targetType.equals(value.getMetaClass().getName())) {
595             throw getRuntime().newTypeError(value.getMetaClass().getName() + "#" + convertMethod +
596                     "should return " + targetType);
597         }
598
599         return value;
600     }
601
602     /*
603      * @see org.jruby.runtime.builtin.IRubyObject#convertToType(java.lang.String, java.lang.String, boolean)
604      */

605     public IRubyObject convertToType(String JavaDoc targetType, String JavaDoc convertMethod, boolean raise) {
606         // No need to convert something already of the correct type.
607
// XXXEnebo - Could this pass actual class reference instead of String?
608
if (targetType.equals(getMetaClass().getName())) {
609             return this;
610         }
611         
612         if (!respondsTo(convertMethod)) {
613             if (raise) {
614                 throw getRuntime().newTypeError(
615                     "can't convert " + trueFalseNil(getMetaClass().getName()) + " into " + trueFalseNil(targetType));
616             }
617
618             return getRuntime().getNil();
619         }
620         return callMethod(getRuntime().getCurrentContext(), convertMethod);
621     }
622
623     public static String JavaDoc trueFalseNil(IRubyObject v) {
624         return trueFalseNil(v.getMetaClass().getName());
625     }
626
627     public static String JavaDoc trueFalseNil(String JavaDoc v) {
628         if("TrueClass".equals(v)) {
629             return "true";
630         } else if("FalseClass".equals(v)) {
631             return "false";
632         } else if("NilClass".equals(v)) {
633             return "nil";
634         }
635         return v;
636     }
637
638     public RubyArray convertToArray() {
639         return (RubyArray) convertToType("Array", "to_ary", true);
640     }
641
642     public RubyFloat convertToFloat() {
643         return (RubyFloat) convertToType("Float", "to_f", true);
644     }
645
646     public RubyInteger convertToInteger() {
647         return (RubyInteger) convertToType("Integer", "to_int", true);
648     }
649
650     public RubyString convertToString() {
651         return (RubyString) convertToType("String", "to_str", true);
652     }
653
654     /** rb_obj_as_string
655      */

656     public RubyString objAsString() {
657         if (this instanceof RubyString) return (RubyString) this;
658         
659         IRubyObject str = this.callMethod(getRuntime().getCurrentContext(), "to_s");
660         
661         if (!(str instanceof RubyString)) str = anyToString();
662
663         return (RubyString) str;
664     }
665
666     /** rb_convert_type
667      *
668      */

669     public IRubyObject convertType(Class JavaDoc type, String JavaDoc targetType, String JavaDoc convertMethod) {
670         if (type.isAssignableFrom(getClass())) {
671             return this;
672         }
673
674         IRubyObject result = convertToType(targetType, convertMethod, true);
675
676         if (!type.isAssignableFrom(result.getClass())) {
677             throw getRuntime().newTypeError(
678                 getMetaClass().getName() + "#" + convertMethod + " should return " + targetType + ".");
679         }
680
681         return result;
682     }
683     
684     /** rb_check_string_type
685      *
686      */

687     public IRubyObject checkStringType() {
688         IRubyObject str = convertToTypeWithCheck("String","to_str");
689         if(!str.isNil() && !(str instanceof RubyString)) {
690             str = getRuntime().newString("");
691         }
692         return str;
693     }
694
695     /** rb_check_array_type
696     *
697     */

698     public IRubyObject checkArrayType() {
699         return convertToTypeWithCheck("Array","to_ary");
700     }
701
702     public void checkSafeString() {
703         if (getRuntime().getSafeLevel() > 0 && isTaint()) {
704             ThreadContext tc = getRuntime().getCurrentContext();
705             if (tc.getFrameName() != null) {
706                 throw getRuntime().newSecurityError("Insecure operation - " + tc.getFrameName());
707             }
708             throw getRuntime().newSecurityError("Insecure operation: -r");
709         }
710         getRuntime().secure(4);
711         if (!(this instanceof RubyString)) {
712             throw getRuntime().newTypeError(
713                 "wrong argument type " + getMetaClass().getName() + " (expected String)");
714         }
715     }
716
717     /** specific_eval
718      *
719      */

720     public IRubyObject specificEval(RubyModule mod, IRubyObject[] args, Block block) {
721         if (block.isGiven()) {
722             if (args.length > 0) throw getRuntime().newArgumentError(args.length, 0);
723
724             return yieldUnder(mod, block);
725         }
726         ThreadContext tc = getRuntime().getCurrentContext();
727
728         if (args.length == 0) {
729             throw getRuntime().newArgumentError("block not supplied");
730         } else if (args.length > 3) {
731             String JavaDoc lastFuncName = tc.getFrameName();
732             throw getRuntime().newArgumentError(
733                 "wrong # of arguments: " + lastFuncName + "(src) or " + lastFuncName + "{..}");
734         }
735         /*
736         if (ruby.getSecurityLevel() >= 4) {
737             Check_Type(argv[0], T_STRING);
738         } else {
739             Check_SafeStr(argv[0]);
740         }
741         */

742         
743         // We just want the TypeError if the argument doesn't convert to a String (JRUBY-386)
744
args[0].convertToString();
745         
746         IRubyObject file = args.length > 1 ? args[1] : getRuntime().newString("(eval)");
747         IRubyObject line = args.length > 2 ? args[2] : RubyFixnum.one(getRuntime());
748
749         Visibility savedVisibility = tc.getCurrentVisibility();
750         tc.setCurrentVisibility(Visibility.PUBLIC);
751         try {
752             return evalUnder(mod, args[0], file, line);
753         } finally {
754             tc.setCurrentVisibility(savedVisibility);
755         }
756     }
757
758     public IRubyObject evalUnder(RubyModule under, IRubyObject src, IRubyObject file, IRubyObject line) {
759         /*
760         if (ruby_safe_level >= 4) {
761             Check_Type(src, T_STRING);
762         } else {
763             Check_SafeStr(src);
764             }
765         */

766         return under.executeUnder(new Callback() {
767             public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
768                 IRubyObject source = args[1];
769                 IRubyObject filename = args[2];
770                 // FIXME: lineNumber is not supported
771
//IRubyObject lineNumber = args[3];
772

773                 return args[0].evalSimple(source.getRuntime().getCurrentContext(),
774                                   source, ((RubyString) filename).toString());
775             }
776
777             public Arity getArity() {
778                 return Arity.optional();
779             }
780         }, new IRubyObject[] { this, src, file, line }, Block.NULL_BLOCK);
781     }
782
783     private IRubyObject yieldUnder(RubyModule under, Block block) {
784         return under.executeUnder(new Callback() {
785             public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
786                 ThreadContext context = getRuntime().getCurrentContext();
787
788                 Visibility savedVisibility = block.getVisibility();
789
790                 block.setVisibility(Visibility.PUBLIC);
791                 try {
792                     IRubyObject valueInYield = args[0];
793                     IRubyObject selfInYield = args[0];
794                     return block.yield(context, valueInYield, selfInYield, context.getRubyClass(), false);
795                     //TODO: Should next and return also catch here?
796
} catch (JumpException je) {
797                     if (je.getJumpType() == JumpException.JumpType.BreakJump) {
798                         return (IRubyObject) je.getValue();
799                     }
800
801                     throw je;
802                 } finally {
803                     block.setVisibility(savedVisibility);
804                 }
805             }
806
807             public Arity getArity() {
808                 return Arity.optional();
809             }
810         }, new IRubyObject[] { this }, block);
811     }
812
813     /* (non-Javadoc)
814      * @see org.jruby.runtime.builtin.IRubyObject#evalWithBinding(org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject, java.lang.String)
815      */

816     public IRubyObject evalWithBinding(ThreadContext context, IRubyObject src, IRubyObject scope, String JavaDoc file) {
817         // both of these are ensured by the (very few) callers
818
assert !scope.isNil();
819         assert file != null;
820
821         ThreadContext threadContext = getRuntime().getCurrentContext();
822
823         ISourcePosition savedPosition = threadContext.getPosition();
824         IRubyObject result = getRuntime().getNil();
825
826         IRubyObject newSelf = null;
827
828         if (!(scope instanceof RubyBinding)) {
829             if (scope instanceof RubyProc) {
830                 scope = ((RubyProc) scope).binding();
831             } else {
832                 // bomb out, it's not a binding or a proc
833
throw getRuntime().newTypeError("wrong argument type " + scope.getMetaClass() + " (expected Proc/Binding)");
834             }
835         }
836
837         Block blockOfBinding = ((RubyBinding)scope).getBlock();
838         try {
839             // Binding provided for scope, use it
840
threadContext.preEvalWithBinding(blockOfBinding);
841             newSelf = threadContext.getFrameSelf();
842
843             result = EvaluationState.eval(getRuntime(), threadContext, getRuntime().parse(src.toString(), file, blockOfBinding.getDynamicScope()), newSelf, blockOfBinding);
844         } catch (JumpException je) {
845             if (je.getJumpType() == JumpException.JumpType.ReturnJump) {
846                 throw getRuntime().newLocalJumpError("unexpected return");
847             } else if (je.getJumpType() == JumpException.JumpType.BreakJump) {
848                 throw getRuntime().newLocalJumpError("unexpected break");
849             }
850             throw je;
851         } finally {
852             threadContext.postEvalWithBinding();
853
854             // restore position
855
threadContext.setPosition(savedPosition);
856         }
857         return result;
858     }
859
860     /* (non-Javadoc)
861      * @see org.jruby.runtime.builtin.IRubyObject#evalSimple(org.jruby.runtime.builtin.IRubyObject, java.lang.String)
862      */

863     public IRubyObject evalSimple(ThreadContext context, IRubyObject src, String JavaDoc file) {
864         // this is ensured by the callers
865
assert file != null;
866
867         ISourcePosition savedPosition = context.getPosition();
868
869         // no binding, just eval in "current" frame (caller's frame)
870
try {
871             return EvaluationState.eval(getRuntime(), context, getRuntime().parse(src.toString(), file, context.getCurrentScope()), this, Block.NULL_BLOCK);
872         } catch (JumpException je) {
873             if (je.getJumpType() == JumpException.JumpType.ReturnJump) {
874                 throw getRuntime().newLocalJumpError("unexpected return");
875             } else if (je.getJumpType() == JumpException.JumpType.BreakJump) {
876                 throw getRuntime().newLocalJumpError("unexpected break");
877             }
878             throw je;
879         } finally {
880             // restore position
881
context.setPosition(savedPosition);
882         }
883     }
884
885     // Methods of the Object class (rb_obj_*):
886

887     /** rb_obj_equal
888      *
889      */

890     public IRubyObject obj_equal(IRubyObject obj) {
891         return this == obj ? getRuntime().getTrue() : getRuntime().getFalse();
892 // if (isNil()) {
893
// return getRuntime().newBoolean(obj.isNil());
894
// }
895
// return getRuntime().newBoolean(this == obj);
896
}
897
898     public IRubyObject same(IRubyObject other) {
899         return this == other ? getRuntime().getTrue() : getRuntime().getFalse();
900     }
901
902     
903     /** rb_obj_init_copy
904      *
905      */

906     public IRubyObject initialize_copy(IRubyObject original) {
907         if (this == original) return this;
908         
909         checkFrozen();
910         
911         if (getMetaClass().getRealClass() != original.getMetaClass().getRealClass()) {
912                 throw getRuntime().newTypeError("initialize_copy should take same class object");
913         }
914
915         return this;
916     }
917
918     /**
919      * respond_to?( aSymbol, includePriv=false ) -> true or false
920      *
921      * Returns true if this object responds to the given method. Private
922      * methods are included in the search only if the optional second
923      * parameter evaluates to true.
924      *
925      * @return true if this responds to the given method
926      */

927     public RubyBoolean respond_to(IRubyObject[] args) {
928         checkArgumentCount(args, 1, 2);
929
930         String JavaDoc name = args[0].asSymbol();
931         boolean includePrivate = args.length > 1 ? args[1].isTrue() : false;
932
933         return getRuntime().newBoolean(getMetaClass().isMethodBound(name, !includePrivate));
934     }
935
936     /** Return the internal id of an object.
937      *
938      * <i>CRuby function: rb_obj_id</i>
939      *
940      */

941     public synchronized RubyFixnum id() {
942         return getRuntime().newFixnum(getRuntime().getObjectSpace().idOf(this));
943     }
944
945     public synchronized RubyFixnum id_deprecated() {
946         getRuntime().getWarnings().warn("Object#id will be deprecated; use Object#object_id");
947         return getRuntime().newFixnum(getRuntime().getObjectSpace().idOf(this));
948     }
949     
950     public RubyFixnum hash() {
951         return getRuntime().newFixnum(System.identityHashCode(this));
952     }
953
954     public int hashCode() {
955         IRubyObject hashValue = callMethod(getRuntime().getCurrentContext(), "hash");
956         
957         if (hashValue instanceof RubyFixnum) return (int) RubyNumeric.fix2long(hashValue);
958         
959         return System.identityHashCode(this);
960     }
961
962     /** rb_obj_type
963      *
964      */

965     public RubyClass type() {
966         return getMetaClass().getRealClass();
967     }
968
969     public RubyClass type_deprecated() {
970         getRuntime().getWarnings().warn("Object#type is deprecated; use Object#class");
971         return type();
972     }
973
974     /** rb_obj_clone
975      * should be overriden only by: Proc, Method, UnboundedMethod, Binding
976      */

977     public IRubyObject rbClone() {
978         if (isImmediate()) { // rb_special_const_p(obj) equivalent
979
throw getRuntime().newTypeError("can't clone " + getMetaClass().getName());
980         }
981         
982         IRubyObject clone = doClone();
983         clone.setMetaClass(getSingletonClassClone());
984         clone.setTaint(isTaint());
985         clone.initCopy(this);
986         clone.setFrozen(isFrozen());
987         return clone;
988     }
989
990     // Hack: allow RubyModule and RubyClass to override the allocation and return the the correct Java instance
991
// Cloning a class object doesn't work otherwise and I don't really understand why --sma
992
protected IRubyObject doClone() {
993         RubyClass realClass = getMetaClass().getRealClass();
994         return realClass.getAllocator().allocate(getRuntime(), realClass);
995     }
996
997     public IRubyObject display(IRubyObject[] args) {
998         IRubyObject port = args.length == 0
999             ? getRuntime().getGlobalVariables().get("$>") : args[0];
1000
1001        port.callMethod(getRuntime().getCurrentContext(), "write", this);
1002
1003        return getRuntime().getNil();
1004    }
1005
1006    /** rb_obj_dup
1007     * should be overriden only by: Proc
1008     */

1009    public IRubyObject dup() {
1010        if (isImmediate()) {
1011            throw getRuntime().newTypeError("can't dup " + getMetaClass().getName());
1012        }
1013        
1014        IRubyObject dup = doClone();
1015
1016        dup.setMetaClass(type());
1017        dup.setFrozen(false);
1018        dup.setTaint(isTaint());
1019        
1020        dup.initCopy(this);
1021
1022        return dup;
1023    }
1024
1025    /** rb_obj_tainted
1026     *
1027     */

1028    public RubyBoolean tainted() {
1029        return getRuntime().newBoolean(isTaint());
1030    }
1031
1032    /** rb_obj_taint
1033     *
1034     */

1035    public IRubyObject taint() {
1036        getRuntime().secure(4);
1037        if (!isTaint()) {
1038            testFrozen("object");
1039            setTaint(true);
1040        }
1041        return this;
1042    }
1043
1044    /** rb_obj_untaint
1045     *
1046     */

1047    public IRubyObject untaint() {
1048        getRuntime().secure(3);
1049        if (isTaint()) {
1050            testFrozen("object");
1051            setTaint(false);
1052        }
1053        return this;
1054    }
1055
1056    /** Freeze an object.
1057     *
1058     * rb_obj_freeze
1059     *
1060     */

1061    public IRubyObject freeze() {
1062        if (getRuntime().getSafeLevel() >= 4 && isTaint()) {
1063            throw getRuntime().newSecurityError("Insecure: can't freeze object");
1064        }
1065        setFrozen(true);
1066        return this;
1067    }
1068
1069    /** rb_obj_frozen_p
1070     *
1071     */

1072    public RubyBoolean frozen() {
1073        return getRuntime().newBoolean(isFrozen());
1074    }
1075
1076    /** rb_obj_inspect
1077     *
1078     */

1079    public IRubyObject inspect() {
1080        if ((!isImmediate()) &&
1081                // TYPE(obj) == T_OBJECT
1082
!(this instanceof RubyClass) &&
1083                this != getRuntime().getObject() &&
1084                this != getRuntime().getClass("Module") &&
1085                !(this instanceof RubyModule) &&
1086                safeHasInstanceVariables()) {
1087
1088            StringBuffer JavaDoc part = new StringBuffer JavaDoc();
1089            String JavaDoc cname = getMetaClass().getRealClass().getName();
1090            part.append("#<").append(cname).append(":0x");
1091            part.append(Integer.toHexString(System.identityHashCode(this)));
1092            if(!getRuntime().registerInspecting(this)) {
1093                /* 6:tags 16:addr 1:eos */
1094                part.append(" ...>");
1095                return getRuntime().newString(part.toString());
1096            }
1097            try {
1098                String JavaDoc sep = "";
1099                Map JavaDoc iVars = getInstanceVariablesSnapshot();
1100                for (Iterator JavaDoc iter = iVars.keySet().iterator(); iter.hasNext();) {
1101                    String JavaDoc name = (String JavaDoc) iter.next();
1102                    if(IdUtil.isInstanceVariable(name)) {
1103                        part.append(sep);
1104                        part.append(" ");
1105                        part.append(name);
1106                        part.append("=");
1107                        part.append(((IRubyObject)(iVars.get(name))).callMethod(getRuntime().getCurrentContext(), "inspect"));
1108                        sep = ",";
1109                    }
1110                }
1111                part.append(">");
1112                return getRuntime().newString(part.toString());
1113            } finally {
1114                getRuntime().unregisterInspecting(this);
1115            }
1116        }
1117        return callMethod(getRuntime().getCurrentContext(), "to_s");
1118    }
1119
1120    /** rb_obj_is_instance_of
1121     *
1122     */

1123    public RubyBoolean instance_of(IRubyObject type) {
1124        return getRuntime().newBoolean(type() == type);
1125    }
1126
1127
1128    public RubyArray instance_variables() {
1129        ArrayList JavaDoc names = new ArrayList JavaDoc();
1130        for(Iterator JavaDoc iter = getInstanceVariablesSnapshot().keySet().iterator();iter.hasNext();) {
1131            String JavaDoc name = (String JavaDoc) iter.next();
1132
1133            // Do not include constants which also get stored in instance var list in classes.
1134
if (IdUtil.isInstanceVariable(name)) {
1135                names.add(getRuntime().newString(name));
1136            }
1137        }
1138        return getRuntime().newArray(names);
1139    }
1140
1141    /** rb_obj_is_kind_of
1142     *
1143     */

1144    public RubyBoolean kind_of(IRubyObject type) {
1145        // TODO: Generalize this type-checking code into IRubyObject helper.
1146
if (!type.isKindOf(getRuntime().getClass("Module"))) {
1147            // TODO: newTypeError does not offer enough for ruby error string...
1148
throw getRuntime().newTypeError(type, getRuntime().getClass("Module"));
1149        }
1150
1151        return getRuntime().newBoolean(isKindOf((RubyModule)type));
1152    }
1153
1154    /** rb_obj_methods
1155     *
1156     */

1157    public IRubyObject methods(IRubyObject[] args) {
1158        checkArgumentCount(args, 0, 1);
1159
1160        if (args.length == 0) {
1161            args = new IRubyObject[] { getRuntime().getTrue() };
1162        }
1163
1164        return getMetaClass().instance_methods(args);
1165    }
1166
1167    public IRubyObject public_methods(IRubyObject[] args) {
1168        return getMetaClass().public_instance_methods(args);
1169    }
1170
1171    /** rb_obj_protected_methods
1172     *
1173     */

1174    public IRubyObject protected_methods() {
1175        return getMetaClass().protected_instance_methods(new IRubyObject[] { getRuntime().getTrue()});
1176    }
1177
1178    /** rb_obj_private_methods
1179     *
1180     */

1181    public IRubyObject private_methods() {
1182        return getMetaClass().private_instance_methods(new IRubyObject[] { getRuntime().getTrue()});
1183    }
1184
1185    /** rb_obj_singleton_methods
1186     *
1187     */

1188    // TODO: This is almost RubyModule#instance_methods on the metaClass. Perhaps refactor.
1189
public RubyArray singleton_methods(IRubyObject[] args) {
1190        boolean all = true;
1191        if(checkArgumentCount(args,0,1) == 1) {
1192            all = args[0].isTrue();
1193        }
1194
1195        RubyArray result = getRuntime().newArray();
1196
1197        for (RubyClass type = getMetaClass(); type != null && ((type instanceof MetaClass) || (all && type.isIncluded()));
1198             type = type.getSuperClass()) {
1199            for (Iterator JavaDoc iter = type.getMethods().entrySet().iterator(); iter.hasNext(); ) {
1200                Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
1201                DynamicMethod method = (DynamicMethod) entry.getValue();
1202
1203                // We do not want to capture cached methods
1204
if (method.getImplementationClass() != type && !(all && type.isIncluded())) {
1205                    continue;
1206                }
1207
1208                RubyString methodName = getRuntime().newString((String JavaDoc) entry.getKey());
1209                if (method.getVisibility().isPublic() && ! result.includes(methodName)) {
1210                    result.append(methodName);
1211                }
1212            }
1213        }
1214
1215        return result;
1216    }
1217
1218    public IRubyObject method(IRubyObject symbol) {
1219        return getMetaClass().newMethod(this, symbol.asSymbol(), true);
1220    }
1221
1222    public IRubyObject anyToString() {
1223        String JavaDoc cname = getMetaClass().getRealClass().getName();
1224        /* 6:tags 16:addr 1:eos */
1225        RubyString str = getRuntime().newString("#<" + cname + ":0x" + Integer.toHexString(System.identityHashCode(this)) + ">");
1226        str.setTaint(isTaint());
1227        return str;
1228    }
1229
1230    public IRubyObject to_s() {
1231        return anyToString();
1232    }
1233
1234    public IRubyObject instance_eval(IRubyObject[] args, Block block) {
1235        return specificEval(getSingletonClass(), args, block);
1236    }
1237
1238    public IRubyObject extend(IRubyObject[] args) {
1239        checkArgumentCount(args, 1, -1);
1240
1241        // Make sure all arguments are modules before calling the callbacks
1242
RubyClass module = getRuntime().getClass("Module");
1243        for (int i = 0; i < args.length; i++) {
1244            if (!args[i].isKindOf(module)) {
1245                throw getRuntime().newTypeError(args[i], module);
1246            }
1247        }
1248
1249        for (int i = 0; i < args.length; i++) {
1250            args[i].callMethod(getRuntime().getCurrentContext(), "extend_object", this);
1251            args[i].callMethod(getRuntime().getCurrentContext(), "extended", this);
1252        }
1253        return this;
1254    }
1255
1256    public IRubyObject inherited(IRubyObject arg, Block block) {
1257        return getRuntime().getNil();
1258    }
1259    public IRubyObject initialize(IRubyObject[] args, Block block) {
1260        return getRuntime().getNil();
1261    }
1262
1263    public IRubyObject method_missing(IRubyObject[] args, Block block) {
1264        if (args.length == 0) {
1265            throw getRuntime().newArgumentError("no id given");
1266        }
1267
1268        String JavaDoc name = args[0].asSymbol();
1269        String JavaDoc description = null;
1270        if("inspect".equals(name) || "to_s".equals(name)) {
1271            description = anyToString().toString();
1272        } else {
1273            description = inspect().toString();
1274        }
1275        boolean noClass = description.length() > 0 && description.charAt(0) == '#';
1276        ThreadContext tc = getRuntime().getCurrentContext();
1277        Visibility lastVis = tc.getLastVisibility();
1278        if(null == lastVis) {
1279            lastVis = Visibility.PUBLIC;
1280        }
1281        CallType lastCallType = tc.getLastCallType();
1282        String JavaDoc format = lastVis.errorMessageFormat(lastCallType, name);
1283        String JavaDoc msg = new PrintfFormat(format).sprintf(new Object JavaDoc[] { name, description,
1284                                                                     noClass ? "" : ":", noClass ? "" : getType().getName()}, null);
1285
1286        if (lastCallType == CallType.VARIABLE) {
1287            throw getRuntime().newNameError(msg, name);
1288        }
1289        throw getRuntime().newNoMethodError(msg, name);
1290    }
1291
1292    /**
1293     * send( aSymbol [, args ]* ) -> anObject
1294     *
1295     * Invokes the method identified by aSymbol, passing it any arguments
1296     * specified. You can use __send__ if the name send clashes with an
1297     * existing method in this object.
1298     *
1299     * <pre>
1300     * class Klass
1301     * def hello(*args)
1302     * "Hello " + args.join(' ')
1303     * end
1304     * end
1305     *
1306     * k = Klass.new
1307     * k.send :hello, "gentle", "readers"
1308     * </pre>
1309     *
1310     * @return the result of invoking the method identified by aSymbol.
1311     */

1312    public IRubyObject send(IRubyObject[] args, Block block) {
1313        if (args.length < 1) {
1314            throw getRuntime().newArgumentError("no method name given");
1315        }
1316        String JavaDoc name = args[0].asSymbol();
1317
1318        IRubyObject[] newArgs = new IRubyObject[args.length - 1];
1319        System.arraycopy(args, 1, newArgs, 0, newArgs.length);
1320
1321        return callMethod(getRuntime().getCurrentContext(), name, newArgs, CallType.FUNCTIONAL, block);
1322    }
1323    
1324    public IRubyObject nil_p() {
1325        return getRuntime().getFalse();
1326    }
1327    
1328    public IRubyObject match(IRubyObject arg) {
1329        return getRuntime().getFalse();
1330    }
1331    
1332   public IRubyObject remove_instance_variable(IRubyObject name, Block block) {
1333       String JavaDoc id = name.asSymbol();
1334
1335       if (!IdUtil.isInstanceVariable(id)) {
1336           throw getRuntime().newNameError("wrong instance variable name " + id, id);
1337       }
1338       if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
1339           throw getRuntime().newSecurityError("Insecure: can't remove instance variable");
1340       }
1341       testFrozen("class/module");
1342
1343       IRubyObject variable = removeInstanceVariable(id);
1344       if (variable != null) {
1345           return variable;
1346       }
1347
1348       throw getRuntime().newNameError("instance variable " + id + " not defined", id);
1349   }
1350    
1351    /**
1352     * @see org.jruby.runtime.builtin.IRubyObject#getType()
1353     */

1354    public RubyClass getType() {
1355        return type();
1356    }
1357
1358    /**
1359     * @see org.jruby.runtime.builtin.IRubyObject#scanArgs()
1360     */

1361    public IRubyObject[] scanArgs(IRubyObject[] args, int required, int optional) {
1362        int total = required+optional;
1363        int real = checkArgumentCount(args,required,total);
1364        IRubyObject[] narr = new IRubyObject[total];
1365        System.arraycopy(args,0,narr,0,real);
1366        for(int i=real; i<total; i++) {
1367            narr[i] = getRuntime().getNil();
1368        }
1369        return narr;
1370    }
1371
1372    private transient Object JavaDoc dataStruct;
1373
1374    /**
1375     * @see org.jruby.runtime.builtin.IRubyObject#dataWrapStruct()
1376     */

1377    public synchronized void dataWrapStruct(Object JavaDoc obj) {
1378        this.dataStruct = obj;
1379    }
1380
1381    /**
1382     * @see org.jruby.runtime.builtin.IRubyObject#dataGetStruct()
1383     */

1384    public synchronized Object JavaDoc dataGetStruct() {
1385        return dataStruct;
1386    }
1387
1388    /** rb_equal
1389     *
1390     */

1391    public IRubyObject equal(IRubyObject other) {
1392        if(this == other || callMethod(getRuntime().getCurrentContext(), "==",other).isTrue()){
1393            return getRuntime().getTrue();
1394        }
1395 
1396        return getRuntime().getFalse();
1397    }
1398    
1399    public final IRubyObject equalInternal(final ThreadContext context, final IRubyObject other){
1400        if (this == other) return getRuntime().getTrue();
1401        return callMethod(context, "==", other);
1402    }
1403}
1404
Popular Tags