NewsBlur/clients/ios/Underscore/USArrayWrapper.m
2013-06-27 09:43:22 -07:00

305 lines
7.2 KiB
Objective-C
Executable file

//
// USArrayWrapper.m
// Underscore
//
// Created by Robert Böhnke on 5/13/12.
// Copyright (C) 2012 Robert Böhnke
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
#import "Underscore.h"
#import "USArrayWrapper.h"
@interface USArrayWrapper ()
- initWithArray:(NSArray *)array;
@property (readwrite, retain) NSArray *array;
@end
@implementation USArrayWrapper
#pragma mark Class methods
+ (USArrayWrapper *)wrap:(NSArray *)array
{
return [[USArrayWrapper alloc] initWithArray:[array copy]];
}
#pragma mark Lifecycle
- (id)init
{
return [super init];
}
- (id)initWithArray:(NSArray *)array
{
if (self = [super init]) {
self.array = array;
}
return self;
}
@synthesize array = _array;
- (NSArray *)unwrap
{
return [self.array copy];
}
#pragma mark Underscore methods
- (id)first
{
return self.array.count ? [self.array objectAtIndex:0] : nil;
}
- (id)last
{
return self.array.lastObject;
}
- (USArrayWrapper *(^)(NSUInteger))head
{
return ^USArrayWrapper *(NSUInteger count) {
NSRange range = NSMakeRange(0, MIN(self.array.count, count));
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
NSArray *result = [self.array objectsAtIndexes:indexSet];
return [[USArrayWrapper alloc] initWithArray:result];
};
}
- (USArrayWrapper *(^)(NSUInteger))tail
{
return ^USArrayWrapper *(NSUInteger count) {
NSRange range;
if (count > self.array.count) {
range = NSMakeRange(0, self.array.count);
} else {
range = NSMakeRange(self.array.count - count, count);
}
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
NSArray *result = [self.array objectsAtIndexes:indexSet];
return [[USArrayWrapper alloc] initWithArray:result];
};
}
- (NSUInteger (^)(id))indexOf
{
return ^NSUInteger (id obj) {
return [self.array indexOfObject:obj];
};
}
- (USArrayWrapper *)flatten
{
__weak NSArray *array = self.array;
__block NSArray *(^flatten)(NSArray *) = ^NSArray *(NSArray *input) {
NSMutableArray *result = [NSMutableArray array];
for (id obj in input) {
if ([obj isKindOfClass:[NSArray class]]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
[result addObjectsFromArray:flatten(obj)];
#pragma clang diagnostic pop
} else {
[result addObject:obj];
}
}
// If the outmost call terminates, nil the reference to flatten to break
// the retain cycle
if (input == array) {
flatten = nil;
}
return result;
};
return [USArrayWrapper wrap:flatten(self.array)];
}
- (USArrayWrapper *(^)(NSArray *))without
{
return ^USArrayWrapper *(NSArray *value) {
return self.reject(^(id obj){
return [value containsObject:obj];
});
};
}
- (USArrayWrapper *)shuffle
{
NSMutableArray *result = [self.array mutableCopy];
for (NSInteger i = result.count - 1; i > 0; i--) {
[result exchangeObjectAtIndex:arc4random() % (i + 1)
withObjectAtIndex:i];
}
return [[USArrayWrapper alloc] initWithArray:result];
}
- (id (^)(id, UnderscoreReduceBlock))reduce
{
return ^USArrayWrapper *(id memo, UnderscoreReduceBlock function) {
for (id obj in self.array) {
memo = function(memo, obj);
}
return memo;
};
}
- (id (^)(id, UnderscoreReduceBlock))reduceRight
{
return ^USArrayWrapper *(id memo, UnderscoreReduceBlock function) {
for (id obj in self.array.reverseObjectEnumerator) {
memo = function(memo, obj);
}
return memo;
};
}
- (USArrayWrapper *(^)(UnderscoreArrayIteratorBlock))each
{
return ^USArrayWrapper *(UnderscoreArrayIteratorBlock block) {
for (id obj in self.array) {
block(obj);
}
return self;
};
}
- (USArrayWrapper *(^)(UnderscoreArrayMapBlock))map
{
return ^USArrayWrapper *(UnderscoreArrayMapBlock block) {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:self.array.count];
for (id obj in self.array) {
id mapped = block(obj);
if (mapped) {
[result addObject:mapped];
}
}
return [[USArrayWrapper alloc] initWithArray:result];
};
}
- (USArrayWrapper *(^)(NSString *))pluck
{
return ^USArrayWrapper *(NSString *keyPath) {
return self.map(^id (id obj) {
return [obj valueForKeyPath:keyPath];
});
};
}
- (USArrayWrapper *)uniq
{
NSSet* uniqSet = [NSSet setWithArray:self.array];
NSArray* result = [uniqSet allObjects];
return [[USArrayWrapper alloc] initWithArray:result];
}
- (id (^)(UnderscoreTestBlock))find
{
return ^id (UnderscoreTestBlock test) {
for (id obj in self.array) {
if (test(obj)) {
return obj;
}
}
return nil;
};
}
- (USArrayWrapper *(^)(UnderscoreTestBlock))filter
{
return ^USArrayWrapper *(UnderscoreTestBlock test) {
return self.map(^id (id obj) {
return test(obj) ? obj : nil;
});
};
}
- (USArrayWrapper *(^)(UnderscoreTestBlock))reject
{
return ^USArrayWrapper *(UnderscoreTestBlock test) {
return self.filter(Underscore.negate(test));
};
}
- (BOOL (^)(UnderscoreTestBlock))all
{
return ^BOOL (UnderscoreTestBlock test) {
if (self.array.count == 0) {
return NO;
}
BOOL result = YES;
for (id obj in self.array) {
if (!test(obj)) {
return NO;
}
}
return result;
};
}
- (BOOL (^)(UnderscoreTestBlock))any
{
return ^BOOL (UnderscoreTestBlock test) {
BOOL result = NO;
for (id obj in self.array) {
if (test(obj)) {
return YES;
}
}
return result;
};
}
- (USArrayWrapper *(^)(UnderscoreSortBlock))sort
{
return ^USArrayWrapper *(UnderscoreSortBlock block) {
NSArray *result = [self.array sortedArrayUsingComparator:block];
return [[USArrayWrapper alloc] initWithArray:result];
};
}
@end