Permalink
Browse files

Support variadic arguments on JSObjectFactory

  • Loading branch information...
1 parent 8e04ce7 commit e8a958eed4fb86d4ef103bd7dd5e13fcc339d70d @thestoics thestoics committed Jun 13, 2012
View
@@ -10,4 +10,5 @@
- (id)initWithInjector:(JSObjectionInjector *)injector;
- (id)getObject:(id)classOrProtocol;
+- (id)getObjectWithArgs:(id)classOrProtocol, ... NS_REQUIRES_NIL_TERMINATION;
@end
View
@@ -14,4 +14,13 @@ - (id)initWithInjector:(JSObjectionInjector *)injector {
- (id)getObject:(id)classOrProtocol {
return [self.injector getObject:classOrProtocol];
}
+
+- (id)getObjectWithArgs:(id)classOrProtocol, ... {
+ va_list va_arguments;
+ va_start(va_arguments, classOrProtocol);
+ id object = [self.injector getObject:classOrProtocol arguments:va_arguments];
+ va_end(va_arguments);
+ return object;
+}
+
@end
@@ -12,4 +12,5 @@
- (id)initWithContext:(NSDictionary *)theGlobalContext andModules:(NSArray *)modules;
- (id)getObject:(id)classOrProtocol;
- (id)getObjectWithArgs:(id)classOrProtocol, ... NS_REQUIRES_NIL_TERMINATION;
+- (id)getObject:(id)classOrProtocol arguments:(va_list)argList;
@end
@@ -70,6 +70,18 @@ - (id)initWithContext:(NSDictionary *)theGlobalContext andModules:(NSArray *)mod
- (id)getObjectWithArgs:(id)classOrProtocol, ... {
+ va_list va_arguments;
+ va_start(va_arguments, classOrProtocol);
+ id object = [self getObject:classOrProtocol arguments:va_arguments];
+ va_end(va_arguments);
+ return object;
+}
+
+- (id)getObject:(id)classOrProtocol {
+ return [self getObjectWithArgs:classOrProtocol, nil];
+}
+
+- (id)getObject:(id)classOrProtocol arguments:(va_list)argList {
@synchronized(self) {
if (!classOrProtocol) {
return nil;
@@ -96,10 +108,7 @@ - (id)getObjectWithArgs:(id)classOrProtocol, ... {
}
if (classOrProtocol && injectorEntry) {
- va_list va_arguments;
- va_start(va_arguments, classOrProtocol);
- NSArray *arguments = JSObjectionUtils.transformVariadicArgsToArray(va_arguments);
- va_end(va_arguments);
+ NSArray *arguments = JSObjectionUtils.transformVariadicArgsToArray(argList);
return [injectorEntry extractObject:arguments];
}
@@ -110,9 +119,6 @@ - (id)getObjectWithArgs:(id)classOrProtocol, ... {
}
-- (id)getObject:(id)classOrProtocol {
- return [self getObjectWithArgs:classOrProtocol, nil];
-}
#pragma mark - Private
View
@@ -85,16 +85,22 @@ static objc_property_t GetProperty(Class klass, NSString *propertyName) {
static id BuildObjectWithInitializer(Class klass, SEL initializer, NSArray *arguments) {
id instance = [klass alloc];
NSMethodSignature *signature = [klass instanceMethodSignatureForSelector:initializer];
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
- [invocation setTarget:instance];
- [invocation setSelector:initializer];
- for (int i = 0; i < arguments.count; i++) {
- id argument = [arguments objectAtIndex:i];
- [invocation setArgument:&argument atIndex:i + 2];
+ if (signature) {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+ [invocation setTarget:instance];
+ [invocation setSelector:initializer];
+ for (int i = 0; i < arguments.count; i++) {
+ id argument = [arguments objectAtIndex:i];
+ [invocation setArgument:&argument atIndex:i + 2];
+ }
+ [invocation invoke];
+ [invocation getReturnValue:&instance];
+ return [instance autorelease];
+ } else {
+ [instance release];
+ @throw [NSException exceptionWithName:JSObjectionException reason:[NSString stringWithFormat:@"Could not find initializer '%@' on %@", NSStringFromSelector(initializer), NSStringFromClass(klass)] userInfo:nil];
}
- [invocation invoke];
- [invocation getReturnValue:&instance];
- return [instance autorelease];
+ return nil;
}
const struct JSObjectionUtils JSObjectionUtils = {
View
@@ -1,6 +1,7 @@
#import "SpecHelper.h"
#import <objc/runtime.h>
#import "Fixtures.h"
+#import "InitializerFixtures.h"
SPEC_BEGIN(BasicUsageSpecs)
beforeEach(^{
@@ -77,17 +78,32 @@
assertThatBool([car awake], equalToBool(YES));
});
-it(@"returns a JSObjectFactory for the given injector context", ^{
- JSObjectionInjector *injector1 = [JSObjection createInjector];
- JSObjectionInjector *injector2 = [JSObjection defaultInjector];
-
- JSObjectFactoryHolder *holder1 = [injector1 getObject:[JSObjectFactoryHolder class]];
- JSObjectFactoryHolder *holder2 = [injector2 getObject:[JSObjectFactoryHolder class]];
-
- SingletonItem *item1 = [holder1.objectFactory getObject:[SingletonItem class]];
- SingletonItem *item2 = [holder2.objectFactory getObject:[SingletonItem class]];
+
+describe(@"object factory", ^{
+ it(@"injector returns a JSObjectFactory for the given injector context", ^{
+ JSObjectionInjector *injector1 = [JSObjection createInjector];
+ JSObjectionInjector *injector2 = [JSObjection defaultInjector];
+
+ JSObjectFactoryHolder *holder1 = [injector1 getObject:[JSObjectFactoryHolder class]];
+ JSObjectFactoryHolder *holder2 = [injector2 getObject:[JSObjectFactoryHolder class]];
+
+ SingletonItem *item1 = [holder1.objectFactory getObject:[SingletonItem class]];
+ SingletonItem *item2 = [holder2.objectFactory getObject:[SingletonItem class]];
+
+ [[item1 shouldNot] equal:item2];
+ });
+
+ it(@"can take variadic arguments and pass them along to the injector", ^{
+ JSObjectionInjector *injector = [JSObjection defaultInjector];
+ JSObjectFactory *factory = [injector getObject:[JSObjectFactory class]];
+
+ ConfigurableCar *car = [factory getObjectWithArgs:[ConfigurableCar class], @"Model", @"Power", @"Year", nil];
+
+ [[car.model should] equal:@"Model"];
+ [[car.horsePower should] equal:@"Power"];
+ [[car.year should] equal:@"Year"];
- [[item1 shouldNot] equal:item2];
+ });
});
SPEC_END
@@ -21,3 +21,6 @@
- (id)initWithModel:(NSString *)model horsePower:(NSNumber *)horsePower andYear:(NSNumber *)year;
@end
+@interface BadInitializer : NSObject
+@end
+
@@ -1,5 +1,10 @@
#import "InitializerFixtures.h"
+@implementation BadInitializer
+objection_register(BadInitializer)
+objection_initializer(initWithNonExistentInitializer)
+@end
+
@implementation ViewController
objection_register(ViewController)
objection_requires(@"car")
@@ -26,7 +31,7 @@ - (void)dealloc {
@implementation ConfigurableCar
objection_register(ConfigurableCar)
-objection_requires(@"car", @"engine")
+objection_requires(@"engine")
objection_initializer(initWithModel:horsePower:andYear:)
@synthesize car = _car;
View
@@ -24,8 +24,19 @@
[[controller.car should] beMemberOfClass:[Car class]];
});
-it(@"is happy to instantiate an object with a number of initializer arguments", ^{
+it(@"is OK to register an object with an initializer without any default arguments", ^{
+ ConfigurableCar *car = [injector getObjectWithArgs:[ConfigurableCar class], @"Passat", [NSNumber numberWithInt:200], [NSNumber numberWithInt:2002], nil];
+ [[car.horsePower should] equal:[NSNumber numberWithInt:200]];
+ [[car.model should] equal:@"Passat"];
+ [[car.year should] equal:[NSNumber numberWithInt:2002]];
+ [[car.engine should] beMemberOfClass:[Engine class]];
+});
+
+it(@"raises an exception if the initializer is not valid", ^{
+ [[theBlock(^{
+ [injector getObject:[BadInitializer class]];
+ }) should] raiseWithReason:@"Could not find initializer 'initWithNonExistentInitializer' on BadInitializer"];
});
SPEC_END

0 comments on commit e8a958e

Please sign in to comment.