Skip to content
This repository was archived by the owner on Dec 12, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Classes/NSArray+ObjectiveSugar.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,11 @@

- (NSArray *)symmetricDifference:(NSArray *)array;

/**
Returns a copy of self with all NSNull elements removed.

@return A copy of self with all NSNull elements removed.
*/
- (NSArray *)compact;

@end
10 changes: 10 additions & 0 deletions Classes/NSArray+ObjectiveSugar.m
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ - (NSArray *)reverse {
return self.reverseObjectEnumerator.allObjects;
}

- (NSArray *)compact {
id resultValues[self.count];
int count = 0;
for (id el in self) {
if (el != [NSNull null])
resultValues[count++] = el;
}
return [NSArray arrayWithObjects:resultValues count:count];
}

#pragma mark - Set operations

- (NSArray *)intersectionWithArray:(NSArray *)array {
Expand Down
3 changes: 3 additions & 0 deletions Classes/NSDictionary+ObjectiveSugar.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

@interface NSDictionary (ObjectiveSugar)

+ (NSDictionary *)dictionaryByMerging:(NSDictionary *) dict1 with:(NSDictionary *) dict2;
- (NSDictionary *)dictionaryByMergingWith:(NSDictionary *)dict;

- (void)each:(void (^)(id key, id value))block;
- (void)eachKey:(void (^)(id key))block;
- (void)eachValue:(void (^)(id value))block;
Expand Down
22 changes: 22 additions & 0 deletions Classes/NSDictionary+ObjectiveSugar.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@

@implementation NSDictionary (Rubyfy)

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2
{
NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];

[dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
if ([dict1 objectForKey:key]) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
[result setObject: newVal forKey: key];
}
} else {
[result setObject: obj forKey: key];
}
}];

return (NSDictionary *) result;
}
- (NSDictionary *)dictionaryByMergingWith:(NSDictionary *)dict
{
return [NSDictionary dictionaryByMerging:self with:dict];
}

- (void)each:(void (^)(id k, id v))block {
[self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
block(key, obj);
Expand Down
73 changes: 73 additions & 0 deletions Classes/NSObject+ObjectiveSugar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// NSObject+Additions.h
// TenzingCore
//
// Created by Endika Gutiérrez Salas on 10/16/12.
// Copyright (c) 2012 Tenzing. All rights reserved.
//

#import <Foundation/Foundation.h>

#define $(sel) (@selector(sel))
#define $_(sel) ([NSValue valueWithPointer:(@selector(sel))])

@interface NSObject (Additions)

- (id)initWithValuesInDictionary:(NSDictionary *)dict;

- (NSDictionary *)asDictionary;

- (id)trySelector:(SEL)selector;
- (id)trySelector:(SEL)selector withObject:(id)obj;
- (id)trySelector:(SEL)selector withObject:(id)obj0 withObject:(id)obj1;

+ (void)defineMethod:(SEL)selector do:(id(^)(id _self, ...))implementation;
+ (void)defineClassMethod:(SEL)selector do:(id(^)(id _self, ...))implementation;

+ (Class)subclass:(NSString *)className;

/**
Inspects all instance methods for calling class

@return an array of strings containing all instance methods for calling class

*/
+ (NSArray *)instanceMethods;

/**
* Inspects all instance methods for calling class
*
* @return an array of strings containing all instance methods for calling class
*/
+ (NSArray *)classMethods;

/**
* Inspects all class methods for calling class
*
* @return an array of strings containing all class methods for calling class
*/
+ (NSArray *)instanceProperties;

/**
* Inspects class of a given property. Checks class of property NOT class of object at property.
*
* @return class of property or nil if class does not has property or if it is not object
*/
+ (Class)classForProperty:(NSString *)propertyName;

/**
* Inspects type of a given property and returns it's code.
* See https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
*
* @return char with type encoding
*/
+ (char)typeForProperty:(NSString *)propertyName;

/**
* Checks if object has property
*
* @return true if object has property with name
*/
+ (BOOL)hasProperty:(NSString *)propertyName;

@end
216 changes: 216 additions & 0 deletions Classes/NSObject+ObjectiveSugar.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//
// NSObject+Additions.m
// TenzingCore
//
// Created by Endika Gutiérrez Salas on 10/16/12.
// Copyright (c) 2012 Tenzing. All rights reserved.
//

#import "NSObject+Additions.h"

#import <objc/runtime.h>
#import "NSArray+Additions.h"

@implementation NSObject (Additions)

- (id)initWithValuesInDictionary:(NSDictionary *)dict
{
self = [self init];
if (self) {
for (NSString *key in dict) {

@try {
NSObject *value = dict[key];

if ([value isKindOfClass:NSNull.class]) {
value = nil;

// Encode recursively objects
} else if ([value isKindOfClass:[NSDictionary class]]) {
Class class = [self.class classForProperty:key];
if (class && class != [NSDictionary class]) {
value = [[class alloc] initWithValuesInDictionary:(NSDictionary *) value];
}
} else if ([value isKindOfClass:[NSArray class]]) {
Class class = [self trySelector:NSSelectorFromString([NSString stringWithFormat:@"%@Class", key])];
if (class && class != [NSArray class]) {
value = [(NSArray *) value transform:^id(id obj) {
return [obj isKindOfClass:[NSDictionary class]]
? [[class alloc] initWithValuesInDictionary:obj]
: obj;
}];
}
}
[self setValue:value forKey:key];
}
@catch (NSException *exception) {
// Do nothing
}

}
}
return self;
}

- (NSDictionary *)asDictionary
{
NSArray *properties = [self.class instanceProperties];

return [properties map:^id(NSString *property) {
id value = [self valueForKey:property];
//char type = [self.class typeForProperty:property];

if ([value isKindOfClass:NSArray.class]) {
value = [(NSArray *) value transform:^id(id obj) {
return ([obj isKindOfClass:NSString.class]
|| [obj isKindOfClass:NSNumber.class]
|| [obj isKindOfClass:NSDictionary.class]
|| [obj isKindOfClass:NSDate.class]
|| [obj isKindOfClass:NSNull.class])
? obj
: [obj asDictionary];
}];

} else if (!([value isKindOfClass:NSString.class]
|| [value isKindOfClass:NSNumber.class]
|| [value isKindOfClass:NSDictionary.class]
|| [value isKindOfClass:NSDate.class]
|| [value isKindOfClass:NSNull.class])) {

value = [value asDictionary];
}
return value;
}];
}

- (id)trySelector:(SEL)selector
{
if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
return [self performSelector:selector];
#pragma clang diagnostic pop
}
return nil;
}

- (id)trySelector:(SEL)selector withObject:(id)obj
{
if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
return [self performSelector:selector withObject:obj];
#pragma clang diagnostic pop
}
return nil;
}

- (id)trySelector:(SEL)selector withObject:(id)obj0 withObject:(id)obj1
{
if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
return [self performSelector:selector withObject:obj0 withObject:obj1];
#pragma clang diagnostic pop
}
return nil;
}

+ (void)defineMethod:(SEL)selector do:(id(^)(id _self, ...))implementation
{
class_addMethod(self, selector, imp_implementationWithBlock(implementation), "@@:@");
}

+ (void)defineClassMethod:(SEL)selector do:(id(^)(id _self, ...))implementation
{
class_addMethod(object_getClass(self), selector, imp_implementationWithBlock(implementation), "@@:@");
}

+ (Class)subclass:(NSString *)className
{
return objc_allocateClassPair(object_getClass(self), [className cStringUsingEncoding:NSUTF8StringEncoding], 0);
}

+ (NSArray *)instanceMethods
{
unsigned int count;
Method *methods = class_copyMethodList(self, &count);
NSString *methodsNames[count];

for (int i = 0; i < count; ++i) {
methodsNames[i] = NSStringFromSelector(method_getName(methods[i]));
}

return [NSArray arrayWithObjects:methodsNames count:count];
}

+ (NSArray *)classMethods
{
return [object_getClass(self) instanceMethods];
}

+ (NSArray *)instanceProperties
{
unsigned int count;
objc_property_t *properties = class_copyPropertyList(self, &count);
NSString *propertiesNames[count];

for (int i = 0; i < count; ++i) {
propertiesNames[i] = [NSString stringWithUTF8String:property_getName(properties[i])];
}

return [NSArray arrayWithObjects:propertiesNames count:count];
}

+ (Class)classForProperty:(NSString *)propertyName
{
objc_property_t property = class_getProperty(self, [propertyName cStringUsingEncoding:NSUTF8StringEncoding]);
if (!property)
return nil; // No property
const char *attr = property_getAttributes(property);
if (!attr)
return nil; // No class

NSString *attributes = [NSString stringWithUTF8String:attr];

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"T@\\\"[^\\\"]+\\\""
options:0
error:&error];
NSRange range = [regex rangeOfFirstMatchInString:attributes options:0 range:NSMakeRange(0, attributes.length)];

if (range.location == NSNotFound || range.length < 4)
return nil; // No class

NSString *type = [attributes substringWithRange:NSMakeRange(range.location + 3, range.length - 4)];

return NSClassFromString(type);
}

+ (char)typeForProperty:(NSString *)propertyName
{
objc_property_t property = class_getProperty(self, [propertyName cStringUsingEncoding:NSUTF8StringEncoding]);
const char *attr = property_getAttributes(property);
if (!attr)
return 0;

NSString *attributes = [NSString stringWithUTF8String:attr];

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"T."
options:0
error:&error];
NSRange range = [regex rangeOfFirstMatchInString:attributes options:0 range:NSMakeRange(0, attributes.length)];

if (range.location == NSNotFound || range.length < 2)
return 0;

return [attributes characterAtIndex:range.location + 1];
}

+ (BOOL)hasProperty:(NSString *)propertyName
{
return (BOOL) class_getProperty(self, [propertyName cStringUsingEncoding:NSUTF8StringEncoding]);
}

@end