-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from k06a/feature/imperative
Add DIImperative plugin and refactored some cleanups
- Loading branch information
Showing
73 changed files
with
2,011 additions
and
588 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
174 changes: 94 additions & 80 deletions
174
Pod/Classes/DIDeluxeInjection.m → DeluxeInjection/Classes/DIDeluxeInjection.m
Large diffs are not rendered by default.
Oops, something went wrong.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// | ||
// DIImperative.h | ||
// DeluxeInjection | ||
// | ||
// Copyright (c) 2016 Anton Bukov <k06aaa@gmail.com> | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// 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. | ||
// | ||
|
||
#import "DIDeluxeInjection.h" | ||
|
||
/** | ||
* Block to filter properties to be injected | ||
* | ||
* @param targetClass Class to be injected | ||
* @param getter Selector of getter method | ||
* @param propertyName Property name to be injected | ||
* @param propertyClass Class of property to be injected, at least \c NSObject | ||
* @param propertyProtocols Set of property protocols including all superprotocols | ||
* | ||
* @return \c YES to inject property, \c NO to skip injection | ||
*/ | ||
typedef BOOL (^DIPropertyFilterBlock)(Class targetClass, SEL getter, NSString *propertyName, Class propertyClass, NSSet<Protocol *> *propertyProtocols); | ||
|
||
// | ||
|
||
@interface DIDeluxeInjectionImperativeInjector : NSObject | ||
|
||
/** | ||
* Set value to be injected | ||
* | ||
* @param valueObject Value to be injected | ||
*/ | ||
- (instancetype)valueObject:(id)valueObject; | ||
|
||
/** | ||
* Set value block to be injected | ||
* | ||
* @param valueBlock Value block to be injected | ||
*/ | ||
- (instancetype)valueBlock:(DIGetter)valueBlock; | ||
|
||
/** | ||
* Set filter class for conditional injection | ||
* | ||
* @param filterClass Class which sublasses properties can be injected | ||
*/ | ||
- (instancetype)filterClass:(Class)filterClass; | ||
|
||
/** | ||
* Set filter block for conditional injection | ||
* | ||
* @param filterBlock Block which define what properties can be injected | ||
*/ | ||
- (instancetype)filterBlock:(DIPropertyFilterBlock)filterBlock; | ||
|
||
@end | ||
|
||
// | ||
|
||
@interface DIDeluxeInjectionImperative : NSObject | ||
|
||
/** | ||
* Inject all properties of class \c klass with \c value | ||
* | ||
* @param klass Property class | ||
* | ||
* @return Injector object to define value and options to be injected | ||
*/ | ||
- (DIDeluxeInjectionImperativeInjector *)injectByPropertyClass:(Class)klass; | ||
|
||
/** | ||
* Inject all properties conforming \c protocol with \c value | ||
* | ||
* @param protocol Protocol of property | ||
* | ||
* @return Injector object to define value and options to be injected | ||
*/ | ||
- (DIDeluxeInjectionImperativeInjector *)injectByPropertyProtocol:(Protocol *)protocol; | ||
|
||
@end | ||
|
||
// | ||
|
||
/** | ||
* Block to apply imperative injections | ||
* | ||
* @param lets Object to apply imperative injections | ||
*/ | ||
typedef void (^DIImperativeBlock)(DIDeluxeInjectionImperative *lets); | ||
|
||
@interface DeluxeInjection (DIImperative) | ||
|
||
/** | ||
* Method to apply imperative injections inside block. All properties | ||
* marked with \c DIInject protocol should be injected at least once. | ||
* Properties who will be injected several times will be logged to \c NSLog(). | ||
* | ||
* @param block Block to apply imperative injections | ||
*/ | ||
+ (void)imperative:(DIImperativeBlock)block; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
// | ||
// DIImperative.m | ||
// DeluxeInjection | ||
// | ||
// Copyright (c) 2016 Anton Bukov <k06aaa@gmail.com> | ||
// | ||
// Licensed under the MIT License (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://opensource.org/licenses/MIT | ||
// | ||
// 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. | ||
// | ||
|
||
#import <assert.h> | ||
|
||
#import "DIDeluxeInjectionPlugin.h" | ||
#import "DIInject.h" | ||
#import "DIImperative.h" | ||
|
||
@interface DIPropertyHolder : NSObject | ||
|
||
@property (assign, nonatomic) Class targetClass; | ||
@property (assign, nonatomic) Class klass; | ||
@property (strong, nonatomic) NSString *name; | ||
@property (strong, nonatomic) NSSet<Protocol *> *protocols; | ||
@property (assign, nonatomic) SEL getter; | ||
@property (assign, nonatomic) BOOL wasInjected; | ||
|
||
@end | ||
|
||
@implementation DIPropertyHolder | ||
|
||
@end | ||
|
||
// | ||
|
||
@interface DIDeluxeInjectionImperativeInjector () | ||
|
||
@property (weak, nonatomic) DIDeluxeInjectionImperative *lets; | ||
@property (assign, nonatomic) Class savedClass; | ||
@property (assign, nonatomic) Protocol *savedProtocol; | ||
@property (copy, nonatomic) DIGetter savedValueBlock; | ||
@property (copy, nonatomic) DIPropertyFilterBlock savedFilterBlock; | ||
|
||
@end | ||
|
||
@interface DIDeluxeInjectionImperative () | ||
|
||
@property (strong, nonatomic) NSMutableDictionary<id,NSMutableArray<DIPropertyHolder *> *> *byClass; | ||
@property (strong, nonatomic) NSMutableDictionary<NSValue *,NSMutableArray<DIPropertyHolder *> *> *byProtocol; | ||
|
||
@end | ||
|
||
// | ||
|
||
@implementation DIDeluxeInjectionImperativeInjector | ||
|
||
- (instancetype)valueObject:(id)valueObject { | ||
return [self valueBlock:DIGetterIfIvarIsNil(^id (id target) { | ||
return valueObject; | ||
})]; | ||
} | ||
|
||
- (instancetype)valueBlock:(DIGetter)valueBlock { | ||
NSAssert(self.savedValueBlock == nil, @"You should call valueObject: or valueBlock: only once"); | ||
self.savedValueBlock = valueBlock; | ||
return self; | ||
} | ||
|
||
- (instancetype)filterClass:(Class)filterClass { | ||
return [self filterBlock:^BOOL(Class targetClass, SEL getter, NSString *propertyName, Class propertyClass, NSSet<Protocol *> *propertyProtocols) { | ||
return [targetClass isSubclassOfClass:filterClass]; | ||
}]; | ||
} | ||
|
||
- (instancetype)filterBlock:(DIPropertyFilterBlock)filterBlock { | ||
NSAssert(self.savedFilterBlock == nil, @"You should call filterClass: or filterBlock: only once"); | ||
self.savedFilterBlock = filterBlock; | ||
return self; | ||
} | ||
|
||
- (void)dealloc { | ||
NSAssert(!!self.savedClass != !!self.savedProtocol, @"You should not define both class and protocol to inject"); | ||
NSAssert(self.savedValueBlock, @"You should call valueObject: or valueBlock: once"); | ||
|
||
NSValue *key = [NSValue valueWithPointer:(__bridge void *)(self.savedProtocol)]; | ||
NSArray *holders = self.savedClass ? self.lets.byClass[self.savedClass] : self.lets.byProtocol[key]; | ||
|
||
for (DIPropertyHolder *holder in holders) { | ||
if (self.savedFilterBlock && !self.savedFilterBlock(holder.targetClass, holder.getter, holder.name, holder.klass, holder.protocols)) { | ||
continue; | ||
} | ||
if (holder.wasInjected) { | ||
NSLog(@"Warning: Reinjecting property [%@ %@]", holder.targetClass, NSStringFromSelector(holder.getter)); | ||
} | ||
[DeluxeInjection inject:holder.targetClass getter:holder.getter getterBlock:self.savedValueBlock]; | ||
holder.wasInjected = YES; | ||
} | ||
} | ||
|
||
@end | ||
|
||
// | ||
|
||
@implementation DIDeluxeInjectionImperative | ||
|
||
- (instancetype)init | ||
{ | ||
self = [super init]; | ||
if (self) { | ||
_byClass = [NSMutableDictionary dictionary]; | ||
_byProtocol = [NSMutableDictionary dictionary]; | ||
|
||
[DeluxeInjection inject:^NSArray * (Class targetClass, SEL getter, SEL setter, NSString *propertyName, Class propertyClass, NSSet<Protocol *> *propertyProtocols) { | ||
|
||
DIPropertyHolder *holder = [[DIPropertyHolder alloc] init]; | ||
holder.targetClass = targetClass; | ||
holder.getter = getter; | ||
holder.name = propertyName; | ||
holder.klass = propertyClass; | ||
holder.protocols = propertyProtocols; | ||
|
||
if (propertyClass) { | ||
if (_byClass[(id)propertyClass] == nil) { | ||
_byClass[(id)propertyClass] = [NSMutableArray array]; | ||
} | ||
[_byClass[(id)propertyClass] addObject:holder]; | ||
} | ||
|
||
for (Protocol *protocol in propertyProtocols) { | ||
NSValue *key = [NSValue valueWithPointer:(__bridge void *)(protocol)]; | ||
if (_byProtocol[key] == nil) { | ||
_byProtocol[key] = [NSMutableArray array]; | ||
} | ||
[_byProtocol[key] addObject:holder]; | ||
} | ||
|
||
return @[[DeluxeInjection doNotInject], | ||
[DeluxeInjection doNotInject]]; | ||
} conformingProtocol:@protocol(DIInject)]; | ||
} | ||
return self; | ||
} | ||
|
||
- (DIDeluxeInjectionImperativeInjector *)injectByPropertyClass:(Class)klass { | ||
DIDeluxeInjectionImperativeInjector *injector = [[DIDeluxeInjectionImperativeInjector alloc] init]; | ||
injector.lets = self; | ||
injector.savedClass = klass; | ||
return injector; | ||
} | ||
|
||
- (DIDeluxeInjectionImperativeInjector *)injectByPropertyProtocol:(Protocol *)protocol { | ||
DIDeluxeInjectionImperativeInjector *injector = [[DIDeluxeInjectionImperativeInjector alloc] init]; | ||
injector.lets = self; | ||
injector.savedProtocol = protocol; | ||
return injector; | ||
} | ||
|
||
- (void)checkAllInjected { | ||
for (Class klass in self.byClass) { | ||
for (DIPropertyHolder *holder in self.byClass[klass]) { | ||
NSString *problemDescription = [NSString stringWithFormat:@"Missing injection by class to [%@ %@]", holder.targetClass, NSStringFromSelector(holder.getter)]; | ||
NSAssert(holder.wasInjected, problemDescription); | ||
if (!holder.wasInjected) { | ||
NSLog(@"Warning: %@", problemDescription); | ||
} | ||
} | ||
} | ||
|
||
for (NSValue *key in self.byProtocol) { | ||
for (DIPropertyHolder *holder in self.byProtocol[key]) { | ||
NSString *problemDescription = [NSString stringWithFormat:@"Missing injection by protocol to [%@ %@]", holder.targetClass, NSStringFromSelector(holder.getter)]; | ||
NSAssert(holder.wasInjected, problemDescription); | ||
if (!holder.wasInjected) { | ||
NSLog(@"Warning: %@", problemDescription); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@end | ||
|
||
// | ||
|
||
@implementation DeluxeInjection (DIImperative) | ||
|
||
+ (void)imperative:(void (^)(DIDeluxeInjectionImperative *lets))block; { | ||
DIDeluxeInjectionImperative *di = [[DIDeluxeInjectionImperative alloc] init]; | ||
block(di); | ||
[di checkAllInjected]; | ||
} | ||
|
||
@end |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.