KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyClass


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-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
15  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
16  * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
17  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
18  *
19  * Alternatively, the contents of this file may be used under the terms of
20  * either of the GNU General Public License Version 2 or later (the "GPL"),
21  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
22  * in which case the provisions of the GPL or the LGPL are applicable instead
23  * of those above. If you wish to allow use of your version of this file only
24  * under the terms of either the GPL or the LGPL, and not to allow others to
25  * use your version of this file under the terms of the CPL, indicate your
26  * decision by deleting the provisions above and replace them with the notice
27  * and other provisions required by the GPL or the LGPL. If you do not delete
28  * the provisions above, a recipient may use your version of this file under
29  * the terms of any one of the CPL, the GPL or the LGPL.
30  ***** END LICENSE BLOCK *****/

31 package org.jruby;
32
33 import java.io.IOException JavaDoc;
34 import java.util.Map JavaDoc;
35 import org.jruby.runtime.Block;
36 import org.jruby.runtime.CallbackFactory;
37 import org.jruby.runtime.ClassIndex;
38 import org.jruby.runtime.ObjectAllocator;
39 import org.jruby.runtime.ObjectMarshal;
40 import org.jruby.runtime.ThreadContext;
41 import org.jruby.runtime.builtin.IRubyObject;
42 import org.jruby.runtime.marshal.MarshalStream;
43 import org.jruby.runtime.marshal.UnmarshalStream;
44 import org.jruby.util.collections.SinglyLinkedList;
45
46 /**
47  *
48  * @author jpetersen
49  */

50 public class RubyClass extends RubyModule {
51     
52     private final Ruby runtime;
53     
54     // the default allocator
55
private final ObjectAllocator allocator;
56     
57     private ObjectMarshal marshal;
58     
59     private static final ObjectMarshal DEFAULT_OBJECT_MARSHAL = new ObjectMarshal() {
60         public void marshalTo(Ruby runtime, Object JavaDoc obj, RubyClass type,
61                               MarshalStream marshalStream) throws IOException JavaDoc {
62             IRubyObject object = (IRubyObject)obj;
63             
64             Map JavaDoc iVars = object.getInstanceVariablesSnapshot();
65             
66             marshalStream.dumpInstanceVars(iVars);
67         }
68
69         public Object JavaDoc unmarshalFrom(Ruby runtime, RubyClass type,
70                                     UnmarshalStream unmarshalStream) throws IOException JavaDoc {
71             IRubyObject result = type.allocate();
72             
73             unmarshalStream.registerLinkTarget(result);
74
75             unmarshalStream.defaultInstanceVarsUnmarshal(result);
76
77             return result;
78         }
79     };
80
81     /**
82      * @mri rb_boot_class
83      */

84     
85     /**
86      * @mri rb_boot_class
87      */

88     
89     /**
90      * @mri rb_boot_class
91      */

92     
93     /**
94      * @mri rb_boot_class
95      */

96     protected RubyClass(RubyClass superClass, ObjectAllocator allocator) {
97         this(superClass.getRuntime(), superClass.getRuntime().getClass("Class"), superClass, allocator, null, null);
98
99         infectBy(superClass);
100     }
101
102     protected RubyClass(Ruby runtime, RubyClass superClass, ObjectAllocator allocator) {
103         this(runtime, null, superClass, allocator, null, null);
104     }
105
106     protected RubyClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator) {
107         this(runtime, metaClass, superClass, allocator, null, null);
108     }
109     
110     protected RubyClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator, SinglyLinkedList parentCRef, String JavaDoc name) {
111         super(runtime, metaClass, superClass, parentCRef, name);
112         this.allocator = allocator;
113         this.runtime = runtime;
114         
115         // use parent's marshal, or default object marshal by default
116
if (superClass != null) {
117             this.marshal = superClass.getMarshal();
118         } else {
119             this.marshal = DEFAULT_OBJECT_MARSHAL;
120         }
121     }
122     
123     public int getNativeTypeIndex() {
124         return ClassIndex.CLASS;
125     }
126     
127     public final IRubyObject allocate() {
128         return getAllocator().allocate(getRuntime(), this);
129     }
130     
131     public final ObjectMarshal getMarshal() {
132         return marshal;
133     }
134     
135     public final void setMarshal(ObjectMarshal marshal) {
136         this.marshal = marshal;
137     }
138     
139     public final void marshal(Object JavaDoc obj, MarshalStream marshalStream) throws IOException JavaDoc {
140         getMarshal().marshalTo(getRuntime(), obj, this, marshalStream);
141     }
142     
143     public final Object JavaDoc unmarshal(UnmarshalStream unmarshalStream) throws IOException JavaDoc {
144         return getMarshal().unmarshalFrom(getRuntime(), this, unmarshalStream);
145     }
146     
147     public static RubyClass newClassClass(Ruby runtime, RubyClass moduleClass) {
148         ObjectAllocator defaultAllocator = new ObjectAllocator() {
149             public IRubyObject allocate(Ruby runtime, RubyClass klass) {
150                 IRubyObject instance = new RubyObject(runtime, klass);
151                 instance.setMetaClass(klass);
152
153                 return instance;
154             }
155         };
156         
157         RubyClass classClass = new RubyClass(
158                 runtime,
159                 null /* FIXME: should be something else? */,
160                 moduleClass,
161                 defaultAllocator,
162                 null,
163                 "Class");
164         
165         classClass.index = ClassIndex.CLASS;
166         
167         return classClass;
168     }
169     
170     /* (non-Javadoc)
171      * @see org.jruby.RubyObject#getRuntime()
172      */

173     public Ruby getRuntime() {
174         return runtime;
175     }
176
177     public boolean isModule() {
178         return false;
179     }
180
181     public boolean isClass() {
182         return true;
183     }
184
185     public static void createClassClass(RubyClass classClass) {
186         CallbackFactory callbackFactory = classClass.getRuntime().callbackFactory(RubyClass.class);
187         classClass.getMetaClass().defineMethod("new", callbackFactory.getOptSingletonMethod("newClass"));
188         classClass.defineFastMethod("allocate", callbackFactory.getFastMethod("allocate"));
189         classClass.defineMethod("new", callbackFactory.getOptMethod("newInstance"));
190         classClass.defineMethod("superclass", callbackFactory.getMethod("superclass"));
191         classClass.defineFastMethod("initialize_copy", callbackFactory.getFastMethod("initialize_copy", RubyKernel.IRUBY_OBJECT));
192         classClass.getMetaClass().defineMethod("inherited", callbackFactory.getSingletonMethod("inherited", RubyKernel.IRUBY_OBJECT));
193         classClass.undefineMethod("module_function");
194     }
195     
196     public static IRubyObject inherited(IRubyObject recv, IRubyObject arg, Block block) {
197         return recv.getRuntime().getNil();
198     }
199
200     /** Invokes if a class is inherited from an other class.
201      *
202      * MRI: rb_class_inherited
203      *
204      * @since Ruby 1.6.7
205      *
206      */

207     public void inheritedBy(RubyClass superType) {
208         if (superType == null) {
209             superType = getRuntime().getObject();
210         }
211         superType.callMethod(getRuntime().getCurrentContext(), "inherited", this);
212     }
213
214     public boolean isSingleton() {
215         return false;
216     }
217
218     public RubyClass getMetaClass() {
219         RubyClass type = super.getMetaClass();
220
221         return type != null ? type : getRuntime().getClass("Class");
222     }
223
224     public RubyClass getRealClass() {
225         return this;
226     }
227
228     public static RubyClass newClass(Ruby runtime, RubyClass superClass, SinglyLinkedList parentCRef, String JavaDoc name) {
229         return new RubyClass(runtime, runtime.getClass("Class"), superClass, superClass.getAllocator(), parentCRef, name);
230     }
231
232     public static RubyClass cloneClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator, SinglyLinkedList parentCRef, String JavaDoc name) {
233         return new RubyClass(runtime, metaClass, superClass, allocator, parentCRef, name);
234     }
235
236     /** Create a new subclass of this class.
237      * @return the new sublass
238      * @throws TypeError if this is class `Class'
239      * @mri rb_class_new
240      */

241     protected RubyClass subclass() {
242         if (this == getRuntime().getClass("Class")) {
243             throw getRuntime().newTypeError("can't make subclass of Class");
244         }
245         return new RubyClass(this, getAllocator());
246     }
247
248     /** rb_class_new_instance
249      *
250      */

251     public IRubyObject newInstance(IRubyObject[] args, Block block) {
252         IRubyObject obj = (IRubyObject) allocate();
253         obj.callInit(args, block);
254         return obj;
255     }
256     
257     public ObjectAllocator getAllocator() {
258         return allocator;
259     }
260
261     /** rb_class_s_new
262      *
263      */

264     public static RubyClass newClass(IRubyObject recv, IRubyObject[] args, Block block) {
265         final Ruby runtime = recv.getRuntime();
266
267         RubyClass superClass;
268         if (args.length > 0) {
269             if (args[0] instanceof RubyClass) {
270                 superClass = (RubyClass) args[0];
271             } else {
272                 throw runtime.newTypeError(
273                     "wrong argument type " + args[0].getType().getName() + " (expected Class)");
274             }
275         } else {
276             superClass = runtime.getObject();
277         }
278
279         ThreadContext tc = runtime.getCurrentContext();
280         // use allocator of superclass, since this will be a pure Ruby class
281
RubyClass newClass = superClass.newSubClass(null, superClass.getAllocator(),tc.peekCRef());
282
283         // call "initialize" method
284
newClass.callInit(args, block);
285
286         // call "inherited" method of the superclass
287
newClass.inheritedBy(superClass);
288
289         if (block.isGiven()) block.yield(tc, null, newClass, newClass, false);
290
291         return newClass;
292     }
293
294     /** Return the real super class of this class.
295      *
296      * rb_class_superclass
297      *
298      */

299     public IRubyObject superclass(Block block) {
300         RubyClass superClass = getSuperClass();
301         while (superClass != null && superClass.isIncluded()) {
302             superClass = superClass.getSuperClass();
303         }
304
305         return superClass != null ? superClass : getRuntime().getNil();
306     }
307
308     /** rb_class_s_inherited
309      *
310      */

311     public static IRubyObject inherited(RubyClass recv) {
312         throw recv.getRuntime().newTypeError("can't make subclass of Class");
313     }
314
315     public static void marshalTo(RubyClass clazz, MarshalStream output) throws java.io.IOException JavaDoc {
316         output.writeString(clazz.getName());
317     }
318
319     public static RubyModule unmarshalFrom(UnmarshalStream output) throws java.io.IOException JavaDoc {
320         return (RubyClass) RubyModule.unmarshalFrom(output);
321     }
322
323     public RubyClass newSubClass(String JavaDoc name, ObjectAllocator allocator, SinglyLinkedList parentCRef) {
324         RubyClass classClass = runtime.getClass("Class");
325         
326         // Cannot subclass 'Class' or metaclasses
327
if (this == classClass) {
328             throw runtime.newTypeError("can't make subclass of Class");
329         } else if (this instanceof MetaClass) {
330             throw runtime.newTypeError("can't make subclass of virtual class");
331         }
332
333         RubyClass newClass = new RubyClass(runtime, classClass, this, allocator, parentCRef, name);
334
335         newClass.makeMetaClass(getMetaClass(), newClass.getCRef());
336         newClass.inheritedBy(this);
337
338         if(null != name) {
339             ((RubyModule)parentCRef.getValue()).setConstant(name, newClass);
340         }
341
342         return newClass;
343     }
344     
345     protected IRubyObject doClone() {
346         return RubyClass.cloneClass(getRuntime(), getMetaClass(), getSuperClass(), getAllocator(), null/*FIXME*/, null);
347     }
348     
349     /** rb_class_init_copy
350      *
351      */

352     public IRubyObject initialize_copy(IRubyObject original){
353
354         if (((RubyClass) original).isSingleton()){
355             throw getRuntime().newTypeError("can't copy singleton class");
356         }
357         
358         super.initialize_copy(original);
359         
360         return this;
361     }
362 }
363
Popular Tags