From bf94dd3a6e1b69425918c2ac2b51b4f3aafee8de Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 13 Jun 2013 13:20:22 +0100 Subject: [PATCH] New: KVC `setValue:forKey:` now automatically unwraps `CPValue`. This corresponds to the same KVC behaviour in Cocoa and is key when decoding cibs with certain properties set to struct values (such as NSSize). --- Foundation/CPKeyValueCoding.j | 6 ++++ Tests/Foundation/CPKeyValueCodingTest.j | 45 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 9e7d319ba..fa86c5f9c 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -187,6 +187,12 @@ var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", - (void)setValue:(id)aValue forKey:(CPString)aKey { + // setValue:forKey: should unwrap CPValue by default. In Objective-C we would need to care about which type + // the setter takes (or target ivar) and send [aValue rectValue], [aValue pointValue] etc, but in + // Objective-C we can use them interchangably. + if (aValue && aValue.isa && [aValue isKindOfClass:CPValue]) + aValue = [aValue JSObject]; + var theClass = [self class], modifier = nil, modifiers = theClass[CPObjectModifiersForClassKey]; diff --git a/Tests/Foundation/CPKeyValueCodingTest.j b/Tests/Foundation/CPKeyValueCodingTest.j index f750857a1..ac57d9f02 100644 --- a/Tests/Foundation/CPKeyValueCodingTest.j +++ b/Tests/Foundation/CPKeyValueCodingTest.j @@ -489,6 +489,51 @@ var accessIVARS = YES; @end +// CPValue unwrapping (AKA Wrapping and Unwrapping Structs) + +@implementation CPKeyValueCodingTest (CPValueUnwrapping) + +- (void)testIfCPValueIsUnwrapped +{ + [KVCTestClass setAccessInstanceVariablesDirectly: YES]; + + var values = @[ + [CPValue valueWithJSObject:CGPointMake(200, -100)], + [CPValue valueWithJSObject:CGSizeMake(100, 100)], + [CPValue valueWithJSObject:CGRectMake(100, 100, 50, 150)], + ]; + + for (var i = 0; i < values.length; i++) + { + var value = values[i]; + + [kvcTestObject setValue:value forKey:"privatePropertyWithoutAccessors"]; + [kvcTestObject setValue:value forKey:"publicPropertyWithoutAccessors"]; + [kvcTestObject setValue:value forKey:"privateBoolPropertyWithoutAccessors"]; + [kvcTestObject setValue:value forKey:"publicBoolPropertyWithoutAccessors"]; + [kvcTestObject setValue:value forKey:"propertyWithPublicAccessor"]; + [kvcTestObject setValue:value forKey:"propertyWithPrivateAccessor"]; + + var allKeys = ["privatePropertyWithoutAccessors","publicPropertyWithoutAccessors", + "privateBoolPropertyWithoutAccessors","publicBoolPropertyWithoutAccessors", + "propertyWithPublicAccessor", "propertyWithPrivateAccessor" + ], + dictForKeys = [kvcTestObject dictionaryWithValuesForKeys:allKeys], + key, + readBackValue, + keyEnumerator = [dictForKeys keyEnumerator]; + + while ((key = [keyEnumerator nextObject]) !== nil) + { + readBackValue = [dictForKeys objectForKey:key]; + [self assertFalse:readBackValue.isa message:"Expected to read back an unwrapped value, not " + readBackValue + "."]; + [self assert:JSON.stringify([value JSObject]) equals:JSON.stringify(readBackValue)]; + } + } +} + +@end + @implementation Employee2 : CPObject { CPString _name @accessors(property=name);