API  0.9.7
 All Classes Files Functions Variables 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 
65 @class CPString
66 @class CPException
67 
69 
70 
71 @protocol CPObject
72 
73 - (BOOL)isEqual:(id)object;
74 - (CPUInteger)hash;
75 
76 - (Class)superclass;
77 - (Class)class;
78 - (id)self;
79 
80 - (id)performSelector:(SEL)aSelector;
81 - (id)performSelector:(SEL)aSelector withObject:(id)object;
82 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
83 
84 - (BOOL)isProxy;
85 
86 - (BOOL)isKindOfClass:(Class)aClass;
87 - (BOOL)isMemberOfClass:(Class)aClass;
88 - (BOOL)conformsToProtocol:(Protocol)aProtocol;
89 
90 - (BOOL)respondsToSelector:(SEL)aSelector;
91 
92 - (CPString)description;
93 @optional
94 - (CPString)debugDescription;
95 
96 @end
97 
98 @protocol CPCoding
99 
100 - (void)encodeWithCoder:(CPCoder)aCoder;
101 - (id)initWithCoder:(CPCoder)aDecoder;
102 
103 @end
104 
105 @implementation CPObject <CPObject>
106 {
107  Class isa;
108 }
109 
110 + (void)load
111 {
112 }
113 
114 + (void)initialize
115 {
116 // CPLog("calling initialize "+self.name);
117 }
118 
123 + (id)new
124 {
125  return [[self alloc] init];
126 }
127 
131 + (id)alloc
132 {
133 // CPLog("calling alloc on " + self.name + ".");
134  return class_createInstance(self);
135 }
136 
137 + (id)allocWithCoder:(CPCoder)aCoder
138 {
139  return [self alloc];
140 }
141 
146 - (id)init
147 {
148  return self;
149 }
150 
155 - (id)copy
156 {
157  return self;
158 }
159 
164 - (id)mutableCopy
165 {
166  return [self copy];
167 }
168 
172 - (void)dealloc
173 {
174 }
175 
176 // Identifying classes
180 + (Class)class
181 {
182  return self;
183 }
184 
188 - (Class)class
189 {
190  return isa;
191 }
192 
196 + (Class)superclass
197 {
198  return self.super_class;
199 }
200 
205 + (BOOL)isSubclassOfClass:(Class)aClass
206 {
207  var theClass = self;
208 
209  for (; theClass; theClass = theClass.super_class)
210  if (theClass === aClass)
211  return YES;
212 
213  return NO;
214 }
215 
220 - (BOOL)isKindOfClass:(Class)aClass
221 {
222  return [isa isSubclassOfClass:aClass];
223 }
224 
225 + (BOOL)isKindOfClass:(Class)aClass
226 {
227  return [self isSubclassOfClass:aClass];
228 }
229 
234 - (BOOL)isMemberOfClass:(Class)aClass
235 {
236  return self.isa === aClass;
237 }
238 
239 + (BOOL)isMemberOfClass:(Class)aClass
240 {
241  return self === aClass;
242 }
243 
248 - (BOOL)isProxy
249 {
250  return NO;
251 }
252 
253 // Testing class functionality
259 + (BOOL)instancesRespondToSelector:(SEL)aSelector
260 {
261  return !!class_getInstanceMethod(self, aSelector);
262 }
263 
269 - (BOOL)respondsToSelector:(SEL)aSelector
270 {
271  // isa is isa.isa in class case.
272  return !!class_getInstanceMethod(isa, aSelector);
273 }
274 
280 - (BOOL)implementsSelector:(SEL)aSelector
281 {
282  var methods = class_copyMethodList(isa),
283  count = methods.length;
284 
285  while (count--)
286  if (method_getName(methods[count]) === aSelector)
287  return YES;
288 
289  return NO;
290 }
291 
297 + (BOOL)conformsToProtocol:(Protocol)aProtocol
298 {
299  return class_conformsToProtocol(self, aProtocol);
300 }
301 
307 - (BOOL)conformsToProtocol:(Protocol)aProtocol
308 {
309  return class_conformsToProtocol(isa, aProtocol);
310 }
311 
312 // Obtaining method information
313 
319 - (IMP)methodForSelector:(SEL)aSelector
320 {
321  return class_getMethodImplementation(isa, aSelector);
322 }
323 
329 + (IMP)instanceMethodForSelector:(SEL)aSelector
330 {
331  return class_getMethodImplementation(self, aSelector);
332 }
333 
339 - (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
340 {
341  // FIXME: We need to implement method signatures.
342  return nil;
343 }
344 
345 // Describing objects
349 - (CPString)description
350 {
351  return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
352 }
353 
354 + (CPString)description
355 {
356  return class_getName(self.isa);
357 }
358 
359 // Sending Messages
365 - (id)performSelector:(SEL)aSelector
366 {
367  return objj_msgSend(self, aSelector);
368 }
369 
376 - (id)performSelector:(SEL)aSelector withObject:(id)anObject
377 {
378  return objj_msgSend(self, aSelector, anObject);
379 }
380 
388 - (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
389 {
390  return objj_msgSend(self, aSelector, anObject, anotherObject);
391 }
392 
399 - (id)performSelector:(SEL)aSelector withObjects:(id)anObject, ...
400 {
401  var params = [self, aSelector].concat(Array.prototype.slice.apply(arguments, [3]));
402  return objj_msgSend.apply(this, params);
403 }
404 
405 - (id)forwardingTargetForSelector:(SEL)aSelector
406 {
407  return nil;
408 }
409 
410 // Forwarding Messages
417 - (void)forwardInvocation:(CPInvocation)anInvocation
418 {
419  [self doesNotRecognizeSelector:[anInvocation selector]];
420 }
421 
422 // Error Handling
428 - (void)doesNotRecognizeSelector:(SEL)aSelector
429 {
430  [CPException raise:CPInvalidArgumentException reason:
431  (class_isMetaClass(isa) ? "+" : "-") + " [" + [self className] + " " + aSelector + "] unrecognized selector sent to " +
432  (class_isMetaClass(isa) ? "class " + class_getName(isa) : "instance 0x" + [CPString stringWithHash:[self UID]])];
433 }
434 
435 // Archiving
444 - (id)awakeAfterUsingCoder:(CPCoder)aCoder
445 {
446  return self;
447 }
448 
453 - (Class)classForKeyedArchiver
454 {
455  return [self classForCoder];
456 }
457 
462 - (Class)classForCoder
463 {
464  return [self class];
465 }
466 
472 - (id)replacementObjectForArchiver:(CPArchiver)anArchiver
473 {
474  return [self replacementObjectForCoder:anArchiver];
475 }
476 
482 - (id)replacementObjectForKeyedArchiver:(CPKeyedArchiver)anArchiver
483 {
484  return [self replacementObjectForCoder:anArchiver];
485 }
486 
492 - (id)replacementObjectForCoder:(CPCoder)aCoder
493 {
494  return self;
495 }
496 
501 + (void)setVersion:(int)aVersion
502 {
503  class_setVersion(self, aVersion);
504 }
505 
509 + (int)version
510 {
511  return class_getVersion(self);
512 }
513 
514 // Scripting (?)
518 - (CPString)className
519 {
520  // FIXME: Why doesn't this work in KVO???
521  // return class_getName([self class]);
522  return isa.name;
523 }
524 
525 // Extras
530 - (id)autorelease
531 {
532  return self;
533 }
534 
538 - (unsigned)hash
539 {
540  return [self UID];
541 }
542 
543 - (CPString)UID
544 {
545  if (typeof self._UID === "undefined")
546  self._UID = objj_generateObjectUID();
547 
548  return self._UID + "";
549 }
550 
555 - (BOOL)isEqual:(id)anObject
556 {
557  return self === anObject || [self UID] === [anObject UID];
558 }
559 
564 - (id)retain
565 {
566  return self;
567 }
568 
572 - (void)release
573 {
574 }
575 
579 - (id)self
580 {
581  return self;
582 }
583 
587 - (Class)superclass
588 {
589  return isa.super_class;
590 }
591 
592 @end
593 
594 function CPDescriptionOfObject(anObject, maximumRecursionDepth)
595 {
596  if (anObject === nil)
597  return "nil";
598 
599  if (anObject === undefined)
600  return "undefined";
601 
602  if (anObject === window)
603  return "window";
604 
605  if (maximumRecursionDepth === 0)
606  return "...";
607 
608  if (anObject.isa)
609  {
610  if ([anObject isKindOfClass:CPString])
611  return '@"' + [anObject description] + '"';
612 
613  if ([anObject respondsToSelector:@selector(_descriptionWithMaximumDepth:)])
614  return [anObject _descriptionWithMaximumDepth:maximumRecursionDepth !== undefined ? maximumRecursionDepth - 1 : maximumRecursionDepth];
615 
616  return [anObject description];
617  }
618 
619  if (typeof(anObject) !== "object")
620  return String(anObject);
621 
622  var properties = [],
623  desc;
624 
625  for (var property in anObject)
626  if (anObject.hasOwnProperty(property))
627  properties.push(property);
628 
629  properties.sort();
630 
631  if (properties.length === 2 && anObject.hasOwnProperty("width") && anObject.hasOwnProperty("height"))
632  desc = [CPString stringWithFormat:@"CGSize: (%f, %f)", anObject.width, anObject.height];
633  else if (properties.length === 2 && anObject.hasOwnProperty("x") && anObject.hasOwnProperty("y"))
634  desc = [CPString stringWithFormat:@"CGPoint: (%f, %f)", anObject.x, anObject.y];
635  else if (properties.length === 2 && anObject.hasOwnProperty("origin") && anObject.hasOwnProperty("size"))
636  desc = [CPString stringWithFormat:@"CGRect: (%f, %f), (%f, %f)", anObject.origin.x, anObject.origin.y, anObject.size.width, anObject.size.height];
637  else if (properties.length === 4 && anObject.hasOwnProperty("top") && anObject.hasOwnProperty("right") && anObject.hasOwnProperty("bottom") && anObject.hasOwnProperty("left"))
638  desc = [CPString stringWithFormat:@"CGInset: { top:%f, right:%f, bottom:%f, left:%f }", anObject.top, anObject.right, anObject.bottom, anObject.left];
639  else
640  {
641  desc = "{";
642 
643  for (var i = 0; i < properties.length; ++i)
644  {
645  if (i === 0)
646  desc += "\n";
647 
648  var value = anObject[properties[i]],
649  valueDescription = CPDescriptionOfObject(value, maximumRecursionDepth !== undefined ? maximumRecursionDepth - 1 : maximumRecursionDepth).split("\n").join("\n ");
650 
651  desc += " " + properties[i] + ": " + valueDescription;
652 
653  if (i < properties.length - 1)
654  desc += ",\n";
655  else
656  desc += "\n";
657  }
658 
659  desc += "}";
660  }
661 
662  return desc;
663 }