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 "CPDictionary.j"
00025 @import "CPNull.j"
00026 @import "CPObject.j"
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 UID = [isa UID],
00049 selector = nil,
00050 accessors = [CPObjectAccessorsForClass objectForKey:UID];
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:UID];
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 UID = [isa UID],
00092 selector = nil,
00093 modifiers = [CPObjectModifiersForClass objectForKey:UID];
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:UID];
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 firstDotIndex = aKeyPath.indexOf(".");
00177
00178 if (firstDotIndex === -1)
00179 return [self valueForKey:aKeyPath];
00180
00181 var firstKeyComponent = aKeyPath.substring(0, firstDotIndex),
00182 remainingKeyPath = aKeyPath.substring(firstDotIndex+1),
00183 value = [self valueForKey:firstKeyComponent];
00184
00185 return [value valueForKeyPath:remainingKeyPath];
00186 }
00187
00188 - (CPDictionary)dictionaryWithValuesForKeys:(CPArray)keys
00189 {
00190 var index = 0,
00191 count = keys.length,
00192 dictionary = [CPDictionary dictionary];
00193
00194 for (; index < count; ++index)
00195 {
00196 var key = keys[index],
00197 value = [self valueForKey:key];
00198
00199 if (value === nil)
00200 [dictionary setObject:[CPNull null] forKey:key];
00201 else
00202 [dictionary setObject:value forKey:key];
00203 }
00204
00205 return dictionary;
00206 }
00207
00208 - (id)valueForUndefinedKey:(CPString)aKey
00209 {
00210 [[CPException exceptionWithName:CPUndefinedKeyException
00211 reason:[self description] + " is not key value coding-compliant for the key " + aKey
00212 userInfo:[CPDictionary dictionaryWithObjects:[self, aKey] forKeys:[CPTargetObjectUserInfoKey, CPUnknownUserInfoKey]]] raise];
00213 }
00214
00215 - (void)setValue:(id)aValue forKeyPath:(CPString)aKeyPath
00216 {
00217 if (!aKeyPath) aKeyPath = "self";
00218
00219 var i = 0,
00220 keys = aKeyPath.split("."),
00221 count = keys.length - 1,
00222 owner = self;
00223
00224 for(; i < count; ++i)
00225 owner = [owner valueForKey:keys[i]];
00226
00227 [owner setValue:aValue forKey:keys[i]];
00228 }
00229
00230 - (void)setValue:(id)aValue forKey:(CPString)aKey
00231 {
00232 var theClass = [self class],
00233 selector = [theClass _modifierForKey:aKey];
00234
00235 if (selector)
00236 return objj_msgSend(self, selector, aValue);
00237
00238 if([theClass accessInstanceVariablesDirectly])
00239 {
00240 var ivar = [self _ivarForKey:aKey];
00241
00242 if (ivar)
00243 {
00244 [self willChangeValueForKey:aKey];
00245
00246 self[ivar] = aValue;
00247
00248 [self didChangeValueForKey:aKey];
00249
00250 return;
00251 }
00252 }
00253
00254 [self setValue:aValue forUndefinedKey:aKey];
00255 }
00256
00257 - (void)setValue:(id)aValue forUndefinedKey:(CPString)aKey
00258 {
00259 [[CPException exceptionWithName:CPUndefinedKeyException
00260 reason:[self description] + " is not key value coding-compliant for the key " + aKey
00261 userInfo:[CPDictionary dictionaryWithObjects:[self, aKey] forKeys:[CPTargetObjectUserInfoKey, CPUnknownUserInfoKey]]] raise];
00262 }
00263
00264 @end
00265
00266 @implementation CPDictionary (KeyValueCoding)
00267
00268 - (id)valueForKey:(CPString)aKey
00269 {
00270 return [self objectForKey:aKey];
00271 }
00272
00273 - (void)setValue:(id)aValue forKey:(CPString)aKey
00274 {
00275 [self setObject:aValue forKey:aKey];
00276 }
00277
00278 @end
00279
00280 @import "CPKeyValueObserving.j"
00281 @import "CPArray+KVO.j"