Skip to content

Commit

Permalink
Merge pull request #68 from tyrone-sudeium/master
Browse files Browse the repository at this point in the history
PONSO: NSSet-based templates, improved inverse relationship logic
  • Loading branch information
nikita-zhuk committed Dec 1, 2011
2 parents dc55ebb + 25b700a commit 21dd19d
Show file tree
Hide file tree
Showing 54 changed files with 3,840 additions and 12 deletions.
2 changes: 1 addition & 1 deletion contributed templates/Nikita Zhuk/ponso/code/ModelObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

#import <Foundation/Foundation.h>

@interface ModelObject : NSObject <NSCopying>
@interface ModelObject : NSObject <NSCopying, NSCoding>
{
NSDictionary *sourceDictionaryRepresentation;
}
Expand Down
16 changes: 16 additions & 0 deletions contributed templates/Nikita Zhuk/ponso/code/ModelObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
8 changes: 6 additions & 2 deletions contributed templates/Nikita Zhuk/ponso/templates/machine.h.motemplate
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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$>
Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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$>
Expand All @@ -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
45 changes: 45 additions & 0 deletions contributed templates/Tyrone Trevorrow/ponso/README.txt
Original file line number Diff line number Diff line change
@@ -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

58 changes: 58 additions & 0 deletions contributed templates/Tyrone Trevorrow/ponso/code/ModelObject.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 21dd19d

Please sign in to comment.