Skip to content

Commit

Permalink
support inheritence
Browse files Browse the repository at this point in the history
  • Loading branch information
jdewind committed Dec 4, 2010
1 parent 593e008 commit 29cca92
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 22 deletions.
14 changes: 12 additions & 2 deletions Headers/ObjectionInjector.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import <Foundation/Foundation.h>
#import "ObjectionEntry.h"
#import <objc/objc.h>

#define objection_register(value) \
+ (void)initialize { \
Expand All @@ -16,8 +17,17 @@
}

#define objection_requires(args...) \
+ (NSArray *)requires { \
return [NSArray arrayWithObjects: args, nil]; \
+ (NSArray *)objectionRequires { \
NSArray *requirements = [NSArray arrayWithObjects: args, nil]; \
Class superClass = class_getSuperclass([self class]); \
if([superClass respondsToSelector:@selector(objectionRequires)]) { \
NSArray *parentsRequirements = [superClass performSelector:@selector(objectionRequires)]; \
NSMutableSet *dependencies = [NSMutableSet setWithCapacity:parentsRequirements.count]; \
[dependencies addObjectsFromArray:parentsRequirements]; \
[dependencies addObjectsFromArray:requirements]; \
requirements = [dependencies allObjects]; \
} \
return requirements; \
} \

@interface ObjectionInjector : NSObject {
Expand Down
20 changes: 16 additions & 4 deletions Objection.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
4B15F24F12AA896900C3CD8E /* OCHamcrest.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 4BA9CFF412AA86E600674F0E /* OCHamcrest.framework */; };
4B25BCE61291B81F00821DC1 /* InjectionErrorsSpecs.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF451E21291AD28006EB2D5 /* InjectionErrorsSpecs.m */; };
4B25BD4B1291BBE700821DC1 /* InjectionErrorFixtures.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B25BD4A1291BBE700821DC1 /* InjectionErrorFixtures.m */; };
4B7300D812AA8F3400903427 /* InheritenceSpecs.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7300D712AA8F3400903427 /* InheritenceSpecs.m */; };
4B7300D912AA8F3400903427 /* InheritenceSpecs.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7300D712AA8F3400903427 /* InheritenceSpecs.m */; };
4BA6DD1F12AAB3CD00CFFD70 /* ObjectionEntry.h in Copy Header Files */ = {isa = PBXBuildFile; fileRef = 4BED512F12AA8BF300CA6B36 /* ObjectionEntry.h */; };
4BA6DD2012AAB3CD00CFFD70 /* ObjectionInjector.h in Copy Header Files */ = {isa = PBXBuildFile; fileRef = 4BED513012AA8BF300CA6B36 /* ObjectionInjector.h */; };
4BA6DD2112AAB3CD00CFFD70 /* ObjectionInstanceEntry.h in Copy Header Files */ = {isa = PBXBuildFile; fileRef = 4BED513112AA8BF300CA6B36 /* ObjectionInstanceEntry.h */; };
4BA9CFB212AA868400674F0E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA9CFB112AA868400674F0E /* main.m */; };
4BA9CFEA12AA86D300674F0E /* Cedar-iPhone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BA9CFE912AA86D300674F0E /* Cedar-iPhone.framework */; };
4BA9CFEC12AA86D300674F0E /* OCHamcrest-iPhone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BA9CFEB12AA86D300674F0E /* OCHamcrest-iPhone.framework */; };
Expand All @@ -49,9 +54,9 @@
4BED512A12AA8BCC00CA6B36 /* ObjectionEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BED511E12AA8BCC00CA6B36 /* ObjectionEntry.m */; };
4BED512B12AA8BCC00CA6B36 /* ObjectionInjector.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BED511F12AA8BCC00CA6B36 /* ObjectionInjector.m */; };
4BED512C12AA8BCC00CA6B36 /* ObjectionInstanceEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BED512012AA8BCC00CA6B36 /* ObjectionInstanceEntry.m */; };
4BED513212AA8BF300CA6B36 /* ObjectionEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED512F12AA8BF300CA6B36 /* ObjectionEntry.h */; };
4BED513312AA8BF300CA6B36 /* ObjectionInjector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513012AA8BF300CA6B36 /* ObjectionInjector.h */; };
4BED513412AA8BF300CA6B36 /* ObjectionInstanceEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513112AA8BF300CA6B36 /* ObjectionInstanceEntry.h */; };
4BED513212AA8BF300CA6B36 /* ObjectionEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED512F12AA8BF300CA6B36 /* ObjectionEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };
4BED513312AA8BF300CA6B36 /* ObjectionInjector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513012AA8BF300CA6B36 /* ObjectionInjector.h */; settings = {ATTRIBUTES = (Public, ); }; };
4BED513412AA8BF300CA6B36 /* ObjectionInstanceEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513112AA8BF300CA6B36 /* ObjectionInstanceEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };
4BED513512AA8BF300CA6B36 /* ObjectionEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED512F12AA8BF300CA6B36 /* ObjectionEntry.h */; };
4BED513612AA8BF300CA6B36 /* ObjectionInjector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513012AA8BF300CA6B36 /* ObjectionInjector.h */; };
4BED513712AA8BF300CA6B36 /* ObjectionInstanceEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BED513112AA8BF300CA6B36 /* ObjectionInstanceEntry.h */; };
Expand Down Expand Up @@ -79,6 +84,9 @@
dstPath = "${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal/${PRODUCT_NAME}.framework/Versions/Current/Headers";
dstSubfolderSpec = 0;
files = (
4BA6DD1F12AAB3CD00CFFD70 /* ObjectionEntry.h in Copy Header Files */,
4BA6DD2012AAB3CD00CFFD70 /* ObjectionInjector.h in Copy Header Files */,
4BA6DD2112AAB3CD00CFFD70 /* ObjectionInstanceEntry.h in Copy Header Files */,
);
name = "Copy Header Files";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -88,6 +96,7 @@
/* Begin PBXFileReference section */
4B25BD491291BBE700821DC1 /* InjectionErrorFixtures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectionErrorFixtures.h; sourceTree = "<group>"; };
4B25BD4A1291BBE700821DC1 /* InjectionErrorFixtures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InjectionErrorFixtures.m; sourceTree = "<group>"; };
4B7300D712AA8F3400903427 /* InheritenceSpecs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InheritenceSpecs.m; sourceTree = "<group>"; };
4BA9CFB112AA868400674F0E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
4BA9CFB312AA86A200674F0E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
4BA9CFE912AA86D300674F0E /* Cedar-iPhone.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "Cedar-iPhone.framework"; path = "Vendor/Cedar-iPhone.framework"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -240,6 +249,7 @@
4BF452461291AFEA006EB2D5 /* Helpers */,
4BF4516B129199AF006EB2D5 /* BasicUsageSpecs.m */,
4BF451E21291AD28006EB2D5 /* InjectionErrorsSpecs.m */,
4B7300D712AA8F3400903427 /* InheritenceSpecs.m */,
);
path = Specs;
sourceTree = "<group>";
Expand Down Expand Up @@ -409,7 +419,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator4.1 -target ${PROJECT_NAME}-StaticLib -configuration ${CONFIGURATION} clean build\nxcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos4.1 -target ${PROJECT_NAME}-StaticLib -configuration ${CONFIGURATION} clean build";
shellScript = "xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator4.2 -target ${PROJECT_NAME}-StaticLib -configuration ${CONFIGURATION} clean build\nxcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos4.2 -target ${PROJECT_NAME}-StaticLib -configuration ${CONFIGURATION} clean build";
};
4B25BE511291C51E00821DC1 /* Build Universal Lib */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -440,6 +450,7 @@
4BED512112AA8BCC00CA6B36 /* ObjectionEntry.m in Sources */,
4BED512212AA8BCC00CA6B36 /* ObjectionInjector.m in Sources */,
4BED512312AA8BCC00CA6B36 /* ObjectionInstanceEntry.m in Sources */,
4B7300D812AA8F3400903427 /* InheritenceSpecs.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -465,6 +476,7 @@
4BED512712AA8BCC00CA6B36 /* ObjectionEntry.m in Sources */,
4BED512812AA8BCC00CA6B36 /* ObjectionInjector.m in Sources */,
4BED512912AA8BCC00CA6B36 /* ObjectionInstanceEntry.m in Sources */,
4B7300D912AA8F3400903427 /* InheritenceSpecs.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
4 changes: 2 additions & 2 deletions Source/ObjectionEntry.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ - (id)initWithClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)theLif


- (id)buildObject {
if([self.classEntry respondsToSelector:@selector(requires)]) {
NSArray *properties = [self.classEntry performSelector:@selector(requires)];
if([self.classEntry respondsToSelector:@selector(objectionRequires)]) {
NSArray *properties = [self.classEntry performSelector:@selector(objectionRequires)];
NSMutableDictionary *propertiesDictionary = [NSMutableDictionary dictionaryWithCapacity:properties.count];
id objectUnderConstruction = [[self.classEntry alloc] init];

Expand Down
42 changes: 31 additions & 11 deletions Source/ObjectionInjector.m
Original file line number Diff line number Diff line change
@@ -1,41 +1,61 @@
#import "ObjectionInjector.h"
#import "ObjectionInstanceEntry.h"
#import <pthread.h>

static NSMutableDictionary *gAOContext;
static NSMutableDictionary *gObjectionContext;
static pthread_mutex_t gObjectionMutex;

@implementation ObjectionInjector

+ (void)initialize {
if (self == [ObjectionInjector class]) {
gAOContext = [[NSMutableDictionary alloc] init];
gObjectionContext = [[NSMutableDictionary alloc] init];
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&gObjectionMutex, &mutexattr);
pthread_mutexattr_destroy(&mutexattr);
}
}

+ (void) registerObject:(id)theObject forClass:(Class)theClass {
[gAOContext setObject:[[[ObjectionInstanceEntry alloc] initWithObject:theObject] autorelease] forKey:NSStringFromClass(theClass)];
pthread_mutex_lock(&gObjectionMutex);
[gObjectionContext setObject:[[[ObjectionInstanceEntry alloc] initWithObject:theObject] autorelease] forKey:NSStringFromClass(theClass)];
pthread_mutex_unlock(&gObjectionMutex);
}

+ (void) registerClass:(Class)theClass lifeCycle:(ObjectionInstantiationRule)lifeCycle {
pthread_mutex_lock(&gObjectionMutex);
if (lifeCycle != ObjectionInstantiationRule_Singleton && lifeCycle != ObjectionInstantiationRule_Everytime) {
@throw [NSException exceptionWithName:@"ObjectionInjectorException" reason:@"Invalid Instantiation Rule" userInfo:nil];
}

if (theClass && [gAOContext objectForKey:NSStringFromClass(theClass)] == nil) {
[gAOContext setObject:[ObjectionEntry withClass:theClass lifeCycle:lifeCycle andContext:self] forKey:NSStringFromClass(theClass)];
if (theClass && [gObjectionContext objectForKey:NSStringFromClass(theClass)] == nil) {
[gObjectionContext setObject:[ObjectionEntry withClass:theClass lifeCycle:lifeCycle andContext:self] forKey:NSStringFromClass(theClass)];
}
pthread_mutex_unlock(&gObjectionMutex);
}

+ (id)getObject:(Class)theClass {
NSString *key = NSStringFromClass(theClass);
ObjectionEntry *entry = [gAOContext objectForKey:key];
if (theClass && entry) {
return [entry extractObject];
}
pthread_mutex_lock(&gObjectionMutex);
@try {
NSString *key = NSStringFromClass(theClass);
ObjectionEntry *entry = [gObjectionContext objectForKey:key];
if (theClass && entry) {
return [entry extractObject];
}
}
@finally {
pthread_mutex_unlock(&gObjectionMutex);
}

return nil;

}

+ (void) reset {
[gAOContext removeAllObjects];
pthread_mutex_lock(&gObjectionMutex);
[gObjectionContext removeAllObjects];
pthread_mutex_unlock(&gObjectionMutex);
}
@end
63 changes: 63 additions & 0 deletions Specs/InheritenceSpecs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#import "SpecHelper.h"

@interface Person : NSObject
{
NSDictionary *_attributes;
}

@property (nonatomic, retain) NSDictionary *attributes;
@end

@implementation Person
objection_register(@"Person")
objection_requires(@"attributes")
@synthesize attributes=_attributes;
@end

@interface Programmer : Person
{
NSDictionary *_favoriteLanguages;
}
@property (nonatomic, retain) NSDictionary *favoriteLanguages;
@end

@implementation Programmer
objection_register(@"Programmer")
objection_requires(@"favoriteLanguages")
@synthesize favoriteLanguages=_favoriteLanguages;

@end

@interface NoInheritence : NSObject
{
NSString *_something;
}

@property (nonatomic, retain) NSString *something;

@end

@implementation NoInheritence
objection_register(@"NoInheritence")
objection_requires(@"something")

@synthesize something=_something;

@end





SPEC_BEGIN(InheritenceSpecs)
it(@"coalesces dependencies from parent to child", ^{
Programmer *programmer = [ObjectionInjector getObject:[Programmer class]];
assertThat(programmer.attributes, is(notNilValue()));
assertThat(programmer.favoriteLanguages, is(notNilValue()));
});

it(@"does not throw a fit if the base class does not implement super", ^{
NoInheritence *noParentObjectWithRequires = [ObjectionInjector getObject:[NoInheritence class]];
assertThat(noParentObjectWithRequires.something, is(notNilValue()));
});
SPEC_END
6 changes: 3 additions & 3 deletions Specs/InjectionErrorsSpecs.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
it(@"throws an exception if property type if not an object", ^{
@try {
[ObjectionInjector getObject:[UnsupportedPropertyObject class]];
assertThatBool(NO, equalToBool(YES));
fail(@"Should have thrown an exception");
}
@catch (NSException * e) {
assertThat([e reason], is(@"Unable to determine class type for property declaration: 'myInteger'"));
Expand All @@ -17,7 +17,7 @@
it(@"throws an exception if property cannot be found", ^{
@try {
[ObjectionInjector getObject:[BadPropertyObject class]];
assertThatBool(NO, equalToBool(YES));
fail(@"Should have thrown an exception");
}
@catch (NSException * e) {
assertThat([e reason], is(@"Unable to find property declaration: 'badProperty'"));
Expand All @@ -28,7 +28,7 @@
it(@"throws if instantiation rule if not valid", ^{
@try {
[ObjectionInjector registerClass:[CarFactory class] lifeCycle:3];
assertThatBool(NO, equalToBool(YES));
fail(@"Should have thrown an exception");
}
@catch (NSException * e) {
assertThat([e reason], is(@"Invalid Instantiation Rule"));
Expand Down

0 comments on commit 29cca92

Please sign in to comment.