1 31 package org.jruby; 32 33 import java.io.IOException ; 34 import java.util.Map ; 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 50 public class RubyClass extends RubyModule { 51 52 private final Ruby runtime; 53 54 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 obj, RubyClass type, 61 MarshalStream marshalStream) throws IOException { 62 IRubyObject object = (IRubyObject)obj; 63 64 Map iVars = object.getInstanceVariablesSnapshot(); 65 66 marshalStream.dumpInstanceVars(iVars); 67 } 68 69 public Object unmarshalFrom(Ruby runtime, RubyClass type, 70 UnmarshalStream unmarshalStream) throws IOException { 71 IRubyObject result = type.allocate(); 72 73 unmarshalStream.registerLinkTarget(result); 74 75 unmarshalStream.defaultInstanceVarsUnmarshal(result); 76 77 return result; 78 } 79 }; 80 81 84 85 88 89 92 93 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 name) { 111 super(runtime, metaClass, superClass, parentCRef, name); 112 this.allocator = allocator; 113 this.runtime = runtime; 114 115 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 obj, MarshalStream marshalStream) throws IOException { 140 getMarshal().marshalTo(getRuntime(), obj, this, marshalStream); 141 } 142 143 public final Object unmarshal(UnmarshalStream unmarshalStream) throws IOException { 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 , 160 moduleClass, 161 defaultAllocator, 162 null, 163 "Class"); 164 165 classClass.index = ClassIndex.CLASS; 166 167 return classClass; 168 } 169 170 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 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 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 name) { 233 return new RubyClass(runtime, metaClass, superClass, allocator, parentCRef, name); 234 } 235 236 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 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 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 RubyClass newClass = superClass.newSubClass(null, superClass.getAllocator(),tc.peekCRef()); 282 283 newClass.callInit(args, block); 285 286 newClass.inheritedBy(superClass); 288 289 if (block.isGiven()) block.yield(tc, null, newClass, newClass, false); 290 291 return newClass; 292 } 293 294 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 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 { 316 output.writeString(clazz.getName()); 317 } 318 319 public static RubyModule unmarshalFrom(UnmarshalStream output) throws java.io.IOException { 320 return (RubyClass) RubyModule.unmarshalFrom(output); 321 } 322 323 public RubyClass newSubClass(String name, ObjectAllocator allocator, SinglyLinkedList parentCRef) { 324 RubyClass classClass = runtime.getClass("Class"); 325 326 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, null); 347 } 348 349 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 |