Skip to content

Instantly share code, notes, and snippets.

@robb
Created May 23, 2013 00:35
Show Gist options
  • Save robb/5631996 to your computer and use it in GitHub Desktop.
Save robb/5631996 to your computer and use it in GitHub Desktop.
//
// Example.m
// Partial
//
// Created by Robert Böhnke on 5/23/13.
// Copyright (c) 2013 Robert Böhnke. All rights reserved.
//
#import "Partial.h"
SpecBegin(Partial)
it(@"should WTF", ^{
BlockVar block = lift(@selector(addObject:));
NSMutableArray *myArray = [NSMutableArray array];
block(myArray, @1);
block(myArray, @2);
block(myArray, @3);
NSLog(@"My array is now %@", myArray); // @[ @1, @2, @3 ]
Block1 add = partial(myArray, (Block2)block);
add(@4);
add(@5);
add(@6);
NSLog(@"My array is now %@", myArray); // @[ @1, @2, @3, @4, @5, @6 ]
});
SpecEnd
//
// Partial.h
// Partialm
//
// Created by Robert Böhnke on 5/23/13.
// Copyright (c) 2013 Robert Böhnke. All rights reserved.
//
#import <Foundation/Foundation.h>
#define OVERLOADABLE __attribute__((overloadable))
typedef id (^Block0)(void);
typedef id (^Block1)(id arg1);
typedef id (^Block2)(id arg1, id arg2);
typedef id (^Block3)(id arg1, id arg2, id arg3);
typedef id (^Block4)(id arg1, id arg2, id arg3, id arg4);
typedef id (^Block5)(id arg1, id arg2, id arg3, id arg4, id arg5);
typedef id (^Block6)(id arg1, id arg2, id arg3, id arg4, id arg5, id arg6);
typedef id (^BlockVar)(id va, ...);
BlockVar lift(SEL selector);
OVERLOADABLE Block0 partial(id value, Block1 block);
OVERLOADABLE Block1 partial(id value, Block2 block);
OVERLOADABLE Block2 partial(id value, Block3 block);
OVERLOADABLE Block3 partial(id value, Block4 block);
OVERLOADABLE Block4 partial(id value, Block5 block);
OVERLOADABLE Block5 partial(id value, Block6 block);
//
// Partial.m
// Partial
//
// Created by Robert Böhnke on 5/23/13.
// Copyright (c) 2013 Robert Böhnke. All rights reserved.
//
#include <objc/objc.h>
#include <objc/objc-class.h>
#include <objc/objc-runtime.h>
#import "Partial.h"
BlockVar lift(SEL selector)
{
return ^id(id _self, ...) {
Method method = class_getInstanceMethod([_self class], selector);
const char *encoding = method_getTypeEncoding(method);
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:encoding];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:_self];
[invocation setSelector:selector];
va_list args;
va_start(args, _self);
for (NSUInteger i = 2; i < signature.numberOfArguments; i++) {
void *arg = va_arg(args, void *);
[invocation setArgument:&arg atIndex:i];
}
va_end(args);
[invocation invoke];
BOOL isVoid = strcmp(signature.methodReturnType, @encode(void)) == 0;
if (isVoid) return nil;
id returnValue;
[invocation getReturnValue:&returnValue];
return returnValue;
};
}
OVERLOADABLE Block0 partial(id value, Block1 block)
{
return ^{
return block(value);
};
}
OVERLOADABLE Block1 partial(id value, Block2 block)
{
return ^(id arg2){
return block(value, arg2);
};
}
OVERLOADABLE Block2 partial(id value, Block3 block)
{
return ^(id arg2, id arg3) {
return block(value, arg2, arg3);
};
}
OVERLOADABLE Block3 partial(id value, Block4 block)
{
return ^(id arg2, id arg3, id arg4) {
return block(value, arg2, arg3, arg4);
};
}
OVERLOADABLE Block4 partial(id value, Block5 block)
{
return ^(id arg2, id arg3, id arg4, id arg5) {
return block(value, arg2, arg3, arg4, arg5);
};
}
OVERLOADABLE Block5 partial(id value, Block6 block)
{
return ^(id arg2, id arg3, id arg4, id arg5, id arg6) {
return block(value, arg2, arg3, arg4, arg5, arg6);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment