Permalink
Browse files

Merge pull request #68 from tyrone-sudeium/master

PONSO: NSSet-based templates, improved inverse relationship logic
  • Loading branch information...
nikita-zhuk committed Dec 1, 2011
2 parents dc55ebb + 25b700a commit 21dd19dd4a9b965e036e6d466173c8226835fb86
Showing with 3,840 additions and 12 deletions.
  1. +1 −1 contributed templates/Nikita Zhuk/ponso/code/ModelObject.h
  2. +16 −0 contributed templates/Nikita Zhuk/ponso/code/ModelObject.m
  3. +6 −2 contributed templates/Nikita Zhuk/ponso/templates/machine.h.motemplate
  4. +64 −9 contributed templates/Nikita Zhuk/ponso/templates/machine.m.motemplate
  5. +45 −0 contributed templates/Tyrone Trevorrow/ponso/README.txt
  6. +58 −0 contributed templates/Tyrone Trevorrow/ponso/code/ModelObject.h
  7. +175 −0 contributed templates/Tyrone Trevorrow/ponso/code/ModelObject.m
  8. +8 −0 ... templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/MyModel.xcdatamodeld/.xccurrentversion
  9. BIN ...Tyrone Trevorrow/ponso/sample project/PonsoTest/MyModel.xcdatamodeld/MyModel.xcdatamodel/elements
  10. BIN ...s/Tyrone Trevorrow/ponso/sample project/PonsoTest/MyModel.xcdatamodeld/MyModel.xcdatamodel/layout
  11. +345 −0 ...ted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/PonsoTest.xcodeproj/project.pbxproj
  12. +7 −0 ...w/ponso/sample project/PonsoTest/PonsoTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  13. BIN ...t.xcodeproj/project.xcworkspace/xcuserdata/t.trevorrow.xcuserdatad/UserInterfaceState.xcuserstate
  14. +84 −0 ...ect/PonsoTest/PonsoTest.xcodeproj/xcuserdata/t.trevorrow.xcuserdatad/xcschemes/PonsoTest.xcscheme
  15. +22 −0 ...nsoTest/PonsoTest.xcodeproj/xcuserdata/t.trevorrow.xcuserdatad/xcschemes/xcschememanagement.plist
  16. +8 −0 contributed templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/PonsoTest/PonsoTest-Prefix.pch
  17. +129 −0 contributed templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/PonsoTest/main.m
  18. +6 −0 contributed templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/Model.h
  19. +11 −0 ...uted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelAssistant.h
  20. +18 −0 ...uted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelAssistant.m
  21. +11 −0 ...ibuted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelCompany.h
  22. +18 −0 ...ibuted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelCompany.m
  23. +11 −0 ...ted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartment.h
  24. +18 −0 ...ted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartment.m
  25. +11 −0 ...ates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartmentAssistant.h
  26. +21 −0 ...ates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartmentAssistant.m
  27. +11 −0 ...lates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartmentEmployee.h
  28. +21 −0 ...lates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelDepartmentEmployee.m
  29. +11 −0 ...buted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelEmployee.h
  30. +20 −0 ...buted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/ModelEmployee.m
  31. +63 −0 ...ted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelAssistant.h
  32. +199 −0 ...ted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelAssistant.m
  33. +68 −0 ...buted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelCompany.h
  34. +293 −0 ...buted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelCompany.m
  35. +63 −0 ...ed templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartment.h
  36. +241 −0 ...ed templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartment.m
  37. +52 −0 ...tes/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartmentAssistant.h
  38. +152 −0 ...tes/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartmentAssistant.m
  39. +52 −0 ...ates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartmentEmployee.h
  40. +152 −0 ...ates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelDepartmentEmployee.m
  41. +67 −0 ...uted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelEmployee.h
  42. +223 −0 ...uted templates/Tyrone Trevorrow/ponso/sample project/PonsoTest/Sources/DataModel/_ModelEmployee.m
  43. +15 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/NSCoding/human.h.motemplate
  44. +45 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/NSCoding/human.m.motemplate
  45. +52 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/NSCoding/machine.h.motemplate
  46. +312 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/NSCoding/machine.m.motemplate
  47. +11 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/human.h.motemplate
  48. +24 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/human.m.motemplate
  49. +52 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/machine.h.motemplate
  50. +232 −0 contributed templates/Tyrone Trevorrow/ponso/templates/NSSet/machine.m.motemplate
  51. +11 −0 contributed templates/Tyrone Trevorrow/ponso/templates/human.h.motemplate
  52. +24 −0 contributed templates/Tyrone Trevorrow/ponso/templates/human.m.motemplate
  53. +52 −0 contributed templates/Tyrone Trevorrow/ponso/templates/machine.h.motemplate
  54. +229 −0 contributed templates/Tyrone Trevorrow/ponso/templates/machine.m.motemplate
@@ -24,7 +24,7 @@
#import <Foundation/Foundation.h>
-@interface ModelObject : NSObject <NSCopying>
+@interface ModelObject : NSObject <NSCopying, NSCoding>
{
NSDictionary *sourceDictionaryRepresentation;
}
@@ -22,6 +22,22 @@
@implementation ModelObject
+- (id) initWithCoder: (NSCoder*) aDecoder
+{
+ self = [super init];
+ if (self) {
+ // Superclass implementation:
+ // If we add ivars/properties, here's where we'll load them
+ }
+ return self;
+}
+
+- (void) encodeWithCoder: (NSCoder*) aCoder
+{
+ // Superclass implementation:
+ // If we add ivars/properties, here's where we'll save them
+}
+
+ (id)createModelObjectFromFile:(NSString *)filePath
{
if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])
@@ -11,7 +11,6 @@
#import <Foundation/Foundation.h>
#import "ModelObject.h"
<$if hasCustomSuperentity$>#import "<$customSuperentity$>.h"<$endif$>
-
<$checkNonTransientRelationshipCycles $>
<$foreach Relationship noninheritedRelationships do$>@class <$Relationship.destinationEntity.managedObjectClassName$>;
<$endforeach do$>
@@ -40,9 +39,14 @@
<$else$>@property (nonatomic, retain, readwrite) <$Relationship.destinationEntity.managedObjectClassName$> *<$Relationship.name$>;<$endif$>
<$endif$><$endforeach do$>
<$foreach Relationship noninheritedRelationships do$>
-<$if Relationship.isToMany$>- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_;
+<$if Relationship.isToMany$>- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: (BOOL) setInverse;
+- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_;
- (void)remove<$Relationship.name.initialCapitalString$>Objects;
+- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: (BOOL) setInverse;
- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_;
<$endif$><$endforeach do$>
+<$foreach Relationship noninheritedRelationships do$><$if ! Relationship.isToMany$>
+- (void) set<$Relationship.name.initialCapitalString$>: (<$Relationship.destinationEntity.managedObjectClassName$>*) <$Relationship.name$>_ settingInverse: (BOOL) setInverse;
+<$endif$><$endforeach do$>
@end
@@ -132,26 +132,80 @@
#pragma mark Direct access
<$foreach Relationship noninheritedRelationships do$><$if Relationship.isToMany$>
-- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_
+- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: (BOOL) setInverse
{
- if(self.<$Relationship.name$> == nil)
+ if(self.<$Relationship.name$> == nil)
{
+ <$if Relationship.isTransient$>
+ CFArrayCallBacks callbacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
+ self.<$Relationship.name$> = [(NSMutableArray*) CFArrayCreateMutable(0, 0, &callbacks) autorelease];
+ <$else$>
self.<$Relationship.name$> = [NSMutableArray array];
+ <$endif$>
}
[(NSMutableArray *)self.<$Relationship.name$> addObject:value_];
- <$if Relationship.inverseRelationship$><$if ! Relationship.inverseRelationship.isToMany$>value_.<$Relationship.inverseRelationship.name$> = (<$managedObjectClassName$>*)self;<$endif$><$endif$>
+ <$if Relationship.inverseRelationship$><$if ! Relationship.inverseRelationship.isToMany$>if (setInverse == YES) {
+ [value_ set<$Relationship.inverseRelationship.name.initialCapitalString$>: (<$managedObjectClassName$>*)self settingInverse: NO];
+ }<$endif$><$endif$>
+}
+- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_
+{
+ [self add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: YES];
}
- (void)remove<$Relationship.name.initialCapitalString$>Objects
{
+ <$if Relationship.isTransient$>
+ CFArrayCallBacks callbacks = {0, NULL, NULL, CFCopyDescription, CFEqual};
+ self.<$Relationship.name$> = [(NSMutableArray*) CFArrayCreateMutable(0, 0, &callbacks) autorelease];
+ <$else$>
self.<$Relationship.name$> = [NSMutableArray array];
+ <$endif$>
+}
+
+- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: (BOOL) setInverse
+{
+ <$if Relationship.inverseRelationship$><$if ! Relationship.inverseRelationship.isToMany$>if (setInverse == YES) {
+ [value_ set<$Relationship.inverseRelationship.name.initialCapitalString$>: nil settingInverse: NO];
+ }<$endif$><$endif$>
+ [(NSMutableArray *)self.<$Relationship.name$> removeObject:value_];
}
- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_
{
- <$if Relationship.inverseRelationship$><$if ! Relationship.inverseRelationship.isToMany$>value_.<$Relationship.inverseRelationship.name$> = nil;<$endif$><$endif$>
- [(NSMutableArray *)self.<$Relationship.name$> removeObject:value_];
+ [self remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ settingInverse: YES];
+}
+
+<$endif$><$endforeach do$>
+
+<$foreach Relationship noninheritedRelationships do$><$if ! Relationship.isToMany$>
+- (void) set<$Relationship.name.initialCapitalString$>: (<$Relationship.destinationEntity.managedObjectClassName$>*) <$Relationship.name$>_ settingInverse: (BOOL) setInverse
+{
+ <$if Relationship.inverseRelationship$><$if Relationship.inverseRelationship.isToMany$>if ((<$Relationship.name$>_ == nil || ![<$Relationship.name$>_ isEqual: <$Relationship.name$>]) && setInverse == YES) {
+ [<$Relationship.name$> remove<$Relationship.inverseRelationship.name.initialCapitalString$>Object: (<$managedObjectClassName$>*)self settingInverse: NO];
+ }<$else$>if (<$Relationship.name$>_ == nil && setInverse == YES) {
+ [<$Relationship.name$> set<$Relationship.inverseRelationship.name.initialCapitalString$>: nil settingInverse: NO];
+ }
+ <$endif$><$endif$><$if Relationship.isTransient$><$Relationship.name$> = <$Relationship.name$>_;<$else$>if (<$Relationship.name$> != <$Relationship.name$>_) {
+ [<$Relationship.name$> release];
+ <$Relationship.name$> = [<$Relationship.name$>_ retain];
+ }<$endif$>
+ <$if Relationship.inverseRelationship$><$if Relationship.inverseRelationship.isToMany$>if (setInverse == YES) {
+ [<$Relationship.name$> add<$Relationship.inverseRelationship.name.initialCapitalString$>Object: (<$managedObjectClassName$>*)self settingInverse: NO];
+ }<$else$>if (setInverse == YES) {
+ [<$Relationship.name$> set<$Relationship.inverseRelationship.name.initialCapitalString$>: (<$managedObjectClassName$>*)self settingInverse: NO];
+ }<$endif$><$endif$>
+}
+
+- (void) set<$Relationship.name.initialCapitalString$>: (<$Relationship.destinationEntity.managedObjectClassName$>*) <$Relationship.name$>_
+{
+ [self set<$Relationship.name.initialCapitalString$>: <$Relationship.name$>_ settingInverse: YES];
+}
+
+- (<$Relationship.destinationEntity.managedObjectClassName$>*) <$Relationship.name$>
+{
+ return <$Relationship.name$>;
}
<$endif$><$endforeach do$>
@@ -160,15 +214,16 @@
{
<$foreach Attribute noninheritedAttributes do$><$if Attribute.hasDefinedAttributeType$>self.<$Attribute.name$> = nil;
<$endif$><$endforeach do$>
- <$foreach Relationship noninheritedRelationships do$>self.<$Relationship.name$> = nil;
- <$endforeach do$>
+ <$foreach Relationship noninheritedRelationships do$><$if ! Relationship.isTransient$>self.<$Relationship.name$> = nil;
+ <$endif$><$endforeach do$>
[super dealloc];
}
#pragma mark Synthesizes
<$foreach Attribute noninheritedAttributes do$>@synthesize <$Attribute.name$>;
<$endforeach do$>
-<$foreach Relationship noninheritedRelationships do$>@synthesize <$Relationship.name$>;
-<$endforeach do$>
+<$foreach Relationship noninheritedRelationships do$><$if Relationship.isToMany$>@synthesize <$Relationship.name$>;
+<$endif$><$endforeach do$>
+
@end
@@ -0,0 +1,45 @@
+PONSO - Plain Old NSObjects
+===========================
+
+What is PONSO?
+--------------
+The idea is to use mogenerator to generate lightweight, memory-only, type-safe ObjC data model classes from Xcode data models.
+
+Features
+--------
+- Type-safe attributes
+- Supports one-to-one and one-to-many relationships
+- Relationships are always ordered - implemented with NSArrays
+- Supports inverse relationships, which should be always marked as 'transient'
+- Supports serialization of any model object to NSDictionary and initialization from NSDictionary
+- Supports writing and reading to binary property list files
+- Requires that data model is a tree, where nodes are entities and edges are strong, non-transient relationships. Does not work with graph data models.
+- Supports weak relationships which are not archived in serialized form. These relationships are not considered as part of the object graph tree, e.g. you can have strong relationships A -> B, A -> C and a weak relationship B -> C and this won't invalidate the "tree model" requirement.
+- To create a weak relationship, add "destinationEntityIDKeyPath" user info key to that relationship in Xcode data modeller, and specify the name of attribute which can be used as unique ID to find the destination object. See sample projects entities DepartmentAssistant and DepartmentEmployee for examples.
+- Cycles between weak relationships are found automatically and are warned about during code generation.
+
+
+How to use
+----------
+- The only additional source code you need to compile into your application for PONSO is ModelObject class found in "contributed templates/Nikita Zhuk/ponso/code"
+- See "contributed templates/Nikita Zhuk/ponso/sample project/PonsoTest" project for sample setup
+
+
+TODO
+-----
+PONSO is a work in progress and can be enchanced in a various ways.
+
+Some missing features include:
+- Automatic setting of inverse one-to-one relationships in setters
+- Support for many-to-many relationships
+- Implementations of to-many relationships as ordered sets instead of arrays
+- Detection of retain cycles caused by both relationship directions being non-transient
+
+Feel free to fork & contribute.
+
+
+Contact info
+-------------
+Nikita Zhuk, 2011
+Twitter: @nzhuk
+
@@ -0,0 +1,58 @@
+/*
+ Copyright 2011 Marko Karppinen & Co. LLC.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ ModelObject.h
+ mogenerator / PONSO
+ Created by Nikita Zhuk on 22.1.2011.
+ */
+
+/**
+ Abstract superclass for all of our model classes.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface ModelObject : NSObject <NSCopying, NSCoding>
+{
+ NSDictionary *sourceDictionaryRepresentation;
+}
+
+@property(nonatomic, retain) NSDictionary *sourceDictionaryRepresentation;
+
+/**
+ Reads and deserializes a ModelObject from plist at given \c filePath
+ \return Newly created ModelObject or nil if any of the following occurs: file doesn't exist, file cannot be read, plist cannot be parsed.
+*/
++ (id)createModelObjectFromFile:(NSString *)filePath;
+
+/**
+ Serializes the receiver into binary plist and writes it to given \c filePath. Creates any intermediate directories in the path if necessary.
+ \return YES on success, NO on error (binary serialization or I/O error).
+*/
+- (BOOL)writeToFile:(NSString *)filePath;
+
+- (id)initWithDictionaryRepresentation:(NSDictionary *)dictionary;
+- (NSDictionary *)dictionaryRepresentation;
+
+- (void)awakeFromDictionaryRepresentationInit;
+
+@end
+
+
+@interface NSMutableDictionary (PONSONSMutableDictionaryAdditions)
+
+- (void)setObjectIfNotNil:(id)obj forKey:(NSString *)key;
+
+@end
Oops, something went wrong.

0 comments on commit 21dd19d

Please sign in to comment.