Skip to content

Commit

Permalink
Merge pull request #14 from aryaxt/AllowMultipleInstanceProviders
Browse files Browse the repository at this point in the history
Version 1.4
  • Loading branch information
aryaxt committed Feb 14, 2015
2 parents aa99427 + ec21b6d commit 05cbc1d
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 22 deletions.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>classNames</key>
<dict>
<key>ObjectMapperTests</key>
<dict>
<key>testPerformance</key>
<dict>
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
<dict>
<key>baselineAverage</key>
<real>0.01</real>
<key>baselineIntegrationDisplayName</key>
<string>Local Baseline</string>
</dict>
</dict>
</dict>
</dict>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,37 @@
<string>com.apple.platform.iphonesimulator</string>
</dict>
</dict>
<key>BC3A5B12-DE29-448A-856D-62B5380399B4</key>
<dict>
<key>localComputer</key>
<dict>
<key>busSpeedInMHz</key>
<integer>100</integer>
<key>cpuCount</key>
<integer>1</integer>
<key>cpuKind</key>
<string>Intel Core i7</string>
<key>cpuSpeedInMHz</key>
<integer>2200</integer>
<key>logicalCPUCoresPerPackage</key>
<integer>8</integer>
<key>modelCode</key>
<string>MacBookPro11,2</string>
<key>physicalCPUCoresPerPackage</key>
<integer>4</integer>
<key>platformIdentifier</key>
<string>com.apple.platform.macosx</string>
</dict>
<key>targetArchitecture</key>
<string>x86_64</string>
<key>targetDevice</key>
<dict>
<key>modelCode</key>
<string>iPhone7,2</string>
<key>platformIdentifier</key>
<string>com.apple.platform.iphonesimulator</string>
</dict>
</dict>
</dict>
</dict>
</plist>
2 changes: 0 additions & 2 deletions OCMapper/Sample/Service Layer/OCMapperConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ @implementation OCMapperConfig

+ (void)configure
{
ObjectInstanceProvider *instanceProvider = [[ObjectInstanceProvider alloc] init];
InCodeMappingProvider *inCodeMappingProvider = [[InCodeMappingProvider alloc] init];
CommonLoggingProvider *commonLoggingProvider = [[CommonLoggingProvider alloc] initWithLogLevel:LogLevelInfo];

[[ObjectMapper sharedInstance] setInstanceProvider:instanceProvider];
[[ObjectMapper sharedInstance] setMappingProvider:inCodeMappingProvider];
[[ObjectMapper sharedInstance] setLoggingProvider:commonLoggingProvider];

Expand Down
1 change: 1 addition & 0 deletions OCMapper/Source/Instance Provider/InstanceProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

@protocol InstanceProvider <NSObject>

- (BOOL)canHandleClass:(Class)class;
- (id)emptyInstanceForClass:(Class)class;
- (id)emptyCollectionInstance;
- (id)upsertObject:(NSObject *)object error:(NSError **)error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ - (id)init

#pragma mark - Public Methods -

- (BOOL)canHandleClass:(Class)class
{
return ([class isSubclassOfClass:NSManagedObject.class]) ? YES : NO;
}

- (void)setUniqueKeys:(NSArray *)keys forClass:(Class)class withUpsertMode:(UpsertMode)upsertMode
{
for (id key in keys)
Expand Down
10 changes: 10 additions & 0 deletions OCMapper/Source/Instance Provider/ObjectInstanceProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ - (id)init

#pragma mark - InstanceProvider Methods -

- (BOOL)canHandleClass:(Class)class
{
static Class managedObjectClass = nil;

if (!managedObjectClass)
managedObjectClass = NSClassFromString(@"NSManagedObject");

return ([class isSubclassOfClass:managedObjectClass]) ? NO : YES;
}

- (id)emptyInstanceForClass:(Class)class
{
return [[class alloc] init];
Expand Down
10 changes: 4 additions & 6 deletions OCMapper/Source/ObjectMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,19 @@
// THE SOFTWARE.

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "ObjectMappingInfo.h"
#import "InstanceProvider.h"
#import "MappingProvider.h"
#import "LoggingProvider.h"

@protocol MappingProvider, LoggingProvider, InstanceProvider;

@interface ObjectMapper : NSObject

@property (nonatomic, strong) NSDateFormatter *defaultDateFormatter;
@property (nonatomic, strong) id <InstanceProvider> instanceProvider;
@property (nonatomic, strong) id <MappingProvider> mappingProvider;
@property (nonatomic, strong) id <LoggingProvider> loggingProvider;
@property (nonatomic, assign) BOOL normalizeDictionary;

+ (ObjectMapper *)sharedInstance;
- (id)objectFromSource:(id)source toInstanceOfClass:(Class)class;
- (id)dictionaryFromObject:(NSObject *)object;
- (void)addInstanceProvider:(id <InstanceProvider>)instanceProvider;

@end
44 changes: 35 additions & 9 deletions OCMapper/Source/ObjectMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
// THE SOFTWARE.

#import "ObjectMapper.h"
#import <objc/runtime.h>
#import "ObjectMappingInfo.h"
#import "InstanceProvider.h"
#import "MappingProvider.h"
#import "LoggingProvider.h"
#import "ObjectInstanceProvider.h"

#ifdef DEBUG
#define ILog(format, ...) [self.loggingProvider log:[NSString stringWithFormat:(format), ##__VA_ARGS__] withLevel:LogLevelInfo]
Expand All @@ -42,6 +48,7 @@ @interface ObjectMapper()
@property (nonatomic, strong) NSMutableArray *classNamesInMainBundle;
@property (nonatomic, strong) NSMutableDictionary *mappedClassNames;
@property (nonatomic, strong) NSMutableDictionary *mappedPropertyNames;
@property (nonatomic, strong) NSMutableArray *instanceProviders;
@end

@implementation ObjectMapper
Expand All @@ -66,6 +73,10 @@ - (id)init
{
[self populateClassNamesFromMainBundle];

self.instanceProviders = [NSMutableArray array];
ObjectInstanceProvider *objectInstanceProvider = [[ObjectInstanceProvider alloc] init];
[self addInstanceProvider:objectInstanceProvider];

self.mappedClassNames = [NSMutableDictionary dictionary];
self.mappedPropertyNames = [NSMutableDictionary dictionary];
}
Expand All @@ -80,9 +91,6 @@ - (id)objectFromSource:(id)source toInstanceOfClass:(Class)class
if (!_mappingProvider)
@throw ([NSException exceptionWithName:@"MissingMappingProvider" reason:@"Mapping provider is not set" userInfo:nil]);

if (!_instanceProvider)
@throw ([NSException exceptionWithName:@"MissingInstanceProvider" reason:@"Instance provider is not set" userInfo:nil]);

if ([source isKindOfClass:[NSDictionary class]])
{
ILog(@"____________________ Mapping Dictionary to instance [%@] ____________________", NSStringFromClass(class));
Expand Down Expand Up @@ -112,6 +120,11 @@ - (id)dictionaryFromObject:(NSObject *)object
}
}

- (void)addInstanceProvider:(id <InstanceProvider>)instanceProvider
{
[self.instanceProviders addObject:instanceProvider];
}

#pragma mark - Private Methods -

- (void)populateClassNamesFromMainBundle
Expand Down Expand Up @@ -259,9 +272,10 @@ - (NSDictionary *)normalizedDictionaryFromDictionary:(NSDictionary *)source forC

- (id)processDictionary:(NSDictionary *)source forClass:(Class)class
{
NSDictionary *normalizedSource = [self normalizedDictionaryFromDictionary:source forClass:class];
NSDictionary *normalizedSource = (self.normalizeDictionary) ? [self normalizedDictionaryFromDictionary:source forClass:class] : source;

id object = [self.instanceProvider emptyInstanceForClass:class];
id <InstanceProvider> instanceProvider = [self instanceProviderForClass:class];
id object = [instanceProvider emptyInstanceForClass:class];

for (NSString *key in normalizedSource)
{
Expand All @@ -276,13 +290,13 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class

if (mappingInfo)
{
propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey];
propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:mappingInfo.propertyKey];
objectType = mappingInfo.objectType;
mappingTransformer = mappingInfo.transformer;
}
else
{
propertyName = [self.instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key];
propertyName = [instanceProvider propertyNameForObject:object byCaseInsensitivePropertyName:key];

if (propertyName && ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]))
{
Expand Down Expand Up @@ -350,7 +364,7 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
}

NSError *error;
object = [self.instanceProvider upsertObject:object error:&error];
object = [instanceProvider upsertObject:object error:&error];

if (error)
ELog(@"Attempt to update existing instance failed with error '%@' for class (%@) and object %@",
Expand All @@ -361,9 +375,21 @@ - (id)processDictionary:(NSDictionary *)source forClass:(Class)class
return object;
}

- (id <InstanceProvider>)instanceProviderForClass:(Class)class
{
for (id<InstanceProvider> instanceProvider in self.instanceProviders)
{
if ([instanceProvider canHandleClass:class])
return instanceProvider;
}

return nil;
}

- (id)processArray:(NSArray *)value forClass:(Class)class
{
id collection = [self.instanceProvider emptyCollectionInstance];
id <InstanceProvider> instanceProvider = [self instanceProviderForClass:class];
id collection = [instanceProvider emptyCollectionInstance];

for (id objectInArray in value)
{
Expand Down
13 changes: 12 additions & 1 deletion OCMapperTests/ManagedObjectMapperTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
// THE SOFTWARE.

#import "ManagedObjectMapperTest.h"
#import "User.h"
#import "CDUser.h"
#import "CDAddress.h"
#import "CDPost.h"
Expand All @@ -47,7 +48,7 @@ - (void)setUp

self.mapper = [[ObjectMapper alloc] init];
self.mapper.mappingProvider = self.mappingProvider;
self.mapper.instanceProvider = self.instanceProvider;
[self.mapper addInstanceProvider:self.instanceProvider];
}

- (void)tearDown
Expand Down Expand Up @@ -404,4 +405,14 @@ - (void)testNumberOfCreatedManagedObjectsOnNonUpdateForUpsertModePurgeExisting
XCTAssertTrue(addresses.count == 2, @"Did Not update existing ManagedObject");
}

- (void)testManagedObjectInstanceProviderShouldReturnFalseForNSObjectSubclasses
{
XCTAssertFalse([self.instanceProvider canHandleClass:User.class]);
}

- (void)testManagedObjectInstanceProviderShouldReturnTrueForNSManagedObjectSubclasses
{
XCTAssertTrue([self.instanceProvider canHandleClass:CDUser.class]);
}

@end
22 changes: 18 additions & 4 deletions OCMapperTests/ObjectMapperTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#import "ObjectMapperTests.h"
#import "ObjectMapper.h"
#import "User.h"
#import "CDUser.h"
#import "Comment.h"
#import "SpecialUser.h"

Expand All @@ -47,7 +48,6 @@ - (void)setUp

self.mapper = [[ObjectMapper alloc] init];
self.mapper.mappingProvider = self.mappingProvider;
self.mapper.instanceProvider = self.instanceProvider;
}

- (void)tearDown
Expand Down Expand Up @@ -361,6 +361,7 @@ - (void)testFlatDataToComplexObjectConversion

[self.mappingProvider mapFromDictionaryKey:@"city" toPropertyKey:@"address.city" forClass:[User class]];
[self.mappingProvider mapFromDictionaryKey:@"country" toPropertyKey:@"address.country" forClass:[User class]];
self.mapper.normalizeDictionary = YES;

User *user = [self.mapper objectFromSource:userDictionary toInstanceOfClass:[User class]];
XCTAssertTrue([[userDictionary objectForKey:@"firstName"] isEqual:user.firstName], @"Did not populate dictionary correctly");
Expand Down Expand Up @@ -415,7 +416,8 @@ - (void)testShouldPopulateDictionaryWithPropertyInSuperClass
XCTAssertTrue([user.power isEqual:[dictionary objectForKey:@"power"]], @"Did Not populate dictionary properly");
}

- (void)testInverseMappingShouldMapKeysWithCorrectName {
- (void)testInverseMappingShouldMapKeysWithCorrectName
{
User *user = [[User alloc] init];
user.firstName = @"Aryan";
user.address = [[Address alloc] init];
Expand All @@ -435,19 +437,31 @@ - (void)testInverseMappingShouldMapKeysWithCorrectName {
XCTAssertTrue([[dictionary[@"location"] objectForKey:@"ct"] isEqualToString:user.address.city]);
}

- (void)testShouldAutomaticallyGenerateInverseMapping {
- (void)testShouldAutomaticallyGenerateInverseMapping
{
[self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]];
ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"];

XCTAssertTrue([info.dictionaryKey isEqualToString:@"dateOfBirth"]);
}

- (void)testShouldNotAutomaticallyGenerateInverseMapping {
- (void)testShouldNotAutomaticallyGenerateInverseMapping
{
self.mappingProvider.automaticallyGenerateInverseMapping = NO;
[self.mappingProvider mapFromDictionaryKey:@"dateOfBirth" toPropertyKey:@"dob" forClass:[User class]];
ObjectMappingInfo *info = [self.mappingProvider mappingInfoForClass:[User class] andPropertyKey:@"dob"];

XCTAssertNil(info);
}

- (void)testObjectInstanceProviderShouldReturnTrueForNSObjectSubclasses
{
XCTAssertTrue([self.instanceProvider canHandleClass:User.class]);
}

- (void)testObjectInstanceProviderShouldReturnFalseForNSManagedObjectSubclasses
{
XCTAssertFalse([self.instanceProvider canHandleClass:CDUser.class]);
}

@end

0 comments on commit 05cbc1d

Please sign in to comment.