Skip to content

Commit

Permalink
Preliminary Core Data Support
Browse files Browse the repository at this point in the history
No consideration has, yet, been given to:
	- threading
	- relationships (sets, etc)
  • Loading branch information
DougRussell-BR committed Sep 17, 2011
1 parent fe1878b commit 60c811a
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 169 deletions.
7 changes: 2 additions & 5 deletions ESObjectMap/ESBaseModelObject.h
Expand Up @@ -18,15 +18,12 @@
//

#import <Foundation/Foundation.h>
#import "NSObject+PropertyDictionary.h"
#import "ESObjectMap.h"
#import "ESObjectProtocol.h"

@interface ESBaseModelObject : NSObject
@interface ESBaseModelObject : NSObject <ESObject>

+ (ESObjectMap *)objectMap;
+ (id)newWithDictionary:(NSDictionary *)dictionary;
- (id)initWithDictionary:(NSDictionary *)dictionary;
- (void)configureWithDictionary:(NSDictionary *)dictionary;
- (NSDictionary *)dictionaryRepresentation;

@end
166 changes: 2 additions & 164 deletions ESObjectMap/ESBaseModelObject.m
Expand Up @@ -45,174 +45,12 @@ - (id)initWithDictionary:(NSDictionary *)dictionary

- (void)configureWithDictionary:(NSDictionary *)dictionary
{
NSDictionary *propertyDictionary = [[self class] propertyDictionary];
ESObjectMap *objectMap = [[self class] objectMap];
for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues])
{
@autoreleasepool {
NSString *inputKey;
NSString *outputKey;
id dictionaryValue;
id propertyValue;

outputKey = attributes.name;
if (outputKey == nil)
continue;
// Get the property map, if it exists
ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey];
if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey
inputKey = outputKey;
else // If there is a property map, get the input key
inputKey = propertyMap.inputKey;
// Grab our value from the input dictionary
dictionaryValue = [dictionary objectForKey:inputKey];
if (dictionaryValue == nil)
continue;
// At this point we have a value to work with, so let's make sure we can actually set it
if (attributes.readOnly)
[NSException raise:@"Readonly Exception" format:@"Attempted to set a readonly property: %@", attributes];
switch (attributes.storageType) {
case IDType:
// If there's a transform block, execute it
if (propertyMap.transformBlock)
propertyValue = propertyMap.transformBlock(dictionaryValue);
else
propertyValue = dictionaryValue;
if (propertyValue == nil)
continue;
[self setValue:propertyValue forKey:outputKey];
break;
case ObjectType:
// If there's a transform block, execute it
if (propertyMap.transformBlock)
propertyValue = propertyMap.transformBlock(dictionaryValue);
else
propertyValue = dictionaryValue;
if (propertyValue == nil)
continue;
Class class = NSClassFromString(attributes.classString);
if (class && ![propertyValue isKindOfClass:class])
[NSException raise:@"Class Mismatch" format:@"Object: %@ is not kind of class: %@", propertyValue, NSStringFromClass(class)];
[self setValue:propertyValue forKey:outputKey];
break;
case IntType:
{
int intPropertyValue = 0;
// If there's a transform block, execute it
if (((ESIntPropertyMap *)propertyMap).intTransformBlock)
intPropertyValue = ((ESIntPropertyMap *)propertyMap).intTransformBlock(dictionaryValue);
else
intPropertyValue = [dictionaryValue intValue];
SetPrimitivePropertyValue(self, attributes.setter, &intPropertyValue);
break;
}
case DoubleType:
{
double doublePropertyValue = 0.0;
// If there's a transform block, execute it
if (((ESDoublePropertyMap *)propertyMap).doubleTransformBlock)
doublePropertyValue = ((ESDoublePropertyMap *)propertyMap).doubleTransformBlock(dictionaryValue);
else
doublePropertyValue = [dictionaryValue doubleValue];
SetPrimitivePropertyValue(self, attributes.setter, &doublePropertyValue);
break;
}
case FloatType:
{
float floatPropertyValue = 0.0f;
// If there's a transform block, execute it
if (((ESFloatPropertyMap *)propertyMap).floatTransformBlock)
floatPropertyValue = ((ESFloatPropertyMap *)propertyMap).floatTransformBlock(dictionaryValue);
else
floatPropertyValue = [dictionaryValue floatValue];
SetPrimitivePropertyValue(self, attributes.setter, &floatPropertyValue);
break;
}
case BoolType:
{
BOOL boolPropertyValue = NO;
// If there's a transform block, execute it
if (((ESBOOLPropertyMap *)propertyMap).boolTransformBlock)
boolPropertyValue = ((ESBOOLPropertyMap *)propertyMap).boolTransformBlock(dictionaryValue);
else
boolPropertyValue = [dictionaryValue boolValue];
SetPrimitivePropertyValue(self, attributes.setter, &boolPropertyValue);
break;
}
default:
break;
}
}
}
ConfigureObjectWithDictionary(self, dictionary);
}

- (NSDictionary *)dictionaryRepresentation
{
NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary new];
NSDictionary *propertyDictionary = [[self class] propertyDictionary];
ESObjectMap *objectMap = [[self class] objectMap];
for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues])
{
@autoreleasepool {
NSString *inputKey;
NSString *outputKey;
id dictionaryValue;
id propertyValue;

outputKey = attributes.name;
if (outputKey == nil)
continue;
// Get the property map, if it exists
ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey];
if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey
inputKey = outputKey;
else // If there is a property map, get the input key
inputKey = propertyMap.inputKey;
switch (attributes.storageType) {
case IDType:
case ObjectType:
propertyValue = [self valueForKey:outputKey];
if (propertyMap.inverseTransformBlock)
dictionaryValue = propertyMap.inverseTransformBlock(propertyValue);
else
dictionaryValue = propertyValue;
break;
case IntType:
{
int result;
GetPrimitivePropertyValue(self, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithInt:result];
break;
}
case DoubleType:
{
double result;
GetPrimitivePropertyValue(self, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithDouble:result];
break;
}
case FloatType:
{
float result;
GetPrimitivePropertyValue(self, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithFloat:result];
break;
}
case BoolType:
{
BOOL result;
GetPrimitivePropertyValue(self, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithBool:result];
break;
}
default:
break;
}
if (dictionaryValue)
[dictionaryRepresentation setObject:dictionaryValue forKey:inputKey];
}
}
return dictionaryRepresentation;
return GetDictionaryRepresentation(self);
}

@end
3 changes: 3 additions & 0 deletions ESObjectMap/ESObjectMapFunctions.h
Expand Up @@ -19,7 +19,10 @@

#import <Foundation/Foundation.h>
#import "ESObjectMap.h"
#import "ESObjectProtocol.h"

void ConfigureObjectWithDictionary(id<ESObject> object, NSDictionary *dictionary);
NSDictionary * GetDictionaryRepresentation(id<ESObject> object);
ESObjectMap * GetObjectMapForClass(Class objectClass);
void GetPrimitivePropertyValue(id object, SEL getter, void * value);
void SetPrimitivePropertyValue(id object, SEL setter, void * value);
173 changes: 173 additions & 0 deletions ESObjectMap/ESObjectMapFunctions.m
Expand Up @@ -20,6 +20,179 @@
#import "ESObjectMapFunctions.h"
#import "ESMutableDictionary.h"
#import <objc/runtime.h>
#import "NSObject+PropertyDictionary.h"

void ConfigureObjectWithDictionary(id<ESObject> object, NSDictionary *dictionary)
{
NSDictionary *propertyDictionary = [[object class] propertyDictionary];
ESObjectMap *objectMap = [[object class] objectMap];
for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues])
{
@autoreleasepool {
NSString *inputKey;
NSString *outputKey;
id dictionaryValue;
id propertyValue;

outputKey = attributes.name;
if (outputKey == nil)
continue;
// Get the property map, if it exists
ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey];
if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey
inputKey = outputKey;
else // If there is a property map, get the input key
inputKey = propertyMap.inputKey;
// Grab our value from the input dictionary
dictionaryValue = [dictionary objectForKey:inputKey];
if (dictionaryValue == nil)
continue;
// At this point we have a value to work with, so let's make sure we can actually set it
if (attributes.readOnly)
[NSException raise:@"Readonly Exception" format:@"Attempted to set a readonly property: %@", attributes];
switch (attributes.storageType) {
case IDType:
// If there's a transform block, execute it
if (propertyMap.transformBlock)
propertyValue = propertyMap.transformBlock(dictionaryValue);
else
propertyValue = dictionaryValue;
if (propertyValue == nil)
continue;
[object setValue:propertyValue forKey:outputKey];
break;
case ObjectType:
// If there's a transform block, execute it
if (propertyMap.transformBlock)
propertyValue = propertyMap.transformBlock(dictionaryValue);
else
propertyValue = dictionaryValue;
if (propertyValue == nil)
continue;
Class class = NSClassFromString(attributes.classString);
if (![propertyValue isKindOfClass:class])
[NSException raise:@"Class Mismatch" format:@"Object: %@ is not kind of class: %@", propertyValue, NSStringFromClass(class)];
[object setValue:propertyValue forKey:outputKey];
break;
case IntType:
{
int intPropertyValue = 0;
// If there's a transform block, execute it
if (((ESIntPropertyMap *)propertyMap).intTransformBlock)
intPropertyValue = ((ESIntPropertyMap *)propertyMap).intTransformBlock(dictionaryValue);
else
intPropertyValue = [dictionaryValue intValue];
SetPrimitivePropertyValue(object, attributes.setter, &intPropertyValue);
break;
}
case DoubleType:
{
double doublePropertyValue = 0.0;
// If there's a transform block, execute it
if (((ESDoublePropertyMap *)propertyMap).doubleTransformBlock)
doublePropertyValue = ((ESDoublePropertyMap *)propertyMap).doubleTransformBlock(dictionaryValue);
else
doublePropertyValue = [dictionaryValue doubleValue];
SetPrimitivePropertyValue(object, attributes.setter, &doublePropertyValue);
break;
}
case FloatType:
{
float floatPropertyValue = 0.0f;
// If there's a transform block, execute it
if (((ESFloatPropertyMap *)propertyMap).floatTransformBlock)
floatPropertyValue = ((ESFloatPropertyMap *)propertyMap).floatTransformBlock(dictionaryValue);
else
floatPropertyValue = [dictionaryValue floatValue];
SetPrimitivePropertyValue(object, attributes.setter, &floatPropertyValue);
break;
}
case BoolType:
{
BOOL boolPropertyValue = NO;
// If there's a transform block, execute it
if (((ESBOOLPropertyMap *)propertyMap).boolTransformBlock)
boolPropertyValue = ((ESBOOLPropertyMap *)propertyMap).boolTransformBlock(dictionaryValue);
else
boolPropertyValue = [dictionaryValue boolValue];
SetPrimitivePropertyValue(object, attributes.setter, &boolPropertyValue);
break;
}
default:
break;
}
}
}
}

NSDictionary * GetDictionaryRepresentation(id<ESObject> object)
{
NSMutableDictionary *dictionaryRepresentation = [NSMutableDictionary new];
NSDictionary *propertyDictionary = [[object class] propertyDictionary];
ESObjectMap *objectMap = [[object class] objectMap];
for (ESDeclaredPropertyAttributes *attributes in [propertyDictionary allValues])
{
@autoreleasepool {
NSString *inputKey;
NSString *outputKey;
id dictionaryValue;
id propertyValue;

outputKey = attributes.name;
if (outputKey == nil)
continue;
// Get the property map, if it exists
ESPropertyMap *propertyMap = [objectMap propertyMapForOutputKey:outputKey];
if (propertyMap == nil) // If there's no property map, then assume inputKey simply maps to outputKey
inputKey = outputKey;
else // If there is a property map, get the input key
inputKey = propertyMap.inputKey;
switch (attributes.storageType) {
case IDType:
case ObjectType:
propertyValue = [object valueForKey:outputKey];
if (propertyMap.inverseTransformBlock)
dictionaryValue = propertyMap.inverseTransformBlock(propertyValue);
else
dictionaryValue = propertyValue;
break;
case IntType:
{
int result;
GetPrimitivePropertyValue(object, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithInt:result];
break;
}
case DoubleType:
{
double result;
GetPrimitivePropertyValue(object, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithDouble:result];
break;
}
case FloatType:
{
float result;
GetPrimitivePropertyValue(object, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithFloat:result];
break;
}
case BoolType:
{
BOOL result;
GetPrimitivePropertyValue(object, attributes.getter, &result);
dictionaryValue = [NSNumber numberWithBool:result];
break;
}
default:
break;
}
if (dictionaryValue)
[dictionaryRepresentation setObject:dictionaryValue forKey:inputKey];
}
}
return dictionaryRepresentation;
}

static ESMutableDictionary *_objectMapCache;

Expand Down

0 comments on commit 60c811a

Please sign in to comment.