diff --git a/Sculptour.xcodeproj/project.pbxproj b/Sculptour.xcodeproj/project.pbxproj index 00d67a5..e080136 100644 --- a/Sculptour.xcodeproj/project.pbxproj +++ b/Sculptour.xcodeproj/project.pbxproj @@ -112,13 +112,16 @@ 22A5640B158D298600A2AB3E /* 54.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E7158D1C8400A2AB3E /* 54.jpg */; }; 22A5640C158D298600A2AB3E /* 67.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E8158D1C8400A2AB3E /* 67.jpg */; }; 22A5640D158D298600A2AB3E /* 73.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E9158D1C8400A2AB3E /* 73.jpg */; }; + 22A56426158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; }; + 22A56427158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; }; + 22A56428158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; }; + 22A5642B158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; }; + 22A5642C158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; }; + 22A5642D158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; }; 22A59A6A158CDD37007D2FA1 /* CMJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */; }; 22A59A6B158CDD37007D2FA1 /* CMJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */; }; 22A59A6D158CE295007D2FA1 /* harlow.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A6C158CE295007D2FA1 /* harlow.json */; }; 22A59A6E158CE295007D2FA1 /* harlow.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A6C158CE295007D2FA1 /* harlow.json */; }; - 22A59A71158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; }; - 22A59A72158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; }; - 22A59A73158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; }; 22A59A80158CE7E9007D2FA1 /* TestJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A7F158CE7E9007D2FA1 /* TestJsonIngest.m */; }; 22A59A82158CE8D9007D2FA1 /* TestJson.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A81158CE8D9007D2FA1 /* TestJson.json */; }; 22A59AA2158CEDA3007D2FA1 /* CMAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59AA1158CEDA3007D2FA1 /* CMAppDelegate.m */; }; @@ -319,11 +322,13 @@ 22A563E7158D1C8400A2AB3E /* 54.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 54.jpg; sourceTree = ""; }; 22A563E8158D1C8400A2AB3E /* 67.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 67.jpg; sourceTree = ""; }; 22A563E9158D1C8400A2AB3E /* 73.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 73.jpg; sourceTree = ""; }; + 22A56424158D40A600A2AB3E /* Tag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tag.h; sourceTree = ""; }; + 22A56425158D40A700A2AB3E /* Tag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Tag.m; sourceTree = ""; }; + 22A56429158D40A700A2AB3E /* Work.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Work.h; sourceTree = ""; }; + 22A5642A158D40A800A2AB3E /* Work.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Work.m; sourceTree = ""; }; 22A59A68158CDD37007D2FA1 /* CMJsonIngest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMJsonIngest.h; sourceTree = ""; }; 22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CMJsonIngest.m; sourceTree = ""; }; 22A59A6C158CE295007D2FA1 /* harlow.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = harlow.json; sourceTree = ""; }; - 22A59A6F158CE69C007D2FA1 /* Work.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Work.h; sourceTree = ""; }; - 22A59A70158CE69C007D2FA1 /* Work.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Work.m; sourceTree = ""; }; 22A59A7F158CE7E9007D2FA1 /* TestJsonIngest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestJsonIngest.m; sourceTree = ""; }; 22A59A81158CE8D9007D2FA1 /* TestJson.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = TestJson.json; sourceTree = ""; }; 22A59AA0158CEDA3007D2FA1 /* CMAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMAppDelegate.h; sourceTree = ""; }; @@ -530,10 +535,12 @@ isa = PBXGroup; children = ( 22A59AA7158CF7E0007D2FA1 /* Sculptour.xcdatamodeld */, + 22A56429158D40A700A2AB3E /* Work.h */, + 22A5642A158D40A800A2AB3E /* Work.m */, + 22A56424158D40A600A2AB3E /* Tag.h */, + 22A56425158D40A700A2AB3E /* Tag.m */, 2297C730158CB82F0073492A /* Image.h */, 2297C731158CB82F0073492A /* Image.m */, - 22A59A6F158CE69C007D2FA1 /* Work.h */, - 22A59A70158CE69C007D2FA1 /* Work.m */, ); name = Models; sourceTree = ""; @@ -1160,7 +1167,6 @@ 4C5F0547158CC82A009B77C4 /* CMCollectionGridViewController.m in Sources */, 4C5F0566158CE795009B77C4 /* CMWorkGridView.m in Sources */, 22A59A6A158CDD37007D2FA1 /* CMJsonIngest.m in Sources */, - 22A59A71158CE69C007D2FA1 /* Work.m in Sources */, 22A59AA2158CEDA3007D2FA1 /* CMAppDelegate.m in Sources */, 4C6AF263158CFD99005E76FB /* CMWorkViewController_iPhone.m in Sources */, 4C6AF2A4158D162E005E76FB /* CMWorkDetailViewController_iPhone.m in Sources */, @@ -1169,6 +1175,8 @@ 4C4482AD158D25F4007CC4EC /* CMWorkCollectionViewController_iPhone.m in Sources */, 4C4482B2158D26B8007CC4EC /* CMMapViewController.m in Sources */, 4C4482B6158D28C8007CC4EC /* CMPlacemark.m in Sources */, + 22A56426158D40A700A2AB3E /* Tag.m in Sources */, + 22A5642B158D40A800A2AB3E /* Work.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1205,8 +1213,9 @@ 2297C7B0158CBAAD0073492A /* MagicalRecord+Setup.m in Sources */, 2297C7B2158CBAAD0073492A /* MagicalRecord+ShorthandSupport.m in Sources */, 2297C7B4158CBAAD0073492A /* MagicalRecord.m in Sources */, - 22A59A72158CE69C007D2FA1 /* Work.m in Sources */, 22A59AAA158CF7E0007D2FA1 /* Sculptour.xcdatamodeld in Sources */, + 22A56427158D40A700A2AB3E /* Tag.m in Sources */, + 22A5642C158D40A800A2AB3E /* Work.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1247,9 +1256,10 @@ 22B2D6B8158CC5E5004ADAEE /* CoreDataTest.m in Sources */, 22B2D773158CCF25004ADAEE /* CMDataCreater.m in Sources */, 22A59A6B158CDD37007D2FA1 /* CMJsonIngest.m in Sources */, - 22A59A73158CE69C007D2FA1 /* Work.m in Sources */, 22A59A80158CE7E9007D2FA1 /* TestJsonIngest.m in Sources */, 22A59AAB158CF7E0007D2FA1 /* Sculptour.xcdatamodeld in Sources */, + 22A56428158D40A700A2AB3E /* Tag.m in Sources */, + 22A5642D158D40A800A2AB3E /* Work.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sculptour/CMJsonIngest.m b/Sculptour/CMJsonIngest.m index eecc94b..f123b78 100644 --- a/Sculptour/CMJsonIngest.m +++ b/Sculptour/CMJsonIngest.m @@ -10,6 +10,7 @@ #import "Work.h" #import "Image.h" +#import "Tag.h" @implementation CMJsonIngest @@ -87,6 +88,30 @@ -(void)ingestJsonWithFilename:(NSString *)filename { [newWork addImagesObject:newImage]; } + + // Handle tags + NSArray *tagsArray = [theDict objectForKey:@"tags"]; + NSLog(@"tagsArray = %@", tagsArray); + + // Iterate across the tags array + for (NSDictionary *tagDict in tagsArray) { + + NSLog(@"tagDict = %@", tagDict); + NSLog(@"value = %@", [tagDict valueForKey:@"tag"]); + + // See if there's already an existing tag with this name + NSArray *tags = [Tag MR_findByAttribute:@"name" withValue:[tagDict valueForKey:@"tag"]]; + if ([tags count] == 0) { + // No tag currently exists, create a new one + Tag *newTag = [Tag MR_createEntity]; + [newTag setName:[tagDict objectForKey:@"tag"]]; + [newWork addTagsObject:newTag]; + } else { + Tag *theTag = [tags objectAtIndex:0]; + [newWork addTagsObject:theTag]; + } + + } NSString *key; for (key in theDict) { diff --git a/Sculptour/Sculptour.xcdatamodeld/Sculptour.xcdatamodel/contents b/Sculptour/Sculptour.xcdatamodeld/Sculptour.xcdatamodel/contents index 160e6ac..883d520 100644 --- a/Sculptour/Sculptour.xcdatamodeld/Sculptour.xcdatamodel/contents +++ b/Sculptour/Sculptour.xcdatamodeld/Sculptour.xcdatamodel/contents @@ -5,6 +5,10 @@ + + + + @@ -19,9 +23,11 @@ + + \ No newline at end of file diff --git a/Sculptour/Tag.h b/Sculptour/Tag.h new file mode 100644 index 0000000..8a6fe0f --- /dev/null +++ b/Sculptour/Tag.h @@ -0,0 +1,27 @@ +// +// Tag.h +// Sculptour +// +// Created by Tim Duckett on 16/06/2012. +// Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved. +// + +#import +#import + +@class Work; + +@interface Tag : NSManagedObject + +@property (nonatomic, retain) NSString * name; +@property (nonatomic, retain) NSSet *work; +@end + +@interface Tag (CoreDataGeneratedAccessors) + +- (void)addWorkObject:(Work *)value; +- (void)removeWorkObject:(Work *)value; +- (void)addWork:(NSSet *)values; +- (void)removeWork:(NSSet *)values; + +@end diff --git a/Sculptour/Tag.m b/Sculptour/Tag.m new file mode 100644 index 0000000..ed825eb --- /dev/null +++ b/Sculptour/Tag.m @@ -0,0 +1,18 @@ +// +// Tag.m +// Sculptour +// +// Created by Tim Duckett on 16/06/2012. +// Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved. +// + +#import "Tag.h" +#import "Work.h" + + +@implementation Tag + +@dynamic name; +@dynamic work; + +@end diff --git a/Sculptour/TestJson.json b/Sculptour/TestJson.json index 262c354..820c843 100644 --- a/Sculptour/TestJson.json +++ b/Sculptour/TestJson.json @@ -9,7 +9,12 @@ "size": "Size 1", "latitude": 1.23456, "longitude": 9.8765, - "image":"1" + "image":"1", + "tags": [ + { + "tag": "foo" + } + ] }, { "artist": "Artist 2", @@ -21,7 +26,8 @@ "size": "Size 2", "latitude": null, "longitude": null, - "image":"2" + "image":"2", + "tags": [] }, { "artist": "Artist 3", @@ -33,6 +39,14 @@ "size": "Size 3", "latitude": null, "longitude": null, - "image": null + "image": null, + "tags": [ + { + "tag": "bar" + }, + { + "tag": "foo" + } + ] } ] \ No newline at end of file diff --git a/Sculptour/Work.h b/Sculptour/Work.h index 7af938c..3862507 100644 --- a/Sculptour/Work.h +++ b/Sculptour/Work.h @@ -9,7 +9,7 @@ #import #import -@class Image; +@class Image, Tag; @interface Work : NSManagedObject @@ -26,6 +26,7 @@ @property (nonatomic, retain) NSString * title; @property (nonatomic, retain) NSString * url; @property (nonatomic, retain) NSSet *images; +@property (nonatomic, retain) NSSet *tags; @end @interface Work (CoreDataGeneratedAccessors) @@ -35,4 +36,9 @@ - (void)addImages:(NSSet *)values; - (void)removeImages:(NSSet *)values; +- (void)addTagsObject:(Tag *)value; +- (void)removeTagsObject:(Tag *)value; +- (void)addTags:(NSSet *)values; +- (void)removeTags:(NSSet *)values; + @end diff --git a/Sculptour/Work.m b/Sculptour/Work.m index f6a43ce..5f203cd 100644 --- a/Sculptour/Work.m +++ b/Sculptour/Work.m @@ -8,6 +8,7 @@ #import "Work.h" #import "Image.h" +#import "Tag.h" @implementation Work @@ -25,5 +26,6 @@ @implementation Work @dynamic title; @dynamic url; @dynamic images; +@dynamic tags; @end diff --git a/Tests/TestJsonIngest.m b/Tests/TestJsonIngest.m index ebc215c..3d285e0 100644 --- a/Tests/TestJsonIngest.m +++ b/Tests/TestJsonIngest.m @@ -9,6 +9,7 @@ #import #import "Work.h" #import "Image.h" +#import "Tag.h" #import "CMDataCreater.h" #import "CMJsonIngest.h" @@ -50,7 +51,7 @@ -(void)testJson { NSError *error; self.jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; - GHAssertNotNil(self.jsonArray, @"is nil, should not be nil"); + GHAssertNotNil(self.jsonArray, @"is nil: got error %@", error); int jsonArrayCount = [self.jsonArray count]; GHAssertEquals(jsonArrayCount, 3, @"expected 3 elements, got %d", jsonArrayCount); @@ -198,4 +199,91 @@ -(void)testPresenceOfImages { } +-(void)testCreationOfTags { + + CMJsonIngest *ingester = [[CMJsonIngest alloc] init]; + + [ingester ingestJsonWithFilename:@"TestJson"]; + + Work *workOne = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 1"]; + GHAssertNotNil(workOne, @"workOne was not found"); + + // Given the test JSON + // When I ingest the JSON + // Then the first work should have one tag + // And the tag name should be "foo" + + NSSet *tags = workOne.tags; + NSArray *tagsArray = [tags allObjects]; + int tagsCount = [tagsArray count]; + GHAssertEquals(tagsCount, 1, @"expected 1 tag, got %d", tagsCount); + + Tag *theTag = [tagsArray objectAtIndex:0]; + GHAssertEqualStrings(theTag.name, @"foo", @"expected tag.name = foo, got %@", theTag.name); + + // Given the test JSON + // When I ingest the JSON + // Then the second work should have no tags + + Work *workTwo = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 2"]; + GHAssertNotNil(workTwo, @"workTwo was not found"); + + NSSet *workTwoTags = workTwo.tags; + NSArray *workTwoTagsArray = [workTwoTags allObjects]; + int workTwoTagCount = [workTwoTagsArray count]; + GHAssertEquals(workTwoTagCount, 0, @"expected 0 tag, got %d", tagsCount); + + // Given the test JSON + // When I ingest the JSON + // Then the third work should have two tags + // And the first tag should be foo + // And the second tag should be bar + + Work *workThree = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 3"]; + GHAssertNotNil(workThree, @"workThree was not found"); + + NSSet *workThreeTags = workThree.tags; + NSArray *workThreeTagsArray = [workThreeTags allObjects]; + int workThreeTagCount = [workThreeTagsArray count]; + GHAssertEquals(workThreeTagCount, 2, @"expected 0 tag, got %d", tagsCount); + + NSInteger fooIndex = [workThreeTagsArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + Tag *theTag = (Tag *)obj; + return ([theTag.name isEqualToString:@"foo"]); + }]; + + GHAssertNotEquals(NSNotFound, fooIndex, @"should have found a foo tag"); + + NSInteger barIndex = [workThreeTagsArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + Tag *theTag = (Tag *)obj; + return ([theTag.name isEqualToString:@"bar"]); + }]; + + GHAssertNotEquals(NSNotFound, barIndex, @"should have found a bar tag"); + + // Given the test JSON + // When I ingest the JSON + // Then the tag "foo" should have two Works + // And the tag "bar" should have one Work + + NSArray *tagFooArray = [Tag MR_findByAttribute:@"name" withValue:@"foo"]; + int tagFooArrayCount = [tagFooArray count]; + GHAssertEquals(tagFooArrayCount, 1, @"there should be 1 tagFoo, got %d", tagFooArrayCount); + + Tag *fooTag = [tagFooArray objectAtIndex:0]; + NSSet *fooWorksSet = fooTag.work; + int fooWorksCount = [fooWorksSet count]; + GHAssertEquals(fooWorksCount, 2, @"foo should have 2 works, got %d", fooWorksCount); + + NSArray *tagBarArray = [Tag MR_findByAttribute:@"name" withValue:@"bar"]; + int tagBarArrayCount = [tagBarArray count]; + GHAssertEquals(tagBarArrayCount, 1, @"there should be 1 tagBars, got %d", tagFooArrayCount); + + Tag *barTag = [tagBarArray objectAtIndex:0]; + NSSet *barWorksSet = barTag.work; + int barWorksCount = [barWorksSet count]; + GHAssertEquals(barWorksCount, 1, @"bar should have 1 work, got %d", fooWorksCount); + +} + @end