00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPArray.j"
00024 @import "CPObject.j"
00025 @import "CPDictionary.j"
00026
00027
00028 var CPObjectAccessorsForClass = nil,
00029 CPObjectModifiersForClass = nil;
00030
00031 CPUndefinedKeyException = @"CPUndefinedKeyException";
00032 CPTargetObjectUserInfoKey = @"CPTargetObjectUserInfoKey";
00033 CPUnknownUserInfoKey = @"CPUnknownUserInfoKey";
00034
00035 @implementation CPObject (CPKeyValueCoding)
00036
00037 + (BOOL)accessInstanceVariablesDirectly
00038 {
00039 return YES;
00040 }
00041
00042
00043 + (SEL)_accessorForKey:(CPString)aKey
00044 {
00045 if (!CPObjectAccessorsForClass)
00046 CPObjectAccessorsForClass = [CPDictionary dictionary];
00047
00048 var hash = [isa hash],
00049 selector = nil,
00050 accessors = [CPObjectAccessorsForClass objectForKey:hash];
00051
00052 if (accessors)
00053 {
00054 selector = [accessors objectForKey:aKey];
00055
00056 if (selector)
00057 return selector == [CPNull null] ? nil : selector;
00058 }
00059 else
00060 {
00061 accessors = [CPDictionary dictionary];
00062
00063 [CPObjectAccessorsForClass setObject:accessors forKey:hash];
00064 }
00065
00066 var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1);
00067
00068 if ([self instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] ||
00069 [self instancesRespondToSelector:selector = CPSelectorFromString(aKey)] ||
00070 [self instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] ||
00071 [self instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] ||
00072 [self instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] ||
00073 [self instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)])
00074 {
00075 [accessors setObject:selector forKey:aKey];
00076
00077 return selector;
00078 }
00079
00080 [accessors setObject:[CPNull null] forKey:aKey];
00081
00082 return nil;
00083 }
00084
00085
00086 + (SEL)_modifierForKey:(CPString)aKey
00087 {
00088 if (!CPObjectModifiersForClass)
00089 CPObjectModifiersForClass = [CPDictionary dictionary];
00090
00091 var hash = [isa hash],
00092 selector = nil,
00093 modifiers = [CPObjectModifiersForClass objectForKey:hash];
00094
00095 if (modifiers)
00096 {
00097 selector = [modifiers objectForKey:aKey];
00098
00099 if (selector)
00100 return selector == [CPNull null] ? nil : selector;
00101 }
00102 else
00103 {
00104 modifiers = [CPDictionary dictionary];
00105
00106 [CPObjectModifiersForClass setObject:modifiers forKey:hash];
00107 }
00108
00109 if (selector)
00110 return selector == [CPNull null] ? nil : selector;
00111
00112 var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1) + ':';
00113
00114 if ([self instancesRespondToSelector:selector = CPSelectorFromString("set" + capitalizedKey)] ||
00115 [self instancesRespondToSelector:selector = CPSelectorFromString("_set" + capitalizedKey)])
00116 {
00117 [modifiers setObject:selector forKey:aKey];
00118
00119 return selector;
00120 }
00121
00122 [modifiers setObject:[CPNull null] forKey:aKey];
00123
00124 return nil;
00125 }
00126
00127
00128 - (CPString)_ivarForKey:(CPString)aKey
00129 {
00130 var ivar = '_' + aKey;
00131
00132 if (typeof self[ivar] != "undefined")
00133 return ivar;
00134
00135 var isKey = "is" + aKey.charAt(0).toUpperCase() + aKey.substr(1);
00136
00137 ivar = '_' + isKey;
00138
00139 if (typeof self[ivar] != "undefined")
00140 return ivar;
00141
00142 ivar = aKey;
00143
00144 if (typeof self[ivar] != "undefined")
00145 return ivar;
00146
00147 ivar = isKey;
00148
00149 if (typeof self[ivar] != "undefined")
00150 return ivar;
00151
00152 return nil;
00153 }
00154
00155 - (id)valueForKey:(CPString)aKey
00156 {
00157 var theClass = [self class],
00158 selector = [theClass _accessorForKey:aKey];
00159
00160 if (selector)
00161 return objj_msgSend(self, selector);
00162
00163 if([theClass accessInstanceVariablesDirectly])
00164 {
00165 var ivar = [self _ivarForKey:aKey];
00166
00167 if (ivar)
00168 return self[ivar];
00169 }
00170
00171 return [self valueForUndefinedKey:aKey];
00172 }
00173
00174 - (id)valueForKeyPath:(CPString)aKeyPath
00175 {
00176 var keys = aKeyPath.split("."),
00177
00178 index = 0,
00179 count = keys.length,
00180
00181 value = self;
00182
00183 for(; index < count; ++index)
00184 value = [value valueForKey:keys[index]];
00185
00186 return value;
00187 }
00188
00189 - (CPDictionary)dictionaryWithValuesForKeys:(CPArray)keys
00190 {
00191 var index = 0,
00192 count = keys.length,
00193 dictionary = [CPDictionary dictionary];
00194
00195 for (; index < count; ++index)
00196 {
00197 var key = keys[index],
00198 value = [self valueForKey:key];
00199
00200 if (value === nil)
00201 [dictionary setObject:[CPNull null] forKey:key];
00202 else
00203 [dictionary setObject:value forKey:key];
00204 }
00205
00206 return dictionary;
00207 }
00208
00209 - (id)valueForUndefinedKey:(CPString)aKey
00210 {
00211 [[CPException exceptionWithName:CPUndefinedKeyException
00212 reason:[self description] + " is not key value coding-compliant for the key " + aKey
00213 userInfo:[CPDictionary dictionaryWithObjects:[self, aKey] forKeys:[CPTargetObjectUserInfoKey, CPUnknownUserInfoKey]]] raise];
00214 }
00215
00216 - (void)setValue:(id)aValue forKeyPath:(CPString)aKeyPath
00217 {
00218 if (!aKeyPath) aKeyPath = "self";
00219
00220 var i = 0,
00221 keys = aKeyPath.split("."),
00222 count = keys.length - 1,
00223 owner = self;
00224
00225 for(; i < count; ++i)
00226 owner = [owner valueForKey:keys[i]];
00227
00228 [owner setValue:aValue forKey:keys[i]];
00229 }
00230
00231 - (void)setValue:(id)aValue forKey:(CPString)aKey
00232 {
00233 var theClass = [self class],
00234 selector = [theClass _modifierForKey:aKey];
00235
00236 if (selector)
00237 return objj_msgSend(self, selector, aValue);
00238
00239 if([theClass accessInstanceVariablesDirectly])
00240 {
00241 var ivar = [self _ivarForKey:aKey];
00242
00243 if (ivar)
00244 {
00245 [self willChangeValueForKey:aKey];
00246
00247 self[ivar] = aValue;
00248
00249 [self didChangeValueForKey:aKey];
00250 }
00251
00252 return;
00253 }
00254
00255 [self setValue:aValue forUndefinedKey:aKey];
00256 }
00257
00258 - (void)setValue:(id)aValue forUndefinedKey:(CPString)aKey
00259 {
00260 [[CPException exceptionWithName:CPUndefinedKeyException
00261 reason:[self description] + " is not key value coding-compliant for the key " + aKey
00262 userInfo:[CPDictionary dictionaryWithObjects:[self, aKey] forKeys:[CPTargetObjectUserInfoKey, CPUnknownUserInfoKey]]] raise];
00263 }
00264
00265 @end
00266
00267 @implementation CPDictionary (KeyValueCoding)
00268
00269 - (id)valueForKey:(CPString)aKey
00270 {
00271 return [self objectForKey:aKey];
00272 }
00273
00274 - (void)setValue:(id)aValue forKey:(CPString)aKey
00275 {
00276 [self setObject:aValue forKey:aKey];
00277 }
00278
00279 @end
00280
00281
00282
00283 @implementation CPArray (KeyValueCoding)
00284
00285 - (id)valueForKey:(CPString)aKey
00286 {
00287 if (aKey.indexOf("@") == 0)
00288 {
00289 if (aKey == "@count")
00290 return length;
00291
00292 return nil;
00293 }
00294 else
00295 {
00296 var newArray = [],
00297 enumerator = [self objectEnumerator],
00298 object;
00299
00300 while (object = [enumerator nextObject])
00301 {
00302 var value = [object valueForKey:aKey];
00303
00304 if (!value && value !== "")
00305 value = [NSNull null];
00306
00307 newArray.push(value);
00308 }
00309
00310 return newArray;
00311 }
00312 }
00313
00314 - (id)valueForKeyPath:(CPString)aKeyPath
00315 {
00316 if (aKey.indexOf("@") == 0)
00317 {
00318 return nil;
00319 }
00320 else
00321 {
00322 var newArray = [],
00323 enumerator = [self objectEnumerator],
00324 object;
00325
00326 while (object = [enumerator nextObject])
00327 {
00328 var value = [object valueForKeyPath:aKeyPath];
00329
00330 if (!value && value !== "")
00331 value = [NSNull null];
00332
00333 newArray.push(value);
00334 }
00335
00336 return newArray;
00337 }
00338 }
00339
00340 - (void)setValue:(id)aValue forKey:(CPString)aKey
00341 {
00342 var enumerator = [self objectEnumerator],
00343 object;
00344
00345 while (object = [enumerator nextObject])
00346 [object setValue:aValue forKey:aKey];
00347 }
00348
00349 - (void)setValue:(id)aValue forKeyPath:(CPString)aKeyPath
00350 {
00351 var enumerator = [self objectEnumerator],
00352 object;
00353
00354 while (object = [enumerator nextObject])
00355 [object setValue:aValue forKeyPath:aKeyPath];
00356 }
00357
00358 @end