Skip to content

Commit

Permalink
Add Set equivalents for valid Array methods
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb committed Oct 2, 2015
1 parent cdf5fab commit 35d4708
Show file tree
Hide file tree
Showing 38 changed files with 823 additions and 1 deletion.
2 changes: 1 addition & 1 deletion NSArray+inject.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ @implementation NSArray (YOLOInject)

- (id(^)(id, id (^)(id, id)))inject {
return ^(id initial_memo, id (^block)(id, id)) {
BOOL wasNonMutable = [initial_memo classForCoder] == [NSArray class] || [initial_memo classForCoder] == [NSDictionary class];
BOOL wasNonMutable = [initial_memo classForCoder] == [NSArray class] || [initial_memo classForCoder] == [NSDictionary class] || [initial_memo classForCoder] == [NSSet class];
if (wasNonMutable)
initial_memo = [initial_memo mutableCopy];

Expand Down
29 changes: 29 additions & 0 deletions NSSet+all.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#import <Foundation/NSSet.h>


@interface NSSet (YOLOAll)

/**
Invokes the given block for each element in the receiver. Should the
block return `NO`, the method immediately returns `NO`, ceasing
enumeration. If all executions of the block return `YES`, `all`
returns `YES`.
BOOL rv = @[@1, @2, @3].all(^(id o){
return [o intValue] > 0;
});
// rv => YES
BOOL rv = @[@1, @2, @3].all(^(int d){
return d < 3;
});
// rv => NO
Instead of a block, you can pass a `Class` object.
BOOL rv = @[@1, @2, @3].all(NSNumber.class);
// rv => YES
*/
- (BOOL(^)(id blockOrClass))all;

@end
43 changes: 43 additions & 0 deletions NSSet+all.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#import "YOLO.ph"


@implementation NSSet (YOLOAll)

- (BOOL(^)(id o))all {
return ^(id arg){
BOOL (^block)(id o) = nil;

if (arg == NSString.class /*or segfaults!*/ || YOLOIsClass(arg)) {
Class cls = arg;
block = ^(id o){
return [o isKindOfClass:cls];
};
} else {
switch ([YOLOMS(arg) getArgumentTypeAtIndex:1][0]) {
case 'c': { block = ^(id o){ return ((BOOL(^)(char))arg)([o charValue]); }; break; }
case 'i': { block = ^(id o){ return ((BOOL(^)(int))arg)([o intValue]); }; break; }
case 's': { block = ^(id o){ return ((BOOL(^)(short))arg)([o shortValue]); }; break; }
case 'l': { block = ^(id o){ return ((BOOL(^)(long))arg)([o longValue]); }; break; }
case 'q': { block = ^(id o){ return ((BOOL(^)(long long))arg)([o longLongValue]); }; break; }
case 'C': { block = ^(id o){ return ((BOOL(^)(unsigned char))arg)([o unsignedCharValue]); }; break; }
case 'I': { block = ^(id o){ return ((BOOL(^)(unsigned))arg)([o unsignedIntValue]); }; break; }
case 'S': { block = ^(id o){ return ((BOOL(^)(unsigned short))arg)([o unsignedShortValue]); }; break; }
case 'L': { block = ^(id o){ return ((BOOL(^)(unsigned long))arg)([o unsignedLongValue]); }; break; }
case 'Q': { block = ^(id o){ return ((BOOL(^)(unsigned long long))arg)([o unsignedLongLongValue]); }; break; }
case 'f': { block = ^(id o){ return ((BOOL(^)(float))arg)([o floatValue]); }; break; }
case 'd': { block = ^(id o){ return ((BOOL(^)(double))arg)([o doubleValue]); }; break; }
case 'B': { block = ^(id o){ return ((BOOL(^)(BOOL))arg)([o boolValue]); }; break; }
default:
block = arg;
break;
}
}

for (id o in self)
if (!block(o))
return NO;
return YES;
};
}

@end
18 changes: 18 additions & 0 deletions NSSet+any.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOAny)

/**
BOOL rv = @[@1, @2, @3].any(^(id o){
return [o intValue] == 3;
});
// rv => YES
Instead of a block, you can pass a `Class` object.
BOOL rv = @[@1, @2, @3].any(NSNumber.class);
// rv => YES
*/
- (BOOL(^)(id blockOrClass))any;

@end
24 changes: 24 additions & 0 deletions NSSet+any.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#import "YOLO.ph"

@implementation NSSet (YOLOAny)

- (BOOL(^)(id))any {
return ^(id arg){
BOOL (^block)(id o) = nil;

if (arg == NSString.class /*or segfaults!*/ || YOLOIsClass(arg)) {
Class cls = arg;
block = ^(id o){
return [o isKindOfClass:cls];
};
} else
block = arg;

for (id o in self)
if (block(o))
return YES;
return NO;
};
}

@end
17 changes: 17 additions & 0 deletions NSSet+find.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOFind)

/**
Passes each entry in the array to the given block, returning the first
element for which block is not `NO`. If no object matches, returns
`nil`.
id rv = @[@1, @2, @3, @4].find(^(id n){
return [n isEqual:@3];
});
// rv => @3
*/
- (id(^)(id))find;

@end
14 changes: 14 additions & 0 deletions NSSet+find.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import "YOLO.ph"

@implementation NSSet (YOLOFind)

- (id(^)(id))find {
return ^id(BOOL (^block)(id o)) {
for (id item in self)
if (block(item))
return item;
return nil;
};
}

@end
30 changes: 30 additions & 0 deletions NSSet+flatMap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOFlatMap)

/**
Returns a new set with the concatenated results of running block once
for every element in the receiver.
id rv = @[@1, @2, @3, @4].flatMap(^(id n){
return @[n, n];
});
// rv => @[@1, @1, @2, @2, @3, @3, @4, @4]
id rv = @[@1, @2, @3, @4].flatMap(^(id n){
return [NSSet setWithArray:@[n, n]];
});
// rv => @[@1, @1, @2, @2, @3, @3, @4, @4]
id rv = @[@1, @2, @3, @4].flatMap(^(id n){
return @[n, @[n]];
});
// rv => @[@1, @[@1], @2, @[@2], @3, @[@3], @4, @[@4]]
PROTIP: Useful over vanilla map followed by a flatten because flatten is
recursive, and you may want to preserve array relationships beyond the
first level. Also, `flatMap` is technically more efficient.
*/
- (id(^)(NSSet *(^)(id o)))flatMap;

@end
19 changes: 19 additions & 0 deletions NSSet+flatMap.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import "YOLO.ph"

@implementation NSSet (YOLOFlatMap)

- (NSSet *(^)(NSSet *(^)(id o)))flatMap {
return ^(NSSet *(^block)(id o)){
NSMutableSet *rv = [NSMutableSet new];
for (id o in self) {
id m = block(o);
if ([m isKindOfClass:[NSSet class]])
[rv addObjectsFromArray:[m allObjects]];
else
[rv addObjectsFromArray:m];
}
return rv;
};
}

@end
14 changes: 14 additions & 0 deletions NSSet+flatten.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOFlatten)

/**
Returns a new, one-dimensional array that is a recursive flattening of
the receiver.
id rv = @[@[@1, @[@2]], @3, @[@4]].flatten
// rv => @[@1, @2, @3, @4]
*/
- (NSSet *)flatten;

@end
18 changes: 18 additions & 0 deletions NSSet+flatten.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import "YOLO.ph"

@implementation NSSet (YOLOFlatten)

- (id)flatten {
NSMutableSet *aa = [NSMutableSet set];
for (id o in self) {
if ([o isKindOfClass:[NSArray class]])
[aa addObjectsFromArray:[o flatten]];
else if ([o isKindOfClass:[NSSet class]])
[aa addObjectsFromArray:[o allObjects]];
else
[aa addObject:o];
}
return aa;
}

@end
15 changes: 15 additions & 0 deletions NSSet+groupBy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOGroupBy)

/**
Groups the collection by result of the given block.
id rv = @[@1, @2, @3, @4].groupBy(^(NSNumber *n) {
return @(n.intValue % 2);
});
// rv => @{@0: @[@1, @3], @1: @[@2, @4]}
*/
- (NSDictionary *(^)(id (^)(id o)))groupBy;

@end
19 changes: 19 additions & 0 deletions NSSet+groupBy.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import "YOLO.ph"

@implementation NSSet (YOLOGroupBy)

- (NSDictionary *(^)(id (^)(id o)))groupBy {
return ^id(id (^block)(id)) {
NSMutableDictionary *dict = [NSMutableDictionary new];
for (id o in self) {
id key = block(o);
if (!dict[key])
dict[key] = [NSMutableArray arrayWithObject:o];
else
[dict[key] addObject:o];
}
return dict;
};
}

@end
24 changes: 24 additions & 0 deletions NSSet+has.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#import <Foundation/NSArray.h>

@interface NSSet (YOLOHas)

/**
BOOL rv = @[@1, @2, @3].has(@2)
// rv => YES
Short-hand for containsObject:. Provided because doing a map, then a
select and a few more chained dot-notations are commonly followed with
the need to then determine if a particular value is in the resulting
array, and then having to square bracket the whole chain is ugly.
We decided not to override any or find with the capability to take an
object rather than a block and instead add this method. Rest assured the
decision was careful. In the end has() seemed the choice that resulted in
the clearest code.
`has` was chosen over *contains* or *includes* because it is short and
clear.
*/
- (BOOL (^)(id o))has;

@end
11 changes: 11 additions & 0 deletions NSSet+has.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import "YOLO.ph"

@implementation NSSet (YOLOHas)

- (BOOL (^)(id o))has {
return ^BOOL(id o){
return [self containsObject:o];
};
}

@end
21 changes: 21 additions & 0 deletions NSSet+inject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOInject)

/**
Combines all elements of the receiver by applying a binary operation.
id rv = @[@1, @2, @3, @4].inject(@{}, ^(NSMutableDictionary *memo, NSNumber *n){
memo[n] = @(n.intValue * n.intValue);
return memo;
});
// rv => @{@1: @1, @2: @4, @3: @9, @4: @16}
PROTIP: If you feed `inject` a non-mutable dictionary or array YOLOKit
mutates it for your block, and then finally returns a non-mutable copy.
@see -reject
*/
- (id(^)(id initial_memo, id (^)(id memo, id obj)))inject;

@end
18 changes: 18 additions & 0 deletions NSSet+inject.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import "YOLO.ph"

@implementation NSSet (YOLOInject)

- (id(^)(id, id (^)(id, id)))inject {
return ^(id initial_memo, id (^block)(id, id)) {
BOOL wasNonMutable = [initial_memo classForCoder] == [NSArray class] || [initial_memo classForCoder] == [NSDictionary class] || [initial_memo classForCoder] == [NSSet class];
if (wasNonMutable)
initial_memo = [initial_memo mutableCopy];

id memo = initial_memo;
for (id obj in self)
memo = block(memo, obj);
return wasNonMutable ? [memo copy] : memo;
};
}

@end
19 changes: 19 additions & 0 deletions NSSet+join.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import <Foundation/NSSet.h>

@interface NSSet (YOLOJoin)

/**
Returns a string of all the receiver’s elements joined with the provided
separator string.
id rv = @[@1, @2, @3, @4].join(@",");
// rv => @"1,2,3,4"
id rv = @[@1, @2, @3, @4].join(@"");
// rv => @"1234"
PROTIP: `-description` is called on all objects before joining them.
*/
- (NSString *(^)(NSString *))join;

@end
12 changes: 12 additions & 0 deletions NSSet+join.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#import "NSSet+pluck.h"
#import "YOLO.ph"

@implementation NSSet (YOLOJoin)

- (NSString *(^)(NSString *))join {
return ^(NSString *separator) {
return [self.pluck(@"description").allObjects componentsJoinedByString:separator ?: @""];
};
}

@end
Loading

0 comments on commit 35d4708

Please sign in to comment.