Skip to content

Commit

Permalink
Provide mechanism to bind a concrete class to a protocol. closes atom…
Browse files Browse the repository at this point in the history
  • Loading branch information
jdewind committed Aug 19, 2011
1 parent 1edcd1f commit 2e137cc
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Objection-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.8</string>
<string>0.8.5</string>
<key>CFBundleSignature</key>
<string>ATOM</string>
<key>CFBundleVersion</key>
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Objection supports associating an object outside the context of Objection by con

#### Instance and Protocol Bindings

You can bind a type to a specific instance of that type. This is useful when an object exists or is constructed outside of Objection.
You can bind a protocol or class to a specific instance of that type. This is useful when an object exists or is constructed outside of Objection.

#### Example
```objective-c
Expand All @@ -88,6 +88,7 @@ You can bind a type to a specific instance of that type. This is useful when an
- (void)configure {
[self bind:[UIApplication sharedApplication] toClass:[UIApplication class]];
[self bind:[UIApplication sharedApplication].delegate toProtocol:@protocol(UIApplicationDelegate)];
[self bindClass:[MyAPIService class] toProtocol:@protocol(APIService)];
}

@end
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def system_or_exit(cmd, stdout = nil)
system(cmd) or raise "******** Build failed ********"
end

task :default => [:specs, :uispecs]
task :default => ["specs:ios", "specs:osx"]
task :cruise do
Rake::Task[:clean].invoke
Rake::Task[:build_all].invoke
Expand Down
1 change: 1 addition & 0 deletions Source/JSObjectionModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- (void)bindMetaClass:(Class)metaClass toProtocol:(Protocol *)aProtocol;
- (void)bindProvider:(id<JSObjectionProvider>)provider toClass:(Class)aClass;
- (void)bindProvider:(id<JSObjectionProvider>)provider toProtocol:(Protocol *)aProtocol;
- (void)bindClass:(Class)aClass toProtocol:(Protocol *)aProtocol;
#if NS_BLOCKS_AVAILABLE
- (void)bindBlock:(id (^)(JSObjectionInjector *context))block toClass:(Class)aClass;
- (void)bindBlock:(id (^)(JSObjectionInjector *context))block toProtocol:(Protocol *)aProtocol;
Expand Down
33 changes: 33 additions & 0 deletions Source/JSObjectionModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,31 @@
#import "JSObjectionBindingEntry.h"
#import "JSObjectionProviderEntry.h"
#import <objc/runtime.h>
#import "JSObjectionInjector.h"

@interface __JSClassToProtoclProvider : NSObject<JSObjectionProvider>
{
Class _class;
}
- (id)initWithClass:(Class)aClass;
@end

@implementation __JSClassToProtoclProvider

- (id)initWithClass:(Class)aClass
{
if ((self = [super init])) {
_class = aClass;
}
return self;
}

- (id)createInstance:(JSObjectionInjector *)context
{
return [context getObject:_class];
}

@end

@interface JSObjectionModule()
- (NSString *)protocolKey:(Protocol *)aProtocol;
Expand Down Expand Up @@ -62,6 +87,14 @@ - (void)bindProvider:(id<JSObjectionProvider>)provider toProtocol:(Protocol *)aP
[_bindings setObject:entry forKey:key];
}

- (void)bindClass:(Class)aClass toProtocol:(Protocol *)aProtocol
{
NSString *key = [self protocolKey:aProtocol];
__JSClassToProtoclProvider *provider = [[[__JSClassToProtoclProvider alloc] initWithClass:aClass] autorelease];
JSObjectionProviderEntry *entry = [[[JSObjectionProviderEntry alloc] initWithProvider:provider] autorelease];
[_bindings setObject:entry forKey:key];
}

#if NS_BLOCKS_AVAILABLE
- (void)bindBlock:(id (^)(JSObjectionInjector *context))block toClass:(Class)aClass
{
Expand Down
14 changes: 13 additions & 1 deletion Specs/ModuleFixtures.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

extern BOOL gEagerSingletonHook;


@protocol MetaCar<NSObject>
- (id)manufacture;
@end
Expand Down Expand Up @@ -58,6 +57,19 @@ extern BOOL gEagerSingletonHook;
@interface BlockModule : JSObjectionModule
@end

@interface CreditCardValidator : NSObject
@end

@protocol CreditCardProcessor <NSObject>
- (void)processNumber:(NSString *)number;
@end

@interface VisaCCProcessor : NSObject<CreditCardProcessor> {
CreditCardValidator *_validator;
}
@property (nonatomic, retain) CreditCardValidator *validator;
@end




Expand Down
21 changes: 20 additions & 1 deletion Specs/ModuleFixtures.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ - (id)initWithEngine:(Engine *)engine andGearBox:(id<GearBox>)gearBox {
- (void)configure {
[self bind:_engine toClass:[Engine class]];
[self bind:_gearBox toProtocol:@protocol(GearBox)];

[self bindClass:[VisaCCProcessor class] toProtocol:@protocol(CreditCardProcessor)];
if (self.instrumentInvalidMetaClass) {
[self bindMetaClass:(id)@"sneaky" toProtocol:@protocol(MetaCar)];
} else {
Expand Down Expand Up @@ -114,3 +114,22 @@ - (void)configure
}

@end

@implementation CreditCardValidator
@end

@implementation VisaCCProcessor
objection_register(VisaCCProcessor)
objection_requires(@"validator")

@synthesize validator = _validator;

- (void)processNumber:(NSString *)number {

}

- (void)dealloc {
[_validator release];
[super dealloc];
}
@end
9 changes: 9 additions & 0 deletions Specs/ModuleUsageSpecs.m
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,14 @@
[module configure];
}) should] raiseWithReason:@"\"sneaky\" can not be bound to the protocol \"MetaCar\" because it is not a meta class"];
});

describe(@"class to protocol bindings", ^{
it(@"supports associating a concrete class with a protocol", ^{
VisaCCProcessor *processor = [[JSObjection globalInjector] getObject:@protocol(CreditCardProcessor)];

assertThat(processor, is(instanceOf([VisaCCProcessor class])));
assertThat(processor.validator, is(instanceOf([CreditCardValidator class])));
});
});
});
SPEC_END

0 comments on commit 2e137cc

Please sign in to comment.