API  0.9.8
 All Classes Files Functions Variables Typedefs Macros Groups Pages
CPObject.j
Go to the documentation of this file.
1 /*
2  * CPObject.j
3  * Foundation
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
67 
68 
69 @protocol CPObject
70 
71 - (BOOL)isEqual:(id)object;
72 - (CPUInteger)hash;
73 
74 - (Class)superclass;
75 - (Class)class;
76 - (id)self;
77 
78 - (id)performSelector:(SEL)aSelector;
79 - (id)performSelector:(SEL)aSelector withObject:(id)object;
80 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
81 
82 - (BOOL)isProxy;
83 
84 - (BOOL)isKindOfClass:(Class)aClass;
85 - (BOOL)isMemberOfClass:(Class)aClass;
86 - (BOOL)conformsToProtocol:(Protocol)aProtocol;
87 
88 - (BOOL)respondsToSelector:(SEL)aSelector;
89 
91 @optional
92 - (CPString)debugDescription;
93 
94 @end
95 
96 @protocol CPCoding
97 
98 - (void)encodeWithCoder:(CPCoder)aCoder;
99 - (id)initWithCoder:(CPCoder)aDecoder;
100 
101 @end
102 
103 @implementation CPObject <CPObject>
104 {
105  id isa;
106 }
107 
108 + (void)load
109 {
110 }
111 
112 + (void)initialize
113 {
114 // CPLog("calling initialize "+self.name);
115 }
116 
121 + (id)new
122 {
123  return [[self alloc] init];
124 }
125 
129 + (id)alloc
130 {
131 // CPLog("calling alloc on " + self.name + ".");
132  return class_createInstance(self);
133 }
134 
135 + (id)allocWithCoder:(CPCoder)aCoder
136 {
137  return [self alloc];
138 }
139 
144 - (id)init
145 {
146  return self;
147 }
148 
153 - (id)copy
154 {
155  return self;
156 }
157 
162 - (id)mutableCopy
163 {
164  return [self copy];
165 }
166 
170 - (void)dealloc
171 {
172 }
173 
174 // Identifying classes
178 + (Class)class
179 {
180  return self;
181 }
182 
186 - (Class)class
187 {
188  return isa;
189 }
190 
194 + (Class)superclass
195 {
196  return self.super_class;
197 }
198 
203 + (BOOL)isSubclassOfClass:(Class)aClass
204 {
205  var theClass = self;
206 
207  for (; theClass; theClass = theClass.super_class)
208  if (theClass === aClass)
209  return YES;
210 
211  return NO;
212 }
213 
218 - (BOOL)isKindOfClass:(Class)aClass
219 {
220  return [isa isSubclassOfClass:aClass];
221 }
222 
223 + (BOOL)isKindOfClass:(Class)aClass
224 {
225  return [self isSubclassOfClass:aClass];
226 }
227 
232 - (BOOL)isMemberOfClass:(Class)aClass
233 {
234  return self.isa === aClass;
235 }
236 
237 + (BOOL)isMemberOfClass:(Class)aClass
238 {
239  return self === aClass;
240 }
241 
246 - (BOOL)isProxy
247 {
248  return NO;
249 }
250 
251 // Testing class functionality
257 + (BOOL)instancesRespondToSelector:(SEL)aSelector
258 {
259  return !!class_getInstanceMethod(self, aSelector);
260 }
261 
267 - (BOOL)respondsToSelector:(SEL)aSelector
268 {
269  // isa is isa.isa in class case.
270  return !!class_getInstanceMethod(isa, aSelector);
271 }
272 
278 - (BOOL)implementsSelector:(SEL)aSelector
279 {
280  var methods = class_copyMethodList(isa),
281  count = methods.length;
282 
283  while (count--)
284  if (method_getName(methods[count]) === aSelector)
285  return YES;
286 
287  return NO;
288 }
289 
295 + (BOOL)conformsToProtocol:(Protocol)aProtocol
296 {
297  return class_conformsToProtocol(self, aProtocol);
298 }
299 
305 - (BOOL)conformsToProtocol:(Protocol)aProtocol
306 {
307  return class_conformsToProtocol(isa, aProtocol);
308 }
309 
310 // Obtaining method information
311 
317 - (IMP)methodForSelector:(SEL)aSelector
318 {
319  return class_getMethodImplementation(isa, aSelector);
320 }
321 
327 + (IMP)instanceMethodForSelector:(SEL)aSelector
328 {
329  return class_getMethodImplementation(self, aSelector);
330 }
331 
337 - (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
338 {
339  // FIXME: We need to implement method signatures.
340  return nil;
341 }
342 
343 // Describing objects
348 {
349  return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
350 }
351 
353 {
354  return class_getName(self.isa);
355 }
356 
357 // Sending Messages
363 - (id)performSelector:(SEL)aSelector
364 {
365  return self.isa.objj_msgSend0(self, aSelector);
366 }
367 
374 - (id)performSelector:(SEL)aSelector withObject:(id)anObject
375 {
376  return self.isa.objj_msgSend1(self, aSelector, anObject);
377 }
378 
386 - (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
387 {
388  return self.isa.objj_msgSend2(self, aSelector, anObject, anotherObject);
389 }
390 
397 - (id)performSelector:(SEL)aSelector withObjects:(id)anObject, ...
398 {
399  var params = [self, aSelector].concat(Array.prototype.slice.apply(arguments, [3]));
400  return objj_msgSend.apply(this, params);
401 }
402 
403 - (id)forwardingTargetForSelector:(SEL)aSelector
404 {
405  return nil;
406 }
407 
408 // Forwarding Messages
415 - (void)forwardInvocation:(CPInvocation)anInvocation
416 {
417  [self doesNotRecognizeSelector:[anInvocation selector]];
418 }
419 
420 // Error Handling
426 - (void)doesNotRecognizeSelector:(SEL)aSelector
427 {
428  [CPException raise:CPInvalidArgumentException reason:
429  (class_isMetaClass(isa) ? "+" : "-") + " [" + [self className] + " " + aSelector + "] unrecognized selector sent to " +
430  (class_isMetaClass(isa) ? "class " + class_getName(isa) : "instance 0x" + [CPString stringWithHash:[self UID]])];
431 }
432 
433 // Archiving
442 - (id)awakeAfterUsingCoder:(CPCoder)aCoder
443 {
444  return self;
445 }
446 
451 - (Class)classForKeyedArchiver
452 {
453  return [self classForCoder];
454 }
455 
460 - (Class)classForCoder
461 {
462  return [self class];
463 }
464 
470 - (id)replacementObjectForArchiver:(CPArchiver)anArchiver
471 {
472  return [self replacementObjectForCoder:anArchiver];
473 }
474 
480 - (id)replacementObjectForKeyedArchiver:(CPKeyedArchiver)anArchiver
481 {
482  return [self replacementObjectForCoder:anArchiver];
483 }
484 
490 - (id)replacementObjectForCoder:(CPCoder)aCoder
491 {
492  return self;
493 }
494 
499 + (void)setVersion:(int)aVersion
500 {
501  class_setVersion(self, aVersion);
502 }
503 
507 + (int)version
508 {
509  return class_getVersion(self);
510 }
511 
512 // Scripting (?)
517 {
518  // FIXME: Why doesn't this work in KVO???
519  // return class_getName([self class]);
520  return isa.name;
521 }
522 
523 // Extras
528 - (id)autorelease
529 {
530  return self;
531 }
532 
536 - (unsigned)hash
537 {
538  return [self UID];
539 }
540 
541 - (CPString)UID
542 {
543  if (typeof self._UID === "undefined")
544  self._UID = objj_generateObjectUID();
545 
546  return self._UID + "";
547 }
548 
553 - (BOOL)isEqual:(id)anObject
554 {
555  return self === anObject || [self UID] === [anObject UID];
556 }
557 
562 - (id)retain
563 {
564  return self;
565 }
566 
570 - (void)release
571 {
572 }
573 
577 - (id)self
578 {
579  return self;
580 }
581 
585 - (Class)superclass
586 {
587  return isa.super_class;
588 }
589 
590 @end
591 
592 function CPDescriptionOfObject(anObject, maximumRecursionDepth)
593 {
594  if (anObject === nil)
595  return "nil";
596 
597  if (anObject === undefined)
598  return "undefined";
599 
600  if (anObject === window)
601  return "window";
602 
603  if (maximumRecursionDepth === 0)
604  return "...";
605 
606  if (anObject.isa)
607  {
608  if ([anObject isKindOfClass:CPString])
609  return '@"' + [anObject description] + '"';
610 
611  if ([anObject respondsToSelector:@selector(_descriptionWithMaximumDepth:)])
612  return [anObject _descriptionWithMaximumDepth:maximumRecursionDepth !== undefined ? maximumRecursionDepth - 1 : maximumRecursionDepth];
613 
614  return [anObject description];
615  }
616 
617  if (typeof(anObject) !== "object")
618  return String(anObject);
619 
620  var properties = [],
621  desc;
622 
623  for (var property in anObject)
624  if (anObject.hasOwnProperty(property))
625  properties.push(property);
626 
627  properties.sort();
628 
629  if (properties.length === 2 && anObject.hasOwnProperty("width") && anObject.hasOwnProperty("height"))
630  desc = [CPString stringWithFormat:@"CGSize: (%f, %f)", anObject.width, anObject.height];
631  else if (properties.length === 2 && anObject.hasOwnProperty("x") && anObject.hasOwnProperty("y"))
632  desc = [CPString stringWithFormat:@"CGPoint: (%f, %f)", anObject.x, anObject.y];
633  else if (properties.length === 2 && anObject.hasOwnProperty("origin") && anObject.hasOwnProperty("size"))
634  desc = [CPString stringWithFormat:@"CGRect: (%f, %f), (%f, %f)", anObject.origin.x, anObject.origin.y, anObject.size.width, anObject.size.height];
635  else if (properties.length === 4 && anObject.hasOwnProperty("top") && anObject.hasOwnProperty("right") && anObject.hasOwnProperty("bottom") && anObject.hasOwnProperty("left"))
636  desc = [CPString stringWithFormat:@"CGInset: { top:%f, right:%f, bottom:%f, left:%f }", anObject.top, anObject.right, anObject.bottom, anObject.left];
637  else
638  {
639  desc = "{";
640 
641  for (var i = 0; i < properties.length; ++i)
642  {
643  if (i === 0)
644  desc += "\n";
645 
646  var value = anObject[properties[i]],
647  valueDescription = CPDescriptionOfObject(value, maximumRecursionDepth !== undefined ? maximumRecursionDepth - 1 : maximumRecursionDepth).split("\n").join("\n ");
648 
649  desc += " " + properties[i] + ": " + valueDescription;
650 
651  if (i < properties.length - 1)
652  desc += ",\n";
653  else
654  desc += "\n";
655  }
656 
657  desc += "}";
658  }
659 
660  return desc;
661 }