Skip to content

Commit

Permalink
respect property types on current class that is being mapped. This be…
Browse files Browse the repository at this point in the history
…haviour is turned off by default.
  • Loading branch information
DenTelezhkin committed Jun 6, 2015
1 parent 597c3a9 commit 9bec955
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 15 deletions.
3 changes: 2 additions & 1 deletion EasyMapping/EKManagedObjectMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ - (id)fillObject:(id)object fromExternalRepresentation:(NSDictionary *)externalR
[EKPropertyHelper setProperty:obj
onObject:object
fromRepresentation:representation
inContext:self.importer.context];
inContext:self.importer.context
respectPropertyType:mapping.respectPropertyFoundationTypes];
}];
[mapping.hasOneMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping * relationship, BOOL * stop)
{
Expand Down
5 changes: 3 additions & 2 deletions EasyMapping/EKMapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ + (id)fillObject:(id)object fromExternalRepresentation:(NSDictionary *)externalR
NSDictionary *representation = [EKPropertyHelper extractRootPathFromExternalRepresentation:externalRepresentation withMapping:mapping];
[mapping.propertyMappings enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[EKPropertyHelper setProperty:obj
onObject:object
fromRepresentation:representation];
onObject:object
fromRepresentation:representation
respectPropertyType:mapping.respectPropertyFoundationTypes];
}];
[mapping.hasOneMappings enumerateKeysAndObjectsUsingBlock:^(id key, EKRelationshipMapping * valueMapping, BOOL *stop) {
NSDictionary * value = [valueMapping extractObjectFromRepresentation:representation];
Expand Down
7 changes: 7 additions & 0 deletions EasyMapping/EKObjectMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
*/
@property (nonatomic, assign) BOOL incrementalData;

/**
If set to YES, mapper will introspect your class properties and try to create appropriate objects. Supported classes: NSMutableArray, NSMutableDictionary, NSSet, NSMutableSet, NSOrderedSet, NSMutableOrderedSet.
Due to perfomance reasons, this property defaults to NO.
*/
@property (nonatomic, assign) BOOL respectPropertyFoundationTypes;

/**
Class, for which this mapping is meant to be used.
*/
Expand Down
6 changes: 4 additions & 2 deletions EasyMapping/EKPropertyHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@

+ (void) setProperty:(EKPropertyMapping *)propertyMapping
onObject:(id)object
fromRepresentation:(NSDictionary *)representation;
fromRepresentation:(NSDictionary *)representation
respectPropertyType:(BOOL)respectPropertyType;

+ (void) setProperty:(EKPropertyMapping *)propertyMapping
onObject:(id)object
fromRepresentation:(NSDictionary *)representation
inContext:(NSManagedObjectContext *)context;
inContext:(NSManagedObjectContext *)context
respectPropertyType:(BOOL)respectPropertyType;

+ (id)getValueOfProperty:(EKPropertyMapping *)propertyMapping
fromRepresentation:(NSDictionary *)representation;
Expand Down
33 changes: 23 additions & 10 deletions EasyMapping/EKPropertyHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ + (NSString *) propertyTypeStringRepresentationFromProperty:(objc_property_t)pro
return propertyType;
}

+ (id)propertyRepresentation:(NSArray *)array forObject:(id)object withPropertyName:(NSString *)propertyName
+ (id)propertyRepresentation:(id)value forObject:(id)object withPropertyName:(NSString *)propertyName
{
if (!array)
if (!value)
{
return nil;
}
Expand All @@ -73,35 +73,42 @@ + (id)propertyRepresentation:(NSArray *)array forObject:(id)object withPropertyN
{
NSString *type = [self propertyTypeStringRepresentationFromProperty:property];
if ([type isEqualToString:@"NSSet"]) {
return [NSSet setWithArray:array];
return [NSSet setWithArray:value];
}
else if ([type isEqualToString:@"NSMutableSet"]) {
return [NSMutableSet setWithArray:array];
return [NSMutableSet setWithArray:value];
}
else if ([type isEqualToString:@"NSOrderedSet"]) {
return [NSOrderedSet orderedSetWithArray:array];
return [NSOrderedSet orderedSetWithArray:value];
}
else if ([type isEqualToString:@"NSMutableOrderedSet"]) {
return [NSMutableOrderedSet orderedSetWithArray:array];
return [NSMutableOrderedSet orderedSetWithArray:value];
}
else if ([type isEqualToString:@"NSMutableArray"]) {
return [NSMutableArray arrayWithArray:array];
}
return [NSMutableArray arrayWithArray:value];
} else if ([type isEqualToString:@"NSMutableDictionary"]) {
return [NSMutableDictionary dictionaryWithDictionary:value];
}
}
return array;
return value;
}

#pragma mark Property accessor methods

+ (void)setProperty:(EKPropertyMapping *)propertyMapping onObject:(id)object
fromRepresentation:(NSDictionary *)representation
fromRepresentation:(NSDictionary *)representation respectPropertyType:(BOOL)respectPropertyType
{
id value = [self getValueOfProperty:propertyMapping fromRepresentation:representation];
if (value == (id)[NSNull null]) {
if (![self propertyNameIsScalar:propertyMapping.property fromObject:object]) {
[self setValue:nil onObject:object forKeyPath:propertyMapping.property];
}
} else if (value) {
if (respectPropertyType) {
value = [self propertyRepresentation:value
forObject:object
withPropertyName:propertyMapping.property];
}
[self setValue:value onObject:object forKeyPath:propertyMapping.property];
}
}
Expand All @@ -110,6 +117,7 @@ + (void) setProperty:(EKPropertyMapping *)propertyMapping
onObject:(id)object
fromRepresentation:(NSDictionary *)representation
inContext:(NSManagedObjectContext *)context
respectPropertyType:(BOOL)respectPropertyType
{
id value = [self getValueOfManagedProperty:propertyMapping
fromRepresentation:representation
Expand All @@ -119,6 +127,11 @@ + (void) setProperty:(EKPropertyMapping *)propertyMapping
[self setValue:nil onObject:object forKeyPath:propertyMapping.property];
}
} else if (value) {
if (respectPropertyType) {
value = [self propertyRepresentation:value
forObject:object
withPropertyName:propertyMapping.property];
}
[self setValue:value onObject:object forKeyPath:propertyMapping.property];
}
}
Expand Down
14 changes: 14 additions & 0 deletions EasyMappingExample/EasyMappingExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
9A170335194C820200682F00 /* EKRelationshipMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A170331194C820200682F00 /* EKRelationshipMapping.m */; };
9A1B2D161A9F446F00E1FACD /* EKMappingBlocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A53E2E21A7EA77300C4D169 /* EKMappingBlocks.m */; };
9A1B2D171A9F446F00E1FACD /* EKMappingBlocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A53E2E21A7EA77300C4D169 /* EKMappingBlocks.m */; };
9A2044111B23810D00AB7363 /* MutableFoundationClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2044101B23810D00AB7363 /* MutableFoundationClass.m */; };
9A2044121B23810D00AB7363 /* MutableFoundationClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2044101B23810D00AB7363 /* MutableFoundationClass.m */; };
9A2044141B23819500AB7363 /* MutableFoundationClass.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A2044131B23819500AB7363 /* MutableFoundationClass.json */; };
9A2044151B23819500AB7363 /* MutableFoundationClass.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A2044131B23819500AB7363 /* MutableFoundationClass.json */; };
9A2056A11956DF7900499FC3 /* BaseTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A01956DF7900499FC3 /* BaseTestModel.m */; };
9A2056A21956DF7900499FC3 /* BaseTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A01956DF7900499FC3 /* BaseTestModel.m */; };
9A2056A51956E0EE00499FC3 /* BaseManagedTestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2056A41956E0EE00499FC3 /* BaseManagedTestModel.m */; };
Expand Down Expand Up @@ -379,6 +383,9 @@
9A130226190BF9380060A25C /* OS X Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OS X Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
9A170330194C820200682F00 /* EKRelationshipMapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EKRelationshipMapping.h; sourceTree = "<group>"; };
9A170331194C820200682F00 /* EKRelationshipMapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EKRelationshipMapping.m; sourceTree = "<group>"; };
9A20440F1B23810D00AB7363 /* MutableFoundationClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MutableFoundationClass.h; path = Tests/Fixtures/FixtureClasses/MutableFoundationClass.h; sourceTree = "<group>"; };
9A2044101B23810D00AB7363 /* MutableFoundationClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MutableFoundationClass.m; path = Tests/Fixtures/FixtureClasses/MutableFoundationClass.m; sourceTree = "<group>"; };
9A2044131B23819500AB7363 /* MutableFoundationClass.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = MutableFoundationClass.json; path = Tests/Fixtures/MutableFoundationClass.json; sourceTree = SOURCE_ROOT; };
9A20569E1956CF7900499FC3 /* EKMappingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EKMappingProtocol.h; sourceTree = "<group>"; };
9A20569F1956DF7900499FC3 /* BaseTestModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BaseTestModel.h; path = Classes/Models/BaseTestModel.h; sourceTree = SOURCE_ROOT; };
9A2056A01956DF7900499FC3 /* BaseTestModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BaseTestModel.m; path = Classes/Models/BaseTestModel.m; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -628,6 +635,7 @@
9AA7CED2191FA7C400608262 /* ComplexRepresentation.json */,
9A210F361944B13A00871071 /* CommentsRecursive.json */,
9AC1321C1A2CA193001ED491 /* PersonsWithSamePhones.json */,
9A2044131B23819500AB7363 /* MutableFoundationClass.json */,
);
name = Fixtures;
path = EasyMappingExampleTests;
Expand Down Expand Up @@ -886,6 +894,8 @@
9A8420F8195723BE006DDDE3 /* Two.m */,
9A8420FB195723D0006DDDE3 /* Three.h */,
9A8420FC195723D0006DDDE3 /* Three.m */,
9A20440F1B23810D00AB7363 /* MutableFoundationClass.h */,
9A2044101B23810D00AB7363 /* MutableFoundationClass.m */,
);
name = FixtureClasses;
sourceTree = "<group>";
Expand Down Expand Up @@ -1252,6 +1262,7 @@
9A45121F19164705006E6022 /* Cars.json in Resources */,
9A45124719164705006E6022 /* PersonWithNullCar.json in Resources */,
9A45122B19164705006E6022 /* CarWithRoot.json in Resources */,
9A2044141B23819500AB7363 /* MutableFoundationClass.json in Resources */,
9A45124B19164705006E6022 /* PersonWithNullPhones.json in Resources */,
9A210F3A1944B81500871071 /* PersonRecursive.json in Resources */,
9A45122719164705006E6022 /* CarWithNestedAttributes.json in Resources */,
Expand Down Expand Up @@ -1285,6 +1296,7 @@
9A45124819164705006E6022 /* PersonWithNullCar.json in Resources */,
9AC0F3151A7276C6004B2096 /* PersonWithZeroPhones.json in Resources */,
9A45122C19164705006E6022 /* CarWithRoot.json in Resources */,
9A2044151B23819500AB7363 /* MutableFoundationClass.json in Resources */,
9A45124C19164705006E6022 /* PersonWithNullPhones.json in Resources */,
9A210F3B1944B81500871071 /* PersonRecursive.json in Resources */,
9A45122819164705006E6022 /* CarWithNestedAttributes.json in Resources */,
Expand Down Expand Up @@ -1551,6 +1563,7 @@
9A53E2E31A7EA77300C4D169 /* EKMappingBlocks.m in Sources */,
9A4511CC191646C9006E6022 /* Person.m in Sources */,
9A130248190BFEF30060A25C /* EKManagedObjectMapping.m in Sources */,
9A2044111B23810D00AB7363 /* MutableFoundationClass.m in Sources */,
9A45117C19164696006E6022 /* MappingProvider.m in Sources */,
9A4511AC191646C9006E6022 /* Address.m in Sources */,
9A4511F7191646F7006E6022 /* EKObjectMappingSpec.m in Sources */,
Expand Down Expand Up @@ -1588,6 +1601,7 @@
9A13024D190BFEF30060A25C /* EKMapper.m in Sources */,
9A4511FC191646F7006E6022 /* EKPropertyHelperSpec.m in Sources */,
9AA7CEC0191E555300608262 /* EKManagedObjectMapper.m in Sources */,
9A2044121B23810D00AB7363 /* MutableFoundationClass.m in Sources */,
9A8420F6195723A6006DDDE3 /* One.m in Sources */,
9A8420E9195718A2006DDDE3 /* EKManagedObjectModel.m in Sources */,
9A210F351944B10B00871071 /* CommentObject.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// MutableFoundationClass.h
// EasyMappingExample
//
// Created by Denys Telezhkin on 06.06.15.
// Copyright (c) 2015 EasyKit. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "EKObjectModel.h"

@interface MutableFoundationClass : EKObjectModel

@property (nonatomic, strong) NSMutableArray * array;
@property (nonatomic, strong) NSMutableDictionary * dictionary;
@property (nonatomic, strong) NSSet * set;
@property (nonatomic, strong) NSMutableSet * mutableSet;
@property (nonatomic, strong) NSOrderedSet * orderedSet;
@property (nonatomic, strong) NSMutableOrderedSet * mutableOrderedSet;
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// MutableFoundationClass.m
// EasyMappingExample
//
// Created by Denys Telezhkin on 06.06.15.
// Copyright (c) 2015 EasyKit. All rights reserved.
//

#import "MutableFoundationClass.h"

@implementation MutableFoundationClass

+(EKObjectMapping *)objectMapping
{
EKObjectMapping * mapping = [[EKObjectMapping alloc] initWithObjectClass:self];

[mapping mapPropertiesFromArray:@[@"array",@"dictionary", @"set"]];
[mapping mapKeyPath:@"ordered_set" toProperty:@"orderedSet"];
[mapping mapKeyPath:@"mutable_set" toProperty:@"mutableSet"];
[mapping mapKeyPath:@"mutable_ordered_set" toProperty:@"mutableOrderedSet"];
mapping.respectPropertyFoundationTypes = YES;
return mapping;
}

@end
10 changes: 10 additions & 0 deletions EasyMappingExample/Tests/Fixtures/MutableFoundationClass.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"array":[],
"dictionary": {
"foo":"bar"
},
"set":[1,2,3],
"mutable_set":["1"],
"ordered_set":["4","5"],
"mutable_ordered_set": []
}
40 changes: 40 additions & 0 deletions EasyMappingExample/Tests/Specs/EKMapperSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import "Finger.h"
#import "Cat.h"
#import "CommentObject.h"
#import "MutableFoundationClass.h"

SPEC_BEGIN(EKMapperSpec)

Expand Down Expand Up @@ -829,6 +830,45 @@
[[person.car.year should] equal:@"2013"];
});
});

describe(@"#mapKeyPath:toProperty should convert properties to mutable values, if properties are mutable", ^{

__block MutableFoundationClass * instance = nil;

beforeEach(^{

NSDictionary * externalRepresentation = [CMFixture buildUsingFixture:@"MutableFoundationClass"];
instance = [[MutableFoundationClass alloc] initWithProperties:externalRepresentation];
});

it(@"should have mutable array", ^{
[[instance.array should] beKindOfClass:[NSMutableArray class]];
});

it(@"should have mutable dictionary", ^{
[[[instance dictionary] should] beKindOfClass:[NSMutableDictionary class]];
[[theBlock(^{
instance.dictionary[@"it's really mutable"] = @"";
}) shouldNot] raise];
});

it(@"should have mutable set", ^{
[[[instance mutableSet] should] beKindOfClass:[NSMutableSet class]];
});

it(@"should have mutable ordered set", ^{
[[[instance mutableOrderedSet] should] beKindOfClass:[NSMutableOrderedSet class]];
});

it(@"should have set", ^{
[[[instance set] should] beKindOfClass:[NSSet class]];
});

it(@"should have ordered set", ^{
[[[instance orderedSet] should] beKindOfClass:[NSOrderedSet class]];
});

});
});

SPEC_END
Expand Down

0 comments on commit 9bec955

Please sign in to comment.