├── .gitattributes
├── .gitignore
├── GHKit.podspec
├── GHKit.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── GHKit.xccheckout
├── GHKit
├── GHKit.h
├── GHKitDefines.h
├── GHNSArray+Utils.h
├── GHNSArray+Utils.m
├── GHNSBundle+Utils.h
├── GHNSBundle+Utils.m
├── GHNSData+Utils.h
├── GHNSData+Utils.m
├── GHNSDate+Formatters.h
├── GHNSDate+Formatters.m
├── GHNSDate+Utils.h
├── GHNSDate+Utils.m
├── GHNSDictionary+NSNull.h
├── GHNSDictionary+NSNull.m
├── GHNSDictionary+Utils.h
├── GHNSDictionary+Utils.m
├── GHNSError+Utils.h
├── GHNSError+Utils.m
├── GHNSFileManager+Utils.h
├── GHNSFileManager+Utils.m
├── GHNSMutableArray+Utils.h
├── GHNSMutableArray+Utils.m
├── GHNSMutableDictionary+Utils.h
├── GHNSMutableDictionary+Utils.m
├── GHNSNotificationCenter+Utils.h
├── GHNSNotificationCenter+Utils.m
├── GHNSNumber+Utils.h
├── GHNSNumber+Utils.m
├── GHNSObject+Utils.h
├── GHNSObject+Utils.m
├── GHNSString+TimeInterval.h
├── GHNSString+TimeInterval.m
├── GHNSString+URL.h
├── GHNSString+URL.m
├── GHNSString+Utils.h
├── GHNSString+Utils.m
├── GHNSStringEnumerator.h
├── GHNSStringEnumerator.m
├── GHNSURL+Utils.h
├── GHNSURL+Utils.m
├── GHNSUserDefaults+Utils.h
├── GHNSUserDefaults+Utils.m
├── GHReversableDictionary.h
├── GHReversableDictionary.m
├── GHValidators.h
├── GHValidators.m
├── Info.plist
└── iOS
│ ├── GHCGUtils.h
│ ├── GHCGUtils.m
│ ├── GHUIColor+Utils.h
│ ├── GHUIColor+Utils.m
│ ├── GHUIImage+Utils.h
│ ├── GHUIImage+Utils.m
│ ├── GHUIUtils.h
│ ├── GHUIUtils.m
│ └── Info.plist
├── LICENSE
├── README.md
└── Tests
├── GHDefinesTest.m
├── GHNSStringEnumeratorTest.m
├── GHReversableDictionaryTest.m
├── GHValidatorsTest.m
├── Info.plist
├── NSArrayUtilsTest.m
├── NSDataUtilsTest.m
├── NSDateParsingTest.m
├── NSDateUtilsTest.m
├── NSDictionaryNSNullTest.m
├── NSDictionaryUtilsTest.m
├── NSErrorUtilsTest.m
├── NSFileManagerUtilsTest.m
├── NSMutableArrayUtilsTest.m
├── NSMutableDictionaryUtilsTest.m
├── NSNumberUtilsTest.m
├── NSObjectUtilsTest.m
├── NSStringTimeIntervalTest.m
├── NSStringUtilsTest.m
├── NSURLUtilsTest.m
└── iOS
├── GHUIColorUtilsTest.m
├── GHUIImageUtilsTest.m
└── Info.plist
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -crlf -diff -merge
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .DS_Store
3 | *.pbxuser
4 | *.mode1v3
5 | xcuserdata
6 | Documentation/output
7 | GHKit.docset
8 | GHKitIPhone.xcodeproj/project.xcworkspace/xcuserdata
9 | Project-iOS/build
10 | Project-iOS/Documentation
11 | tmp
12 | GHKit.xcworkspace/xcuserdata
13 | Pods
14 |
--------------------------------------------------------------------------------
/GHKit.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "GHKit"
4 | s.version = "2.0.3"
5 | s.summary = "Objective-C categories and utilities"
6 | s.homepage = "https://github.com/gabriel/GHKit"
7 | s.license = "MIT"
8 | s.author = { "Gabriel Handford" => "gabrielh@gmail.com" }
9 | s.source = { :git => "https://github.com/gabriel/GHKit.git", :tag => s.version.to_s }
10 |
11 | s.ios.platform = :ios, "7.0"
12 | s.ios.deployment_target = "7.0"
13 | s.ios.source_files = "GHKit", "GHKit/iOS"
14 |
15 | s.osx.platform = :osx, "10.8"
16 | s.osx.deployment_target = "10.8"
17 | s.osx.source_files = "GHKit"
18 |
19 | s.requires_arc = true
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/GHKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GHKit.xcodeproj/project.xcworkspace/xcshareddata/GHKit.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 15693D2D-7570-4673-8BBF-E3E5B66EA5D3
9 | IDESourceControlProjectName
10 | GHKit
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | FCF1318D7FA6CAB10513AC324A1290B93E7E7F64
14 | github.com:gabriel/gh-kit.git
15 |
16 | IDESourceControlProjectPath
17 | GHKit.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | FCF1318D7FA6CAB10513AC324A1290B93E7E7F64
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | github.com:gabriel/gh-kit.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | FCF1318D7FA6CAB10513AC324A1290B93E7E7F64
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | FCF1318D7FA6CAB10513AC324A1290B93E7E7F64
36 | IDESourceControlWCCName
37 | gh-kit
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/GHKit/GHKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHKit.h
3 | //
4 | // Created by Gabe on 6/30/08.
5 | //
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | #import
29 |
30 | //! Project version number for GHKit.
31 | FOUNDATION_EXPORT double GHKitVersionNumber;
32 |
33 | //! Project version string for Testing.
34 | FOUNDATION_EXPORT const unsigned char GHKitVersionString[];
35 |
36 | #import
37 |
38 | #import
39 | #import
40 |
41 | #import
42 |
43 | #import
44 | #import
45 | #import
46 |
47 | #import
48 |
49 | #import
50 |
51 | #import
52 |
53 | #import
54 | #import
55 | #import
56 | #import
57 | #import
58 |
59 | #import
60 | #import
61 | #import
62 |
63 | #import
64 |
65 | #import
66 | #import
67 |
68 | #import
69 | #import
70 |
71 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
72 | #import
73 | #import
74 | #import
75 | #import
76 | #endif
77 |
78 |
--------------------------------------------------------------------------------
/GHKit/GHKitDefines.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHKitDefines.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/28/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #define GHDict(...) [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:__VA_ARGS__, nil]
31 |
32 | #define GHCGRectToString(rect) NSStringFromRect(NSRectFromCGRect(rect))
33 | #define GHCGSizeToString(size) NSStringFromSize(NSSizeFromCGSize(size))
34 | #define GHCGPointToString(point) NSStringFromPoint(NSPointFromCGPoint(point))
35 |
36 | #define XCTAssertMainThread() NSAssert([NSThread isMainThread], @"Should be on main thread")
37 |
38 | // Default epsilon for float comparisons
39 | #define GH_EPSILON 1.0E-5
40 |
41 | #define GHProperties(obj, ...) [[obj dictionaryWithValuesForKeys:[NSArray arrayWithObjects:__VA_ARGS__, nil]] description]
42 |
43 | // Makes it easier to generate descriptions
44 | // - (NSString *)description {
45 | // return GHDescription(@"prop1", @"prop2", @"prop3");
46 | // }
47 | #define GHDescription(...) \
48 | [NSString stringWithFormat:@"%@ %@", \
49 | [super description], \
50 | [[self dictionaryWithValuesForKeys:[NSArray arrayWithObjects:__VA_ARGS__, nil]] description] \
51 | ]
52 |
53 | //
54 | // Creates arguments NSArray from var args, with first object named 'object'
55 | // - (void)methodName:(id)arg1 withObjects:object, ...
56 | //
57 | #define GHConvertVarArgs(object) \
58 | NSMutableArray *arguments = [NSMutableArray array]; \
59 | do { \
60 | id arg; \
61 | va_list args; \
62 | if (object) { \
63 | [arguments addObject:object]; \
64 | va_start(args, object); \
65 | while ((arg = va_arg(args, id))) \
66 | [arguments addObject:arg]; \
67 | va_end(args); \
68 | } \
69 | } while(0);
70 |
71 | /*!
72 | Macro defaults.
73 | */
74 | #undef GHDebug
75 | #define GHDebug(fmt, ...) do {} while(0)
76 | #undef GHErr
77 | #define GHErr(fmt, ...) do {} while(0)
78 |
79 | /*!
80 | Logging macros.
81 | */
82 | #if DEBUG
83 | #undef GHDebug
84 | #define GHDebug(fmt, ...) NSLog((@"%s:%d: " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
85 | #undef GHErr
86 | #define GHErr(fmt, ...) NSLog((@"%s:%d: " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
87 | #endif
88 |
89 | /*!
90 | Time.
91 | */
92 | #define GHTimeIntervalMinute (60)
93 | #define GHTimeIntervalHour (GHTimeIntervalMinute * 60)
94 | #define GHTimeIntervalDay (GHTimeIntervalHour * 24)
95 | #define GHTimeIntervalWeek (GHTimeIntervalDay * 7)
96 | #define GHTimeIntervalYear (GHTimeIntervalDay * 365.242199)
97 | #define GHTimeIntervalMax (DBL_MAX)
98 |
99 | /*!
100 | For when you need a weak reference of an object, example: `GHWeakObject(obj) wobj = obj;`
101 | */
102 | #define GHWeakObject(o) __typeof__(o) __weak
103 |
104 | /*!
105 | For when you need a weak reference to self, example: `GHWeakSelf wself = self;`
106 | */
107 | #define GHWeakSelf GHWeakObject(self)
108 |
109 | typedef void (^GHTargetBlock)(id sender);
110 |
111 | #define GHNSError(CODE, MESSAGE) [NSError errorWithDomain:NSStringFromClass([self class]) code:CODE userInfo:@{NSLocalizedDescriptionKey:MESSAGE}]
112 |
113 | #define GHMakeError(CODE, fmt, ...) [NSError errorWithDomain:NSStringFromClass(self.class) code:CODE userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:fmt, ##__VA_ARGS__]}]
114 |
115 | #define GHOrNull(obj) (obj ? obj : NSNull.null)
116 |
117 | #define GHIfNull(obj, val) ([obj isEqual:NSNull.null] ? val : obj)
118 |
119 | #define GHEquals(obj1, obj2) ((!obj1 && !obj2) || [obj1 isEqual:obj2])
120 |
121 | #define GHNSStringFromNSData(data) ([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding])
122 | #define GHNSDataFromNSString(str) ([str dataUsingEncoding:NSUTF8StringEncoding])
123 |
124 | #define GHNSDataFromBase64String(str) ([[NSData alloc] initWithBase64EncodedString:str options:0])
125 | #define GHBase64StringFromNSData(data) ([data base64EncodedStringWithOptions:0])
126 |
127 |
--------------------------------------------------------------------------------
/GHKit/GHNSArray+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSArray+Utils.h
3 | // Created by Gabriel Handford on 12/11/08.
4 | //
5 | // Permission is hereby granted, free of charge, to any person
6 | // obtaining a copy of this software and associated documentation
7 | // files (the "Software"), to deal in the Software without
8 | // restriction, including without limitation the rights to use,
9 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the
11 | // Software is furnished to do so, subject to the following
12 | // conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | // OTHER DEALINGS IN THE SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | /*!
30 | Utilities for arrays.
31 | */
32 | @interface NSArray(GHUtils)
33 |
34 | /*!
35 | First object or nil if array is empty.
36 |
37 | @result Object at index 0
38 | */
39 | - (id)gh_firstObject;
40 |
41 | /*!
42 | Random object in the array.
43 | Uses arc4random_uniform.
44 |
45 | @result Random object
46 | */
47 | - (id)gh_randomObject;
48 |
49 | /*!
50 | Return new reversed array.
51 | Use reverseObjectEnumerator if you want to enumerate values in reverse.
52 |
53 | @result Reversed array
54 | */
55 | - (NSArray *)gh_arrayByReversingArray;
56 |
57 | /*!
58 | Safe subarrayWithRange that checks range.
59 | If the length is out of bounds will return all elements from location to the end.
60 | If the location is out of bounds will return nil.
61 |
62 | @param range Range
63 | @result Sub-array
64 | */
65 | - (NSArray *)gh_subarrayWithRange:(NSRange)range;
66 |
67 | /*!
68 | Get sub-array from location to end.
69 |
70 | @param location Index
71 | @result Sub-array
72 | */
73 | - (NSArray *)gh_subarrayFromLocation:(NSInteger)location;
74 |
75 | /*!
76 | Remove all instances of NSNull.
77 |
78 | @result New array with NSNull instances removed. Returns self if no NSNull's were found.
79 | */
80 | - (NSArray *)gh_compact;
81 |
82 | /*!
83 | Safe array with object.
84 |
85 | @param obj Object
86 | @result Array with object. Returns empty if obj is nil.
87 | */
88 | + (NSArray *)gh_arrayWithObject:(id)obj;
89 |
90 | /*!
91 | Safe object at index.
92 |
93 | @param index Index
94 | @result Object at index, or nil if index < 0 or >= count
95 | */
96 | - (id)gh_objectAtIndex:(NSInteger)index;
97 |
98 | /*!
99 | Safe object at index with default.
100 |
101 | @param index Index
102 | @param withDefault Default if not found
103 | @result Object at index, or default value if index < 0 or >= count
104 | */
105 | - (id)gh_objectAtIndex:(NSInteger)index withDefault:(id)withDefault;
106 |
107 | /*!
108 | Filter array.
109 | @param filterBlock Filter block
110 | */
111 | - (NSArray *)gh_filter:(BOOL(^)(id obj, NSInteger index))filterBlock;
112 |
113 | /*!
114 | Convert array to JSON string.
115 | */
116 | - (NSString *)gh_toJSON:(NSJSONWritingOptions)options error:(NSError **)error;
117 |
118 | /*!
119 | Except last object.
120 | */
121 | - (NSArray *)gh_exceptLast;
122 |
123 | /*!
124 | Uniqify (de-dupe) an array.
125 | */
126 | - (NSArray *)gh_uniq;
127 |
128 | /*!
129 | New array with object removed.
130 | */
131 | - (NSArray *)gh_arrayByRemovingObject:(id)obj;
132 |
133 | /*!
134 | Array from arrays.
135 | */
136 | + (NSArray *)gh_arrayWithArrays:(NSArray *)arrays;
137 |
138 | @end
139 |
--------------------------------------------------------------------------------
/GHKit/GHNSArray+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSArray+Utils.m
3 | // Created by Gabriel Handford on 12/11/08.
4 | //
5 | // Permission is hereby granted, free of charge, to any person
6 | // obtaining a copy of this software and associated documentation
7 | // files (the "Software"), to deal in the Software without
8 | // restriction, including without limitation the rights to use,
9 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the
11 | // Software is furnished to do so, subject to the following
12 | // conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | // OTHER DEALINGS IN THE SOFTWARE.
25 | //
26 |
27 | #import "GHNSArray+Utils.h"
28 |
29 | @implementation NSArray(GHUtils)
30 |
31 | - (id)gh_firstObject {
32 | if ([self count] > 0)
33 | return [self objectAtIndex:0];
34 | return nil;
35 | }
36 |
37 | + (NSArray *)gh_arrayWithObject:(id)obj {
38 | if (!obj) return [NSArray array];
39 | return [NSArray arrayWithObject:obj];
40 | }
41 |
42 | - (id)gh_objectAtIndex:(NSInteger)index {
43 | return [self gh_objectAtIndex:index withDefault:nil];
44 | }
45 |
46 | - (id)gh_objectAtIndex:(NSInteger)index withDefault:(id)defaultValue {
47 | if (index >= 0 && index < [self count]) return [self objectAtIndex:index];
48 | return defaultValue;
49 | }
50 |
51 | - (id)gh_randomObject {
52 | if ([self count] == 0) return nil;
53 | NSUInteger count = [self count];
54 | NSAssert(count <= UINT32_MAX, @"Array size is greater than rand supports");
55 | NSUInteger index = arc4random_uniform((int32_t)count);
56 | return [self objectAtIndex:index];
57 | }
58 |
59 | - (NSArray *)gh_arrayByReversingArray {
60 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]];
61 | for(id obj in [self reverseObjectEnumerator]) {
62 | [array addObject:obj];
63 | }
64 | return array;
65 | }
66 |
67 | - (NSArray *)gh_subarrayWithRange:(NSRange)range {
68 | if (range.location >= [self count]) return nil;
69 | NSInteger length = range.length;
70 | if ((range.location + length) >= [self count]) length = [self count] - range.location;
71 |
72 | return [self subarrayWithRange:NSMakeRange(range.location, length)];
73 | }
74 |
75 | - (NSArray *)gh_subarrayFromLocation:(NSInteger)location {
76 | if (location == 0) return self;
77 | if (location >= [self count]) return [NSArray array];
78 | return [self subarrayWithRange:NSMakeRange(location, [self count]-location)];
79 | }
80 |
81 | - (NSArray *)gh_compact {
82 | if ([self count] == 0) return self;
83 | NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:[self count]];
84 | BOOL found = NO;
85 | for(id obj in self) {
86 | if (![obj isEqual:[NSNull null]]) [array addObject:obj];
87 | else found = YES;
88 | }
89 | if (found) {
90 | return array;
91 | } else {
92 | // No NSNulls were found so release array copy and return self
93 | return self;
94 | }
95 | }
96 |
97 | - (NSArray *)gh_uniq {
98 | return [[NSOrderedSet orderedSetWithArray:self] array];
99 | }
100 |
101 | - (NSArray *)gh_filter:(BOOL(^)(id obj, NSInteger index))filterBlock {
102 | id filteredArray = [NSMutableArray arrayWithCapacity:[self count]];
103 | NSInteger i = 0;
104 | for (id obj in self) {
105 | if (filterBlock(obj, i)) {
106 | [filteredArray addObject:obj];
107 | }
108 | i++;
109 | }
110 | return filteredArray;
111 | }
112 |
113 | - (NSString *)gh_toJSON:(NSJSONWritingOptions)options error:(NSError **)error {
114 | NSData *data = [NSJSONSerialization dataWithJSONObject:self options:options error:error];
115 | if (data) return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
116 | return nil;
117 | }
118 |
119 | - (NSArray *)gh_exceptLast {
120 | if (self.count == 0) return self;
121 | if (self.count == 1) return @[];
122 | return [self subarrayWithRange:NSMakeRange(0, self.count - 1)];
123 | }
124 |
125 | - (NSArray *)gh_arrayByRemovingObject:(id)obj {
126 | NSMutableArray *array = [self mutableCopy];
127 | [array removeObject:obj];
128 | return array;
129 | }
130 |
131 | + (NSArray *)gh_arrayWithArrays:(NSArray *)arrays {
132 | NSMutableArray *array = [NSMutableArray array];
133 | for (NSArray *a in arrays) {
134 | [array addObjectsFromArray:a];
135 | }
136 | return array;
137 | }
138 |
139 | @end
140 |
--------------------------------------------------------------------------------
/GHKit/GHNSBundle+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSBundle+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 4/27/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for accessing bundles.
34 | */
35 | @interface NSBundle(GHUtils)
36 |
37 | /*!
38 | Load data from resource.
39 |
40 | @param resource Name of resource, such as "file.txt"
41 | @result NSData
42 | */
43 | - (NSData *)gh_loadDataFromResource:(NSString *)resource;
44 |
45 | /*!
46 | Load string data from resource.
47 |
48 | @param resource Name of resource
49 | @result NSString
50 | */
51 | - (NSString *)gh_loadStringDataFromResource:(NSString *)resource;
52 |
53 | /*!
54 | Get URL for resource.
55 |
56 | @param resource Name of resource
57 | @result URL to resource
58 | */
59 | - (NSURL *)gh_URLForResource:(NSString *)resource;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/GHKit/GHNSBundle+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSBundle+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 4/27/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHNSBundle+Utils.h"
31 |
32 | @implementation NSBundle(GHUtils)
33 |
34 | - (NSData *)gh_loadDataFromResource:(NSString *)resource {
35 | NSParameterAssert(resource);
36 | NSString *resourcePath = [self pathForResource:[resource stringByDeletingPathExtension] ofType:[resource pathExtension]];
37 | if (!resourcePath) [NSException raise:NSInvalidArgumentException format:@"Resource not found: %@", resource];
38 | NSError *error = nil;
39 | NSData *data = [NSData dataWithContentsOfFile:resourcePath options:0 error:&error];
40 | if (error) [NSException raise:NSInvalidArgumentException format:@"Error loading resource at path (%@): %@", resourcePath, error];
41 | return data;
42 | }
43 |
44 | - (NSString *)gh_loadStringDataFromResource:(NSString *)resource {
45 | return [[NSString alloc] initWithData:[self gh_loadDataFromResource:resource] encoding:NSUTF8StringEncoding];
46 | }
47 |
48 | - (NSURL *)gh_URLForResource:(NSString *)resource {
49 | NSParameterAssert(resource);
50 | NSString *resourcePath = [self pathForResource:[resource stringByDeletingPathExtension] ofType:[resource pathExtension]];
51 | return resourcePath ? [NSURL fileURLWithPath:resourcePath] : nil;
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/GHKit/GHNSData+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSData+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/14/14.
6 | // Copyright (c) 2014 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSData (GHUtils)
12 |
13 | /*!
14 | Return hex string for this data.
15 | */
16 | - (NSString *)gh_hexString;
17 |
18 | /*!
19 | Get IP address string from data object.
20 | */
21 | - (NSString *)gh_IPAddressAsString;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/GHKit/GHNSData+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSData+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/14/14.
6 | // Copyright (c) 2014 rel.me. All rights reserved.
7 | //
8 |
9 | #import "GHNSData+Utils.h"
10 | #import
11 |
12 | @implementation NSData (GHUtils)
13 |
14 | - (NSString *)gh_hexString {
15 | if ([self length] == 0) return nil;
16 | NSMutableString *hex = [NSMutableString stringWithCapacity:[self length] * 2];
17 | for (NSUInteger i = 0; i < [self length]; ++i) {
18 | [hex appendFormat:@"%02X", *((uint8_t *)[self bytes] + i)];
19 | }
20 | return hex;
21 | }
22 |
23 | - (NSString *)gh_IPAddressAsString {
24 | struct sockaddr *addr = (struct sockaddr*)[self bytes];
25 | if (addr->sa_family == AF_INET) {
26 | struct sockaddr_in *addr4 = (struct sockaddr_in*) addr;
27 | char addr4CString[INET_ADDRSTRLEN];
28 | if (!inet_ntop(AF_INET, &addr4->sin_addr, addr4CString, INET_ADDRSTRLEN)) {
29 | return nil;
30 | } else {
31 | return [[NSString alloc] initWithUTF8String:addr4CString];
32 | }
33 | } else if (addr->sa_family == AF_INET6) {
34 | struct sockaddr_in6* addr6 = (struct sockaddr_in6*) addr;
35 | char addr6CString[INET6_ADDRSTRLEN];
36 | if (!inet_ntop(AF_INET6, &addr6->sin6_addr, addr6CString, INET6_ADDRSTRLEN)) {
37 | return nil;
38 | } else {
39 | return [[NSString alloc] initWithUTF8String:addr6CString];
40 | }
41 | } else {
42 | return nil;
43 | }
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/GHKit/GHNSDate+Formatters.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDate+Formatters.h
3 | //
4 | // Created by Gabe on 3/18/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Date parsers, formatting and formatters for ISO8601, RFC822, HTTP (RFC1123, RFC850, asctime) and since epoch.
33 | */
34 | @interface NSDate(GHFormatters)
35 |
36 | /*!
37 | Parse ISO8601 date. For example, "2010-10-07T04:25Z".
38 |
39 | @param dateString Date string to parse, eg. "2010-10-07T04:25Z"
40 | @result Date
41 | */
42 | + (NSDate *)gh_parseISO8601:(NSString *)dateString;
43 |
44 | /*!
45 | Parse RFC822 encoded date. For example, 'Wed, 01 Mar 2006 12:00:00 -0400'.
46 |
47 | @param dateString Date string to parse, eg. 'Wed, 01 Mar 2006 12:00:00 -0400'
48 | @result Date
49 | */
50 | + (NSDate *)gh_parseRFC822:(NSString *)dateString;
51 |
52 | /*!
53 | Parse http date. Tries RFC1123, then RFC850, and then ASCTIME.
54 |
55 | HTTP-date = rfc1123-date | rfc850-date | asctime-date
56 |
57 | Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
58 | Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
59 | Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
60 |
61 | @param dateString Date string to parse
62 | @result Date
63 | */
64 | + (NSDate *)gh_parseHTTP:(NSString *)dateString;
65 |
66 | /*!
67 | Parse time since epoch (1970) in seconds.
68 |
69 | @param timeSinceEpoch Seconds since Jan 1970 (epoch); An NSNumber or NSString (responds to doubleValue).
70 | @result NSDate or nil if timeSinceEpoch was nil
71 | */
72 | + (NSDate *)gh_parseTimeSinceEpoch:(id)timeSinceEpoch;
73 |
74 | /*!
75 | Parse time since epoch (1970) in seconds, with default.
76 |
77 | @param timeSinceEpoch Seconds since Jan 1970 (epoch); An NSNumber or NSString (responds to doubleValue)
78 | @param withDefault Default if timeSinceEpoch is nil
79 | @result NSDate or default
80 | */
81 | + (NSDate *)gh_parseTimeSinceEpoch:(id)timeSinceEpoch withDefault:(id)withDefault;
82 |
83 | /*!
84 | Parse time since epoch (1970) in seconds.
85 |
86 | @param timeSinceEpoch Seconds since Jan 1970 (epoch); An NSNumber or NSString (responds to doubleValue)
87 | @param withDefault If timeSinceEpoch is nil, returns this value
88 | @param timeZone If set, the returned Date will be offset from the supplied timestamp by the difference between timeZone and the system time zone
89 | @result NSDate or nil if timeSinceEpoch was nil
90 | */
91 | + (NSDate *)gh_parseTimeSinceEpoch:(id)timeSinceEpoch withDefault:(id)withDefault offsetForTimeZone:(NSTimeZone *)timeZone;
92 |
93 | /*!
94 | Get date formatted for RFC822.
95 |
96 | @result The date string, like "Wed, 01 Mar 2006 12:00:00 -0400"
97 | */
98 | - (NSString *)gh_formatRFC822;
99 |
100 | /*!
101 | Get date formatted for RFC1123 (HTTP date).
102 |
103 | @result The date string, like "Sun, 06 Nov 1994 08:49:37 GMT"
104 | */
105 | - (NSString *)gh_formatHTTP;
106 |
107 | /*!
108 | Get date formatted for ISO8601 (XML date).
109 |
110 | @result The date string, like "2010-10-07T04:25Z"
111 | */
112 | - (NSString *)gh_formatISO8601;
113 |
114 | /*!
115 | Date formatter for ISO8601. For example, '2007-10-18T16:05:10.000Z'.
116 | If this is called from the main thread, a cached date formatter is returned.
117 |
118 | @result Date formatter for ISO8601
119 | */
120 | + (NSArray *)gh_ISO8601DateFormatters;
121 |
122 | /*!
123 | Date formatter for RFC822. For example, 'Wed, 01 Mar 2006 12:00:00 -0400'.
124 | If this is called from the main thread, a cached date formatter is returned.
125 |
126 | @result Date formatter for RFC822
127 | */
128 | + (NSDateFormatter *)gh_RFC822DateFormatter;
129 |
130 | /*!
131 | Date formatter for RFC1123. For example, 'Wed, 01 Mar 2006 12:00:00 GMT'.
132 | If this is called from the main thread, a cached date formatter is returned.
133 |
134 | @result Date formatter for RFC1123
135 | */
136 | + (NSDateFormatter *)gh_RFC1123DateFormatter;
137 |
138 | /*!
139 | Date formatter for RFC850. For example, 'Sunday, 06-Nov-94 08:49:37 GMT'.
140 | If this is called from the main thread, a cached date formatter is returned.
141 |
142 | @result Date formatter for RFC850
143 | */
144 | + (NSDateFormatter *)gh_RFC850DateFormatter;
145 |
146 | /*!
147 | Date formatter for asctime. For example, 'Sun Nov 6 08:49:37 1994'.
148 | If this is called from the main thread, a cached date formatter is returned.
149 |
150 | @result Date formatter for asctime
151 | */
152 | + (NSDateFormatter *)gh_ascTimeDateFormatter;
153 |
154 | @end
155 |
--------------------------------------------------------------------------------
/GHKit/GHNSDate+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDate+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 2/18/09.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSDate+Utils.h"
30 | #import "GHNSString+TimeInterval.h"
31 |
32 | // Common date formats
33 | NSString *const kDateFormatShortMonthFullYearTime = @"LLL d, yyyy hh:mm a";
34 |
35 | @implementation NSDate(GHUtils)
36 |
37 | NSUInteger const kUnitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday;
38 |
39 | + (NSDate *)_gh_dateFromDate:(NSDate *)date day:(NSInteger)day month:(NSInteger)month year:(NSInteger)year
40 | addDay:(NSInteger)addDay addMonth:(NSInteger)addMonth addYear:(NSInteger)addYear
41 | normalize:(BOOL)normalize timeZone:(NSTimeZone *)timeZone {
42 | NSCalendar *calendar = [NSCalendar currentCalendar];
43 | if (timeZone) {
44 | [calendar setTimeZone:timeZone];
45 | }
46 | NSDateComponents *comps = [calendar components:kUnitFlags fromDate:date];
47 | if (normalize) {
48 | [comps setHour:0];
49 | [comps setMinute:0];
50 | [comps setSecond:0];
51 | }
52 | if (day != 0) [comps setDay:day];
53 | if (month != 0) [comps setMonth:month];
54 | if (year != 0) [comps setYear:year];
55 |
56 | if (addDay != 0) [comps setDay:([comps day] + addDay)];
57 | if (addMonth != 0) [comps setMonth:([comps month] + addMonth)];
58 | if (addYear != 0) [comps setYear:([comps year] + addYear)];
59 |
60 | return [calendar dateFromComponents:comps];
61 | }
62 |
63 | + (NSDate *)gh_dateFromDate:(NSDate *)date addDay:(NSInteger)addDay normalize:(BOOL)normalize {
64 | return [self _gh_dateFromDate:date day:0 month:0 year:0 addDay:addDay addMonth:0 addYear:0
65 | normalize:normalize timeZone:nil];
66 | }
67 |
68 | + (NSDate *)gh_dateWithDay:(NSInteger)day month:(NSInteger)month year:(NSInteger)year
69 | timeZone:(NSTimeZone *)timeZone {
70 | return [self gh_dateWithDay:day month:month year:year addDay:0 addMonth:0 addYear:0 timeZone:timeZone];
71 | }
72 |
73 | + (NSDate *)gh_dateWithDay:(NSInteger)day month:(NSInteger)month year:(NSInteger)year
74 | addDay:(NSInteger)addDay addMonth:(NSInteger)addMonth addYear:(NSInteger)addYear
75 | timeZone:(NSTimeZone *)timeZone {
76 | return [self _gh_dateFromDate:[NSDate date] day:day month:month year:year addDay:addDay addMonth:addMonth addYear:addYear
77 | normalize:YES timeZone:timeZone];
78 |
79 | }
80 |
81 | - (NSDateComponents *)gh_dateComponentsFromFlags:(NSUInteger)flags timeZone:(NSTimeZone *)timeZone {
82 | NSCalendar *calendar = [NSCalendar currentCalendar];
83 | if (timeZone) {
84 | [calendar setTimeZone:timeZone];
85 | }
86 | return [calendar components:flags fromDate:self];
87 | }
88 |
89 | - (NSInteger)gh_day {
90 | return [self gh_dayForTimeZone:nil];
91 | }
92 |
93 | - (NSInteger)gh_dayForTimeZone:(NSTimeZone *)timeZone {
94 | return [[self gh_dateComponentsFromFlags:NSCalendarUnitDay timeZone:timeZone] day];
95 | }
96 |
97 | - (NSInteger)gh_month {
98 | return [self gh_monthForTimeZone:nil];
99 | }
100 |
101 | - (NSInteger)gh_monthForTimeZone:(NSTimeZone *)timeZone {
102 | return [[self gh_dateComponentsFromFlags:NSCalendarUnitMonth timeZone:timeZone] month];
103 | }
104 |
105 | - (NSInteger)gh_year {
106 | return [self gh_yearForTimeZone:nil];
107 | }
108 |
109 | - (NSInteger)gh_yearForTimeZone:(NSTimeZone *)timeZone {
110 | return [[self gh_dateComponentsFromFlags:NSCalendarUnitYear timeZone:timeZone] year];
111 | }
112 |
113 | + (NSArray *)gh_monthSymbols {
114 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
115 | NSArray *monthSymbols = [dateFormatter standaloneMonthSymbols];
116 | return monthSymbols;
117 | }
118 |
119 | - (NSDate *)gh_addDays:(NSInteger)days {
120 | NSCalendar *calendar = [NSCalendar currentCalendar];
121 | NSDateComponents *comps = [calendar components:kUnitFlags fromDate:self];
122 | if (days != 0) [comps setDay:[comps day] + days];
123 | return [calendar dateFromComponents:comps];
124 | }
125 |
126 | - (NSDate *)gh_beginningOfDay {
127 | return [NSDate gh_dateFromDate:self addDay:0 normalize:YES];
128 | }
129 |
130 | + (NSDate *)gh_yesterday {
131 | return [NSDate gh_dateFromDate:[NSDate date] addDay:-1 normalize:YES];
132 | }
133 |
134 | + (NSDate *)gh_tomorrow {
135 | return [NSDate gh_dateFromDate:[NSDate date] addDay:1 normalize:YES];
136 | }
137 |
138 | - (BOOL)gh_isTomorrow {
139 | return ([[self gh_beginningOfDay] compare:[NSDate gh_tomorrow]] == NSOrderedSame);
140 | }
141 |
142 | - (BOOL)gh_isToday {
143 | return ([[self gh_beginningOfDay] compare:[[NSDate date] gh_beginningOfDay]] == NSOrderedSame);
144 | }
145 |
146 | - (BOOL)gh_wasYesterday {
147 | return ([[self gh_beginningOfDay] compare:[NSDate gh_yesterday]] == NSOrderedSame);
148 | }
149 |
150 | - (NSString *)gh_weekday:(NSDateFormatter *)formatter {
151 | if ([self gh_isTomorrow]) return NSLocalizedString(@"Tomorrow", nil);
152 | else if ([self gh_isToday]) return NSLocalizedString(@"Today", nil);
153 | else if ([self gh_wasYesterday]) return NSLocalizedString(@"Yesterday", nil);
154 |
155 | if (!formatter) return nil;
156 |
157 | NSInteger weekday = [[[NSCalendar currentCalendar] components:kUnitFlags fromDate:self] weekday] - 1;
158 | return [[formatter weekdaySymbols] objectAtIndex:weekday];
159 | }
160 |
161 | - (NSString *)gh_format:(NSString *)format useWeekday:(BOOL)useWeekday {
162 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
163 | [dateFormatter setDateFormat:format];
164 | NSString *formatted = [dateFormatter stringFromDate:self];
165 | if (useWeekday) {
166 | NSString *specialWeekday = [self gh_weekday:dateFormatter];
167 | formatted = [NSString stringWithFormat:@"%@, %@", specialWeekday, formatted];
168 | }
169 | return formatted;
170 | }
171 |
172 | - (NSString *)gh_timeAgo:(BOOL)includeSeconds {
173 | return [NSString gh_stringForTimeInterval:[self timeIntervalSinceNow] includeSeconds:includeSeconds];
174 | }
175 |
176 | - (NSString *)gh_timeAgoAbbreviated {
177 | return [NSString gh_abbreviatedStringForTimeInterval:[self timeIntervalSinceNow]];
178 | }
179 |
180 | @end
181 |
--------------------------------------------------------------------------------
/GHKit/GHNSDictionary+NSNull.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDictionary+NSNull.h
3 | // Created by Jae Kwon on 5/12/08.
4 | //
5 | // Permission is hereby granted, free of charge, to any person
6 | // obtaining a copy of this software and associated documentation
7 | // files (the "Software"), to deal in the Software without
8 | // restriction, including without limitation the rights to use,
9 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the
11 | // Software is furnished to do so, subject to the following
12 | // conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | // OTHER DEALINGS IN THE SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | /*!
30 | For supporting dictionaries with nil values.
31 | */
32 | @interface NSDictionary(GHNSNull)
33 |
34 | /*!
35 | Create dictionary which supports nil values.
36 | Key is first (instead of value then key). If the value is nil it is stored internally as NSNull,
37 | and when calling objectMaybeNilForKey will return nil.
38 |
39 | For example,
40 |
41 | [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
42 |
43 | @param firstObject Alternating key, value pairs. Terminated when _key_ is nil.
44 | @param ... Keys and objects
45 | @result Dictionary
46 | */
47 | + (id)gh_dictionaryWithKeysAndObjectsMaybeNil:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
48 |
49 | /*!
50 | Create dictionary which supports nil values.
51 | Key is first (instead of value then key). If the value is nil it is stored internally as NSNull,
52 | and when calling objectMaybeNilForKey will return nil.
53 |
54 | For example,
55 |
56 | - (void)setDictionary:(id)key, ... {
57 | va_list args;
58 | va_start(args, key);
59 | [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNilWithKey:key args:args ignoreNilValues:NO];
60 | va_end(args);
61 | }
62 |
63 | @param firstKey First key
64 | @param args Args va_list via va_start
65 | @param ignoreNil If YES, will not store key, value paries where the value is nil
66 | @result Dictionary
67 | */
68 | + (id)gh_dictionaryWithKeysAndObjectsMaybeNilWithKey:(id)firstKey args:(va_list)args ignoreNil:(BOOL)ignoreNil;
69 |
70 | /*!
71 | Create dictionary which supports nil values.
72 | Key is first (instead of value then key). If the value is nil it is stored internally as NSNull,
73 | and when calling objectMaybeNilForKey will return nil.
74 |
75 | For example,
76 |
77 | [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
78 |
79 | @param firstObject... Alternating key, value pairs. Terminated when _key_ is nil.
80 | */
81 |
82 | /*!
83 | Returns objectForKey if you want nil instead of NSNull objects.
84 |
85 | @param key Key
86 | @result Object for key. If object is NSNull, then nil is returned.
87 | */
88 | - (id)gh_objectMaybeNilForKey:(id)key;
89 |
90 | /*!
91 | Same as gh_objectMaybeNilForKey, but checks the class type and if a mismatch returns nil.
92 | */
93 | - (id)gh_objectMaybeNilForKey:(id)key ofClass:(Class)aClass;
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/GHKit/GHNSDictionary+NSNull.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDictionary+NSNull.m
3 | // Created by Jae Kwon on 5/12/08.
4 | //
5 | // Permission is hereby granted, free of charge, to any person
6 | // obtaining a copy of this software and associated documentation
7 | // files (the "Software"), to deal in the Software without
8 | // restriction, including without limitation the rights to use,
9 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the
11 | // Software is furnished to do so, subject to the following
12 | // conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be
15 | // included in all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | // OTHER DEALINGS IN THE SOFTWARE.
25 | //
26 |
27 | #import "GHNSDictionary+NSNull.h"
28 |
29 | @implementation NSDictionary(GHNSNull)
30 |
31 | + (id)gh_dictionaryWithKeysAndObjectsMaybeNilWithKey:(id)firstKey args:(va_list)args ignoreNil:(BOOL)ignoreNil {
32 | if (!firstKey) return [self dictionary];
33 |
34 | NSMutableArray *keys = [[NSMutableArray alloc] init];
35 | NSMutableArray *values = [[NSMutableArray alloc] init];
36 | id key = firstKey;
37 | do {
38 | id value = va_arg(args, id);
39 | if (!value && ignoreNil) {
40 | key = va_arg(args, id);
41 | continue;
42 | }
43 | if (!value) value = [NSNull null];
44 | [keys addObject:key];
45 | [values addObject:value];
46 | key = va_arg(args, id);
47 | } while(key);
48 | NSDictionary *dict = [self dictionaryWithObjects:values forKeys:keys];
49 | return dict;
50 | }
51 |
52 | + (id)gh_dictionaryWithKeysAndObjectsMaybeNil:(id)firstKey, ... {
53 | va_list args;
54 | va_start(args, firstKey);
55 | NSDictionary *dict = [self gh_dictionaryWithKeysAndObjectsMaybeNilWithKey:firstKey args:args ignoreNil:NO];
56 | va_end(args);
57 | return dict;
58 | }
59 |
60 | - (id)gh_objectMaybeNilForKey:(id)key {
61 | id object = [self objectForKey:key];
62 | if (object == [NSNull null] || [object isEqual:[NSNull null]])
63 | return nil;
64 |
65 | return object;
66 | }
67 |
68 | - (id)gh_objectMaybeNilForKey:(id)key ofClass:(Class)aClass {
69 | id obj = [self gh_objectMaybeNilForKey:key];
70 | if (![obj isKindOfClass:aClass]) return nil;
71 | return obj;
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/GHKit/GHNSDictionary+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDictionary+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 3/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for dictionaries.
34 | */
35 | @interface NSDictionary(GHUtils)
36 |
37 | /*!
38 | Get double value for key.
39 |
40 | @param key Key
41 | @param withDefault If value for key is nil or [NSNull null] this default is returned.
42 | @result Double value
43 | */
44 | - (double)gh_doubleForKey:(id)key withDefault:(double)withDefault;
45 |
46 | /*!
47 | Get double value for key.
48 |
49 | @param key Key
50 | @result Double value
51 | */
52 | - (double)gh_doubleForKey:(id)key;
53 |
54 | /*!
55 | Integer for key.
56 |
57 | @param key Key
58 | @param withDefault If value for key is nil or [NSNull null] this default is returned.
59 | @result Integer value
60 | */
61 | - (NSInteger)gh_integerForKey:(id)key withDefault:(NSInteger)withDefault;
62 |
63 | /*!
64 | Integer for key.
65 | If value for key is nil or [NSNull null], 0 is returned.
66 |
67 | @param key Key
68 | @result Integer value
69 | */
70 | - (NSInteger)gh_integerForKey:(id)key;
71 |
72 | /*!
73 | Unsigned integer for key.
74 |
75 | @param key Key
76 | @param withDefault If value for key is nil or [NSNull null] this default is returned.
77 | @result Unsigned integer
78 | */
79 | - (NSUInteger)gh_unsignedIntegerForKey:(id)key withDefault:(NSUInteger)withDefault;
80 |
81 | /*!
82 | Unsigned integer for key.
83 | If value for key is nil or [NSNull null], 0 is returned.
84 |
85 | @param key Key
86 | @result Unsigned integer
87 | */
88 | - (NSUInteger)gh_unsignedIntegerForKey:(id)key;
89 |
90 | /*!
91 | Number for key.
92 | @param key
93 | @result Number
94 | */
95 | - (NSNumber *)gh_numberForKey:(id)key;
96 |
97 | /*!
98 | Number for key with default integer value.
99 |
100 | @param key Key
101 | @param withDefaultInteger If value for key is nil or [NSNull null] this default is returned.
102 | @result Number
103 | */
104 | - (NSNumber *)gh_numberForKey:(id)key withDefaultInteger:(NSInteger)withDefaultInteger;
105 |
106 | /*!
107 | Number for key with default double value.
108 |
109 | @param key Key
110 | @param withDefaultDouble If value for key is nil or [NSNull null] this default is returned.
111 | @result Number
112 | */
113 | - (NSNumber *)gh_numberForKey:(id)key withDefaultDouble:(double)withDefaultDouble;
114 |
115 | /*!
116 | Get BOOL value for key.
117 |
118 | @param key Key
119 | @param withDefault If value for key is nil or [NSNull null] this default is returned.
120 | @result BOOL value
121 | */
122 | - (BOOL)gh_boolForKey:(id)key withDefault:(BOOL)withDefault;
123 |
124 | /*!
125 | Get BOOL value for key.
126 |
127 | @param key Key
128 | @result YES if boolValue; If key not found or is NSNull, returns NO.
129 | */
130 | - (BOOL)gh_boolForKey:(id)key;
131 |
132 | /*!
133 | Get date for key. Value should respond to doubleValue, which should be seconds since epoch GMT.
134 | @param key
135 | */
136 | - (NSDate *)gh_dateForKey:(id)key;
137 |
138 | /*!
139 | Get date for key. Value should respond to doubleValue, which should be seconds since epoch GMT.
140 | @param key
141 | @param withDefaultDate
142 | */
143 | - (NSDate *)gh_dateForKey:(id)key withDefaultDate:(NSDate *)withDefaultDate;
144 |
145 | /*!
146 | Object for key with default value, if entry is NSNull or entry does not exist.
147 |
148 | @param key Key
149 | @param withDefault If value for key is nil or [NSNull null] this default is returned.
150 | @result Value for key with default value, if entry is NSNull or entry does not exist
151 | */
152 | - (id)gh_objectForKey:(id)key withDefault:(id)withDefault;
153 |
154 | /*!
155 | Object for key or NSNull.
156 | Helpful when used with key/value coding.
157 |
158 | @param key Key
159 | @result Value or NSNull#null if not set
160 | */
161 | - (id)gh_objectForKeyOrNSNull:(id)key;
162 |
163 | /*!
164 | Get boolean value (represented by NSNumber).
165 | Usefuly for coercing any object that responds to boolValue into an object for use with Key Value coding.
166 |
167 | @param key Key
168 | @param withDefault Default if value is missing or [NSNull null]
169 | @result Number
170 | */
171 | - (NSNumber *)gh_boolValueForKey:(id)key withDefault:(BOOL)withDefault;
172 |
173 | /*!
174 | Get boolean value (represented by NSNumber).
175 | Usefuly for coercing any object that responds to boolValue into an object for use with Key Value coding.
176 |
177 | @param key Key
178 | @result Number
179 | */
180 | - (NSNumber *)gh_boolValueForKey:(id)key;
181 |
182 | /*!
183 | Get data from base64 string.
184 | @result NSData
185 | */
186 | - (NSData *)gh_dataAsBase64ForKey:(NSString *)key options:(NSDataBase64DecodingOptions)options;
187 |
188 | /*!
189 | Check if dictionary has all keys.
190 |
191 | @param firstKey First key
192 | @param ... Argument list
193 | @result YES if dictionary has all the keys
194 | */
195 | - (BOOL)gh_hasAllKeys:(NSString *)firstKey, ... NS_REQUIRES_NIL_TERMINATION;
196 |
197 | /*!
198 | Return dictionary with subset of keys.
199 |
200 | @param keys Keys
201 | */
202 | - (NSDictionary *)gh_dictionarySubsetWithKeys:(NSArray *)keys;
203 |
204 | /*!
205 | @result Dictionary without entries for keys with NSNull values
206 | */
207 | - (NSDictionary *)gh_compactDictionary;
208 |
209 | /*!
210 | Query string from dictionary.
211 |
212 | Calls [NSURL gh_dictionaryToQueryString:self];
213 | */
214 | - (NSString *)gh_queryString;
215 |
216 | /*!
217 | Create JSON string for dictionary.
218 | */
219 | - (NSString *)gh_toJSON:(NSJSONWritingOptions)options error:(NSError **)error;
220 |
221 | @end
222 |
--------------------------------------------------------------------------------
/GHKit/GHNSDictionary+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSDictionary+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 3/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHNSDictionary+Utils.h"
31 | #import "GHNSDate+Formatters.h"
32 | #import "GHNSURL+Utils.h"
33 |
34 | @implementation NSDictionary(GHUtils)
35 |
36 | - (double)gh_doubleForKey:(id)key withDefault:(double)defaultValue {
37 | id value = [self objectForKey:key];
38 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
39 | return [value doubleValue];
40 | }
41 |
42 | - (double)gh_doubleForKey:(id)key {
43 | return [self gh_doubleForKey:key withDefault:0];
44 | }
45 |
46 | - (NSInteger)gh_integerForKey:(id)key withDefault:(NSInteger)defaultValue {
47 | id value = [self objectForKey:key];
48 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
49 | return [value integerValue];
50 | }
51 |
52 | - (NSInteger)gh_integerForKey:(id)key {
53 | return [self gh_integerForKey:key withDefault:0];
54 | }
55 |
56 | - (NSUInteger)gh_unsignedIntegerForKey:(id)key withDefault:(NSUInteger)defaultValue {
57 | id value = [self objectForKey:key];
58 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
59 | return [value unsignedIntegerValue];
60 | }
61 |
62 | - (NSUInteger)gh_unsignedIntegerForKey:(id)key {
63 | return [self gh_unsignedIntegerForKey:key withDefault:0];
64 | }
65 |
66 | - (NSNumber *)gh_numberForKey:(id)key {
67 | id value = [self objectForKey:key];
68 | if (!value || [value isEqual:[NSNull null]]) return nil;
69 | NSAssert([value isKindOfClass:[NSNumber class]], @"Value must be a NSNumber");
70 | return value;
71 | }
72 |
73 | - (NSNumber *)gh_numberForKey:(id)key withDefaultInteger:(NSInteger)defaultValue {
74 | id value = [self objectForKey:key];
75 | if (!value || [value isEqual:[NSNull null]]) return [NSNumber numberWithInteger:defaultValue];
76 | NSAssert([value isKindOfClass:[NSNumber class]], @"Value must be a NSNumber");
77 | return value;
78 | }
79 |
80 | - (NSNumber *)gh_numberForKey:(id)key withDefaultDouble:(double)defaultValue {
81 | id value = [self objectForKey:key];
82 | if (!value || [value isEqual:[NSNull null]]) return [NSNumber numberWithDouble:defaultValue];
83 | NSAssert([value isKindOfClass:[NSNumber class]], @"Value must be a NSNumber");
84 | return value;
85 | }
86 |
87 | - (NSDate *)gh_dateForKey:(id)key {
88 | return [self gh_dateForKey:key withDefaultDate:nil];
89 | }
90 |
91 | - (NSDate *)gh_dateForKey:(id)key withDefaultDate:(NSDate *)defaultValue {
92 | id value = [self objectForKey:key];
93 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
94 | return [NSDate gh_parseTimeSinceEpoch:value];
95 | }
96 |
97 | - (BOOL)gh_boolForKey:(id)key withDefault:(BOOL)defaultValue {
98 | id value = [self objectForKey:key];
99 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
100 | return [value boolValue];
101 | }
102 |
103 | - (BOOL)gh_boolForKey:(id)key {
104 | return [self gh_boolForKey:key withDefault:NO];
105 | }
106 |
107 | - (NSNumber *)gh_boolValueForKey:(id)key withDefault:(BOOL)defaultValue {
108 | id value = [self objectForKey:key];
109 | if (!value || [value isEqual:[NSNull null]]) return [NSNumber numberWithBool:defaultValue];
110 | return [NSNumber numberWithBool:[value boolValue]];
111 | }
112 |
113 | - (NSNumber *)gh_boolValueForKey:(id)key {
114 | return [self gh_boolValueForKey:key withDefault:NO];
115 | }
116 |
117 | - (NSData *)gh_dataAsBase64ForKey:(NSString *)key options:(NSDataBase64DecodingOptions)options {
118 | id value = [self objectForKey:key];
119 | if (!value || [value isEqual:[NSNull null]]) return nil;
120 | NSAssert([value isKindOfClass:[NSString class]], @"Value must be a Base64 string");
121 | return [[NSData alloc] initWithBase64EncodedString:value options:0];
122 | }
123 |
124 | - (id)gh_objectForKey:(id)key withDefault:(id)defaultValue {
125 | id value = [self objectForKey:key];
126 | if (!value || [value isEqual:[NSNull null]]) return defaultValue;
127 | return value;
128 | }
129 |
130 | - (id)gh_objectForKeyOrNSNull:(id)key {
131 | return [self gh_objectForKey:key withDefault:[NSNull null]];
132 | }
133 |
134 | - (BOOL)gh_hasAllKeys:(NSString *)firstKey, ... {
135 | va_list vl;
136 | va_start(vl, firstKey);
137 | id key = firstKey;
138 | while(key != nil) {
139 | id value = [self objectForKey:key];
140 | if (!value || [value isEqual:[NSNull null]]) return NO;
141 | key = va_arg(vl, NSString *);
142 | }
143 | va_end(vl);
144 | return YES;
145 | }
146 |
147 | - (NSDictionary *)gh_dictionarySubsetWithKeys:(NSArray *)keys {
148 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:[keys count]];
149 | for(id key in keys) {
150 | id value = [self objectForKey:key];
151 | if (value) [dict setObject:value forKey:key];
152 | }
153 | return dict;
154 | }
155 |
156 | - (NSDictionary *)gh_compactDictionary {
157 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
158 | for (id key in self) {
159 | id obj = [self objectForKey:key];
160 | if (obj != [NSNull null])
161 | [dict setObject:obj forKey:key];
162 | }
163 | return dict;
164 | }
165 |
166 | - (NSString *)gh_queryString {
167 | return [NSURL gh_dictionaryToQueryString:self];
168 | }
169 |
170 | - (NSString *)gh_toJSON:(NSJSONWritingOptions)options error:(NSError **)error {
171 | NSData *data = [NSJSONSerialization dataWithJSONObject:self options:options error:error];
172 | if (data) return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
173 | return nil;
174 | }
175 |
176 | @end
177 |
--------------------------------------------------------------------------------
/GHKit/GHNSError+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSError+Utils.h
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 3/9/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for generating errors.
34 | */
35 | @interface NSError(GHUtils)
36 |
37 | /*!
38 | Create error with localized description. (userInfo includes NSLocalizedDescriptionKey=localizedDescription)
39 |
40 | @param domain Domain
41 | @param code Code
42 | @param localizedDescription Localized description
43 | @result NSError
44 | */
45 | + (NSError *)gh_errorWithDomain:(NSString *)domain code:(NSInteger)code localizedDescription:(NSString *)localizedDescription;
46 |
47 | /*!
48 | Create error from exception.
49 |
50 | @param exception Exception
51 | */
52 | + (NSError *)gh_errorFromException:(NSException *)exception;
53 |
54 | /*!
55 | Get full error description, recusively for any errors within the userInfo.
56 | Useful for getting at CoreData validation errors, for example.
57 |
58 | @result Full error description
59 | */
60 | - (NSString *)gh_fullDescription;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/GHKit/GHNSError+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSError+Utils.m
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 3/9/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHNSError+Utils.h"
31 |
32 |
33 | @implementation NSError(GHUtils)
34 |
35 | + (NSError *)gh_errorWithDomain:(NSString *)domain code:(NSInteger)code localizedDescription:(NSString *)localizedDescription {
36 | NSDictionary *userInfo = [NSDictionary dictionaryWithObject:localizedDescription forKey:NSLocalizedDescriptionKey];
37 | return [self errorWithDomain:domain code:code userInfo:userInfo];
38 | }
39 |
40 | + (NSError *)gh_errorFromException:(NSException *)exception {
41 | NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason forKey:NSLocalizedDescriptionKey];
42 | return [self errorWithDomain:exception.name code:-1 userInfo:userInfo];
43 | }
44 |
45 | - (void)gh_fullDescription:(NSMutableString *)errorDescription level:(NSInteger)level {
46 | [errorDescription appendFormat:@"%@\n", [self localizedDescription]];
47 |
48 | if (level > 0) [errorDescription appendString:@"--\n"];
49 | level++;
50 | for(id userInfoKey in [self userInfo]) {
51 | id userInfoEntry = [[self userInfo] objectForKey:userInfoKey];
52 | if (userInfoEntry == self) continue;
53 | [errorDescription appendFormat:@" %@: ", userInfoKey];
54 | if ([userInfoEntry isKindOfClass:[NSArray class]]) {
55 | for(id userInfoEntryItem in userInfoEntry) {
56 | if ([userInfoEntryItem isKindOfClass:[NSError class]]) {
57 | [(NSError *)userInfoEntryItem gh_fullDescription:errorDescription level:level];
58 | } else {
59 | [errorDescription appendFormat:@"%@\n", [userInfoEntryItem description]];
60 | }
61 | }
62 | } else if ([userInfoEntry isKindOfClass:[NSError class]]) {
63 | [(NSError *)userInfoEntry gh_fullDescription:errorDescription level:level];
64 | } else {
65 | [errorDescription appendString:[userInfoEntry description]];
66 | }
67 | }
68 | }
69 |
70 | - (NSString *)gh_fullDescription {
71 | NSMutableString *errorDescription = [[NSMutableString alloc] init];
72 | [self gh_fullDescription:errorDescription level:0];
73 | return errorDescription;
74 | }
75 |
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/GHKit/GHNSFileManager+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSFileManager+Utils.h
3 | //
4 | // Created by Gabe on 3/23/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilities for NSFileManager, for example, file size, exists, generating temporary or unique
33 | file paths.
34 | */
35 | @interface NSFileManager(GHUtils)
36 |
37 | /*!
38 | Get size of file.
39 |
40 | @param filePath Path
41 | @param error Out error
42 | @result File size
43 | */
44 | + (NSNumber *)gh_fileSize:(NSString *)filePath error:(NSError **)error;
45 |
46 | /*!
47 | Check if path is a directory.
48 |
49 | @param filePath Path
50 | @result YES if directory, NO otherwise
51 | */
52 | + (BOOL)gh_isDirectory:(NSString *)filePath;
53 |
54 | /*!
55 | Check if path exists.
56 |
57 | @param filePath Path
58 | @result YES if exists, NO otherwise
59 | */
60 | + (BOOL)gh_exist:(NSString *)filePath;
61 |
62 | /*!
63 | Get path to temporary file.
64 |
65 | @param appendPath Path to append to temporary directory name, if not nil
66 | @param deleteIfExists Will delete existing file if it is in the way
67 | @param error If not nil, will be set if an error occurs
68 | @result Path for temporary file
69 | */
70 | + (NSString *)gh_temporaryFile:(NSString *)appendPath deleteIfExists:(BOOL)deleteIfExists error:(NSError **)error;
71 |
72 | /*!
73 | Get unique filename based on the specified path.
74 | If file does not exist, the same object is returned.
75 | If file does exist a unique variation is returned.
76 |
77 | @param path Path
78 | @result If, for example, foo.txt already exists, will return foo-1.txt, and if that exists foo-2.txt, and so on.
79 | */
80 | + (NSString *)gh_uniquePathWithNumber:(NSString *)path;
81 |
82 | /*!
83 | Ensure directory exists.
84 |
85 | @param directory Directory
86 | @param created Set if was created
87 | @param error If not nil, will set if error occurs
88 | @result YES If directory exists or was created
89 | */
90 | + (BOOL)gh_ensureDirectoryExists:(NSString *)directory created:(BOOL *)created error:(NSError **)error;
91 |
92 | /*!
93 | Path to resource in main bundle.
94 |
95 | @param path Path
96 | @result Full path in resource in main bundle.
97 | */
98 | + (NSString *)gh_pathToResource:(NSString *)path;
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/GHKit/GHNSFileManager+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSFileManager+Utils.m
3 | //
4 | // Created by Gabe on 3/23/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSFileManager+Utils.h"
30 | #import "GHNSString+Utils.h"
31 | #import "GHNSError+Utils.h"
32 |
33 | @implementation NSFileManager(GHUtils)
34 |
35 | + (NSNumber *)gh_fileSize:(NSString *)filePath error:(NSError **)error {
36 | NSFileManager *fileManager = [NSFileManager defaultManager];
37 | BOOL isDir;
38 | if ([fileManager fileExistsAtPath:filePath isDirectory:&isDir] && !isDir) {
39 | NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:error];
40 | if (fileAttributes)
41 | return [fileAttributes objectForKey:NSFileSize];
42 | }
43 | return nil;
44 | }
45 |
46 | + (BOOL)gh_isDirectory:(NSString *)filePath {
47 | BOOL isDir;
48 | return ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDir] && isDir);
49 | }
50 |
51 | + (BOOL)gh_exist:(NSString *)filePath {
52 | return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
53 | }
54 |
55 | + (NSString *)gh_temporaryFile:(NSString *)appendPath deleteIfExists:(BOOL)deleteIfExists error:(NSError **)error {
56 | NSParameterAssert(appendPath);
57 | NSString *tmpFile = NSTemporaryDirectory();
58 | if (appendPath) tmpFile = [tmpFile stringByAppendingPathComponent:appendPath];
59 | if (deleteIfExists && [self gh_exist:tmpFile]) {
60 | [[NSFileManager defaultManager] removeItemAtPath:tmpFile error:error];
61 | }
62 | return tmpFile;
63 | }
64 |
65 | + (BOOL)gh_ensureDirectoryExists:(NSString *)directory created:(BOOL *)created error:(NSError **)error {
66 | if (![self gh_exist:directory]) {
67 | BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:error];
68 | if (success && created) *created = YES;
69 | return success;
70 | } else if (![self gh_isDirectory:directory]) {
71 | if (error) *error = [NSError gh_errorWithDomain:@"GHNSFileManager" code:-1 localizedDescription:@"Path exists but is not a directory"];
72 | return NO;
73 | } else {
74 | // Path existed and was a directory
75 | return YES;
76 | }
77 | }
78 |
79 | + (NSString *)gh_uniquePathWithNumber:(NSString *)path {
80 | NSInteger index = 1;
81 | NSString *uniquePath = path;
82 | NSString *prefixPath = nil, *pathExtension = nil;
83 |
84 | while([self gh_exist:uniquePath]) {
85 | if (!prefixPath) prefixPath = [path stringByDeletingPathExtension];
86 | if (!pathExtension) pathExtension = [path gh_fullPathExtension];
87 | uniquePath = [NSString stringWithFormat:@"%@-%ld%@", prefixPath, (long)index, pathExtension];
88 | index++;
89 | }
90 | return uniquePath;
91 | }
92 |
93 | + (NSString *)gh_pathToResource:(NSString *)path {
94 | if (!path) return nil;
95 | return [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:path];
96 | }
97 |
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/GHKit/GHNSMutableArray+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSMutableArray+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/1/09.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilities for mutable arrays, for example, inserting, replacing at index, and more.
33 | */
34 | @interface NSMutableArray(GHUtils)
35 |
36 | /*!
37 | Insert objects at index.
38 |
39 | @param objects Objects to insert
40 | @param index Index to insert at
41 | */
42 | - (void)gh_insertObjects:(NSArray *)objects atIndex:(NSInteger)index;
43 |
44 | /*!
45 | Replace object with another object.
46 |
47 | @param objectToReplace Object to replace
48 | @param object Object that will replace
49 | @result Index object was set; NSNotFound if objectToReplace was not found
50 | */
51 | - (NSUInteger)gh_replaceObject:(id)objectToReplace withObject:(id)object;
52 |
53 | /*!
54 | Compact.
55 | Remove all instances NSNull.
56 | */
57 | - (void)gh_mutableCompact;
58 |
59 | /*!
60 | Add object. If object is nil, this is a no op.
61 |
62 | @param obj Object to add
63 | */
64 | - (void)gh_addObject:(id)obj;
65 |
66 | /*!
67 | Remove last object.
68 |
69 | @result Last object removed
70 | */
71 | - (id)gh_removeLastObject;
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/GHKit/GHNSMutableArray+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSMutableArray+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/1/09.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSMutableArray+Utils.h"
30 |
31 |
32 | @implementation NSMutableArray(GHUtils)
33 |
34 | - (void)gh_insertObjects:(NSArray *)objects atIndex:(NSInteger)index {
35 | NSIndexSet *indexes = [[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(index, [objects count])];
36 | [self insertObjects:objects atIndexes:indexes];
37 | }
38 |
39 | - (NSUInteger)gh_replaceObject:(id)objectToReplace withObject:(id)object {
40 | NSUInteger index = [self indexOfObject:objectToReplace];
41 | if (index != NSNotFound) {
42 | [self replaceObjectAtIndex:index withObject:object];
43 | }
44 | return index;
45 | }
46 |
47 | - (void)gh_mutableCompact {
48 | [self removeObjectIdenticalTo:[NSNull null]];
49 | }
50 |
51 | - (void)gh_addObject:(id)obj {
52 | if (obj) [self addObject:obj];
53 | }
54 |
55 | - (id)gh_removeLastObject {
56 | id obj = [self lastObject];
57 | if (obj) [self removeLastObject];
58 | return obj;
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/GHKit/GHNSMutableDictionary+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSMutableDictionary+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 3/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for NSMutableDictionary.
34 | */
35 | @interface NSMutableDictionary(GHUtils)
36 |
37 | /*!
38 | Set double value.
39 |
40 | @param d Double
41 | @param forKey Key
42 | */
43 | - (void)gh_setDouble:(double)d forKey:(id)forKey;
44 |
45 | /*!
46 | Set integer value.
47 |
48 | @param n Integer
49 | @param forKey Key
50 | */
51 | - (void)gh_setInteger:(NSInteger)n forKey:(id)forKey;
52 |
53 | /*!
54 | Set bool.
55 |
56 | @param b Bool
57 | @param forKey Key
58 | */
59 | - (void)gh_setBool:(BOOL)b forKey:(id)forKey;
60 |
61 | /*!
62 | Set object or [NSNull null] if nil.
63 |
64 | @param object Object
65 | @param forKey Key
66 | */
67 | - (void)gh_setObjectMaybeNil:(id)object forKey:(id)forKey;
68 |
69 | /*!
70 | Compact.
71 | Remove all value with instances NSNull.
72 | */
73 | - (void)gh_mutableCompact;
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/GHKit/GHNSMutableDictionary+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSMutableDictionary+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 3/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHNSMutableDictionary+Utils.h"
31 |
32 | @implementation NSMutableDictionary(GHUtils)
33 |
34 | - (void)gh_setDouble:(double)d forKey:(id)key {
35 | [self setObject:[NSNumber numberWithDouble:d] forKey:key];
36 | }
37 |
38 | - (void)gh_setInteger:(NSInteger)n forKey:(id)key {
39 | [self setObject:[NSNumber numberWithInteger:n] forKey:key];
40 | }
41 |
42 | - (void)gh_setBool:(BOOL)b forKey:(id)key {
43 | [self setObject:[NSNumber numberWithBool:b] forKey:key];
44 | }
45 |
46 | - (void)gh_setObjectMaybeNil:(id)object forKey:(id)key {
47 | if (!object) object = [NSNull null];
48 | [self setObject:object forKey:key];
49 | }
50 |
51 | - (void)gh_mutableCompact {
52 | NSMutableArray *keysToRemove = [[NSMutableArray alloc] init];
53 | for (id key in self) {
54 | if ([[self objectForKey:key] isEqual:[NSNull null]])
55 | [keysToRemove addObject:key];
56 | }
57 | [self removeObjectsForKeys:keysToRemove];
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/GHKit/GHNSNotificationCenter+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSNotificationCenter+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 12/7/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for NSNotificationCenter.
34 | */
35 | @interface NSNotificationCenter(GHUtils)
36 |
37 | /*!
38 | Replace observer. If present, it removes and re-adds the observer.
39 |
40 | @param observer Observer
41 | @param selector Selector
42 | @param name Name
43 | @param object Object
44 | */
45 | - (void)gh_replaceObserver:(id)observer selector:(SEL)selector name:(NSString *)name object:(id)object;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/GHKit/GHNSNotificationCenter+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSNotificationCenter+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 12/7/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHNSNotificationCenter+Utils.h"
31 |
32 |
33 | @implementation NSNotificationCenter(GHUtils)
34 |
35 | - (void)gh_replaceObserver:(id)observer selector:(SEL)selector name:(NSString *)name object:(id)object {
36 | [self removeObserver:observer name:name object:object];
37 | [self addObserver:observer selector:selector name:name object:object];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/GHKit/GHNSNumber+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSNumber+Utils.h
3 | //
4 | // Created by Gabe on 6/24/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilites for dealing with numbers, for example, human readable file size, ordinals, random numbers.
33 | */
34 | @interface NSNumber(GHUtils)
35 |
36 | /*!
37 | File size label.
38 |
39 | @result '904 b', '32 KB', '1.1 MB',
40 | */
41 | - (NSString *)gh_humanSize;
42 |
43 | /*!
44 | File size label.
45 |
46 | @param delimiter In between numeric and unit
47 | @result '904 b', '32 KB', '1.1 MB',
48 | */
49 | - (NSString *)gh_humanSizeWithDelimiter:(NSString *)delimiter;
50 |
51 | /*!
52 | Ordinalize.
53 |
54 | 0 => nil
55 | 1 => "1st"
56 | 2 => "2nd"
57 | 3 => "3rd"
58 | 4-9 -> "4th", "5th", ...
59 | Ending in 11, 12 or 13 => "111th", "212th", ...
60 |
61 | @result Ordinal string for integer.
62 | */
63 | - (NSString *)gh_ordinalize;
64 |
65 | /*!
66 | Ordinalize (masculine).
67 |
68 | @param masculine If YES will format for masculine
69 | @result Ordinal string for integer
70 | */
71 | - (NSString *)gh_ordinalizeMasculine:(BOOL)masculine;
72 |
73 | /*!
74 | Ordinalize. See gh_ordinalize.
75 |
76 | @param value Value
77 | @result Ordinal string for integer.
78 | */
79 | + (NSString *)gh_ordinalize:(NSInteger)value;
80 |
81 | /*!
82 | Ordinalize. See gh_ordinalizeMasculine:.
83 |
84 | @param value Value
85 | @param masculine If masculine
86 | @result Ordinal string for integer.
87 | */
88 | + (NSString *)gh_ordinalize:(NSInteger)value masculine:(BOOL)masculine;
89 |
90 | /*!
91 | Shared bool number instance.
92 |
93 | @param b Bool
94 | */
95 | + (NSNumber *)gh_bool:(BOOL)b;
96 |
97 | /*!
98 | Shared bool number instance representing NO.
99 | */
100 | + (NSNumber *)gh_no;
101 |
102 | /*!
103 | Shared bool number instance representing NO.
104 | */
105 | + (NSNumber *)gh_yes;
106 |
107 | /*!
108 | Random number.
109 |
110 | @result Random integer
111 | */
112 | + (NSInteger)gh_randomInteger;
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/GHKit/GHNSNumber+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSNumber+Utils.m
3 | //
4 | // Created by Gabe on 6/24/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 |
30 | #import "GHNSNumber+Utils.h"
31 | #import "GHNSArray+Utils.h"
32 |
33 |
34 | @implementation NSNumber(GHUtils)
35 |
36 | - (NSString *)gh_humanSize {
37 | return [self gh_humanSizeWithDelimiter:@" "];
38 | }
39 |
40 | - (NSString *)gh_humanSizeWithDelimiter:(NSString *)delimiter {
41 | double value = [self doubleValue];
42 | double byteTest = 1024;
43 | double kilobyteTest = 1024 * byteTest;
44 | double megaByteTest = 1024 * kilobyteTest;
45 |
46 | if (value < byteTest) {
47 | return [NSString stringWithFormat:@"%.0f%@B", value, delimiter];
48 | } else if (value < kilobyteTest) {
49 | double d = value / byteTest;
50 | return [NSString stringWithFormat:@"%.0f%@KB", d, delimiter];
51 | } else if (value < megaByteTest) {
52 | double d = value / kilobyteTest;
53 | return [NSString stringWithFormat:@"%.1f%@MB", d, delimiter];
54 | } else {
55 | double d = value / megaByteTest;
56 | return [NSString stringWithFormat:@"%.2f%@GB", d, delimiter];
57 | }
58 | return nil;
59 | }
60 |
61 | - (NSString *)gh_ordinalize {
62 | return [NSNumber gh_ordinalize:[self integerValue]];
63 | }
64 |
65 | - (NSString *)gh_ordinalizeMasculine:(BOOL)masculine {
66 | return [NSNumber gh_ordinalize:[self integerValue] masculine:masculine];
67 | }
68 |
69 | + (NSString *)gh_ordinalizeEn:(NSInteger)value {
70 | NSString *suffix = nil;
71 | if (value > 0) {
72 | switch(value % 10) {
73 | case 1: suffix = @"st"; break;
74 | case 2: suffix = @"nd"; break;
75 | case 3: suffix = @"rd"; break;
76 | default: suffix = @"th"; break;
77 | }
78 | if (value % 100 >= 11 && value % 100 <= 13) suffix = @"th"; // Handle 11-13
79 | if (suffix) return [NSString stringWithFormat:@"%ld%@", (long)value, suffix];
80 | }
81 | return [NSString stringWithFormat:@"%ld", (long)value];
82 | }
83 |
84 | // NOTE(johnb): Ignoring plural forms of ordinals (ers / res / es)
85 | + (NSString *)gh_ordinalizeFr:(NSInteger)value masculine:(BOOL)masculine {
86 | NSString *suffix = nil;
87 | switch(value) {
88 | case 0: break;
89 | case 1: suffix = masculine ? @"er" : @"re"; break;
90 | default: suffix = @"e"; break;
91 | }
92 | if (suffix) return [NSString stringWithFormat:@"%ld%@", (long)value, suffix];
93 | return [NSString stringWithFormat:@"%ld", (long)value];
94 | }
95 |
96 | + (NSString *)gh_ordinalizeDe:(NSInteger)value masculine:(BOOL)masculine {
97 | NSString *suffix = nil;
98 | switch (value) {
99 | case 0: break;
100 | default: suffix = masculine ? @"ter" : @"te"; break;
101 | }
102 | if (suffix) return [NSString stringWithFormat:@"%ld%@", (long)value, suffix];
103 | return [NSString stringWithFormat:@"%ld", (long)value];
104 | }
105 |
106 | // NOTE(johnb): Ignoring plural forms or ordinals (os / as)
107 | + (NSString *)gh_ordinalizeEs:(NSInteger)value masculine:(BOOL)masculine {
108 | NSString *suffix = nil;
109 | switch(value) {
110 | case 0: break;
111 | default: suffix = masculine ? @"º" : @"ª"; break;
112 | }
113 | if (suffix) return [NSString stringWithFormat:@"%ld%@", (long)value, suffix];
114 | return [NSString stringWithFormat:@"%ld", (long)value];
115 | }
116 |
117 | // The following OpenOffice wiki page is helpful for information about ordinals
118 | // http://wiki.services.openoffice.org/wiki/Localized_AutoCorrection_of_Ordinal_Numbers_(1st_2nd)#French
119 | + (NSString *)gh_ordinalize:(NSInteger)value masculine:(BOOL)masculine {
120 | NSString *languageCode = [[NSLocale preferredLanguages] gh_firstObject];
121 | if ([languageCode isEqual:@"en"]) {
122 | return [NSNumber gh_ordinalizeEn:value];
123 | } else if ([languageCode isEqual:@"fr"]) {
124 | return [NSNumber gh_ordinalizeFr:value masculine:masculine];
125 | } else if ([languageCode isEqual:@"de"]) {
126 | return [NSNumber gh_ordinalizeDe:value masculine:masculine];
127 | } else if ([languageCode isEqual:@"es"]) {
128 | return [NSNumber gh_ordinalizeEs:value masculine:masculine];
129 | }
130 | return [NSString stringWithFormat:@"%ld", (long)value];
131 | }
132 |
133 | + (NSString *)gh_ordinalize:(NSInteger)value {
134 | return [NSNumber gh_ordinalize:value masculine:YES];
135 | }
136 |
137 | + (NSNumber *)gh_bool:(BOOL)b {
138 | if (!b) {
139 | static NSNumber *NumberForNo = NULL;
140 | if (NumberForNo == NULL) NumberForNo = [NSNumber numberWithBool:NO];
141 | return NumberForNo;
142 | } else {
143 | static NSNumber *NumberForYes = NULL;
144 | if (NumberForYes == NULL) NumberForYes = [NSNumber numberWithBool:YES];
145 | return NumberForYes;
146 | }
147 | }
148 |
149 | + (NSNumber *)gh_no {
150 | return [self gh_bool:NO];
151 | }
152 |
153 | + (NSNumber *)gh_yes {
154 | return [self gh_bool:YES];
155 | }
156 |
157 | + (NSInteger)gh_randomInteger {
158 | double r = (double)arc4random()/INT_MAX;
159 | return NSIntegerMax * r;
160 | }
161 |
162 | @end
163 |
--------------------------------------------------------------------------------
/GHKit/GHNSObject+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSObject+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/8/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Utilities for NSObject.
34 | */
35 | @interface NSObject(GHUtils)
36 |
37 | /*!
38 | Check if not equal to NSNull.
39 | Useful for checking nil and NSNull in a single expression:
40 |
41 | if ([foo gh_isNotNSNull]) { } // Will not evaluate if foo == nil or foo is equal to [NSNull null]
42 |
43 | */
44 | - (BOOL)gh_isNotNSNull;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/GHKit/GHNSObject+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSObject+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/8/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 |
31 | #import "GHNSObject+Utils.h"
32 |
33 |
34 | @implementation NSObject(GHUtils)
35 |
36 | - (BOOL)gh_isNotNSNull {
37 | return ![self isEqual:[NSNull null]];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/GHKit/GHNSString+TimeInterval.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSString+TimeInterval.h
3 | //
4 | // Created by Gabe on 6/6/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilities for generating time ago in words.
33 | */
34 | @interface NSString(GHTimeInterval)
35 |
36 | /*!
37 | Time ago in words.
38 |
39 | For localized values see the localization keys below.
40 | This method calls gh_localizedStringForTimeInterval with nil tableName and [NSBundle mainBundle] bundle.
41 |
42 | @param interval Interval in seconds
43 | @param includeSeconds If YES, will say 'less than N seconds', otherwise will show 'less than a minute'
44 | @result Time ago in words
45 | */
46 | + (NSString *)gh_stringForTimeInterval:(NSTimeInterval)interval includeSeconds:(BOOL)includeSeconds;
47 |
48 | /*!
49 | Time ago in words (localized).
50 |
51 | These are the localized defaults, that you can override:
52 |
53 | LessThanAMinute = "less than a minute";
54 | LessThanXSeconds = "less than %d seconds";
55 | HalfMinute = "half a minute";
56 | 1Minute = "1 minute";
57 | XMinutes = "%.0f minutes";
58 | About1Hour = "about 1 hour";
59 | AboutXHours = "about %.0f hours";
60 | 1Day = "1 day";
61 | XDays = "%.0f days";
62 | About1Month = "about 1 month";
63 | XMonths = "%.0f months";
64 | About1Year = "about 1 year";
65 | OverXYears = "over %.0f years";
66 |
67 | @param interval Interval in seconds
68 | @param includeSeconds If YES, will say 'less than N seconds', otherwise will show 'less than a minute'
69 | @param tableName Table name for localized string
70 | @param bundle Bundle for localized string
71 | @result Time ago in words
72 | */
73 | + (NSString *)gh_localizedStringForTimeInterval:(NSTimeInterval)interval includeSeconds:(BOOL)includeSeconds tableName:(NSString *)tableName bundle:(NSBundle *)bundle;
74 |
75 |
76 |
77 |
78 | /*!
79 | Time ago in abbreviated format.
80 |
81 | For localized values see the localization keys below.
82 | This method calls gh_localizedStringForTimeInterval with nil tableName and [NSBundle mainBundle] bundle.
83 |
84 | @param interval Interval in seconds
85 | @result Time ago in abbreviated format
86 | */
87 | + (NSString *)gh_abbreviatedStringForTimeInterval:(NSTimeInterval)interval;
88 |
89 | /*!
90 | Time ago in words (abbreviated and localized).
91 |
92 | These are the localized defaults, that you can override:
93 |
94 | XSecondsAbbreviated = "%.0fs";
95 | XMinutesAbbreviated = "%.0fm";
96 | XHoursAbbreviated = "%.0fh";
97 | XDaysAbbreviated = "%.0fd";
98 | XMonthsAbbreviated = "%.0fmo";
99 | XYearsAbbreviated = "%.0fy";
100 |
101 | @param interval Interval in seconds
102 | @param tableName Table name for localized string
103 | @param bundle Bundle for localized string
104 | @result Time ago in abbreviated words
105 | */
106 | + (NSString *)gh_localizedAbbreviatedStringForTimeInterval:(NSTimeInterval)interval tableName:(NSString *)tableName bundle:(NSBundle *)bundle;
107 |
108 | @end
109 |
--------------------------------------------------------------------------------
/GHKit/GHNSString+TimeInterval.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSString+TimeInterval.m
3 | //
4 | // Created by Gabe on 6/6/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSString+TimeInterval.h"
30 |
31 | #import
32 |
33 | @implementation NSString(GHTimeInterval)
34 |
35 | #define GHIntervalLocalize(key, defaultValue) NSLocalizedStringWithDefaultValue(key, tableName, bundle, defaultValue, nil)
36 |
37 | + (NSString *)gh_stringForTimeInterval:(NSTimeInterval)interval includeSeconds:(BOOL)includeSeconds {
38 | return [self gh_localizedStringForTimeInterval:interval includeSeconds:includeSeconds tableName:nil bundle:[NSBundle mainBundle]];
39 | }
40 |
41 | + (NSString *)gh_localizedStringForTimeInterval:(NSTimeInterval)interval includeSeconds:(BOOL)includeSeconds tableName:(NSString *)tableName bundle:(NSBundle *)bundle {
42 | NSTimeInterval intervalInSeconds = fabs(interval);
43 | double intervalInMinutes = round(intervalInSeconds/60.0);
44 |
45 | if (intervalInMinutes >= 0 && intervalInMinutes <= 1) {
46 | if (!includeSeconds) return intervalInMinutes <= 0 ? GHIntervalLocalize(@"LessThanAMinute", @"less than a minute") : GHIntervalLocalize(@"1Minute", @"1 minute");
47 | if (intervalInSeconds >= 0 && intervalInSeconds < 5) return [NSString stringWithFormat:GHIntervalLocalize(@"LessThanXSeconds", @"less than %d seconds"), 5];
48 | else if (intervalInSeconds >= 5 && intervalInSeconds < 10) return [NSString stringWithFormat:GHIntervalLocalize(@"LessThanXSeconds", @"less than %d seconds"), 10];
49 | else if (intervalInSeconds >= 10 && intervalInSeconds < 20) return [NSString stringWithFormat:GHIntervalLocalize(@"LessThanXSeconds", @"less than %d seconds"), 20];
50 | else if (intervalInSeconds >= 20 && intervalInSeconds < 40) return GHIntervalLocalize(@"HalfMinute", @"half a minute");
51 | else if (intervalInSeconds >= 40 && intervalInSeconds < 60) return GHIntervalLocalize(@"LessThanAMinute", @"less than a minute");
52 | else return GHIntervalLocalize(@"1Minute", @"1 minute");
53 | }
54 | else if (intervalInMinutes >= 2 && intervalInMinutes <= 44) return [NSString stringWithFormat:GHIntervalLocalize(@"XMinutes", @"%.0f minutes"), intervalInMinutes];
55 | else if (intervalInMinutes >= 45 && intervalInMinutes <= 89) return GHIntervalLocalize(@"About1Hour", @"about 1 hour");
56 | else if (intervalInMinutes >= 90 && intervalInMinutes <= 1439) return [NSString stringWithFormat:GHIntervalLocalize(@"AboutXHours", @"about %.0f hours"), round(intervalInMinutes/60.0)];
57 | else if (intervalInMinutes >= 1440 && intervalInMinutes <= 2879) return GHIntervalLocalize(@"1Day", @"1 day");
58 | else if (intervalInMinutes >= 2880 && intervalInMinutes <= 43199) return [NSString stringWithFormat:GHIntervalLocalize(@"XDays", @"%.0f days"), round(intervalInMinutes/1440.0)];
59 | else if (intervalInMinutes >= 43200 && intervalInMinutes <= 86399) return GHIntervalLocalize(@"About1Month", @"about 1 month");
60 | else if (intervalInMinutes >= 86400 && intervalInMinutes <= 525599) return [NSString stringWithFormat:GHIntervalLocalize(@"XMonths", @"%.0f months"), round(intervalInMinutes/43200.0)];
61 | else if (intervalInMinutes >= 525600 && intervalInMinutes <= 1051199) return GHIntervalLocalize(@"About1Year", @"about 1 year");
62 | else
63 | return [NSString stringWithFormat:GHIntervalLocalize(@"OverXYears", @"over %.0f years"), floor(intervalInMinutes/525600.0)];
64 | }
65 |
66 | + (NSString *)gh_abbreviatedStringForTimeInterval:(NSTimeInterval)interval {
67 | return [self gh_localizedAbbreviatedStringForTimeInterval:interval tableName:nil bundle:[NSBundle mainBundle]];
68 | }
69 |
70 | + (NSString *)gh_localizedAbbreviatedStringForTimeInterval:(NSTimeInterval)interval tableName:(NSString *)tableName bundle:(NSBundle *)bundle {
71 | NSTimeInterval intervalInSeconds = fabs(interval);
72 | double intervalInMinutes = round(intervalInSeconds/60.0);
73 |
74 | if (intervalInSeconds < 60) return [NSString stringWithFormat:GHIntervalLocalize(@"XSecondsAbbreviated", @"%.0fs"), intervalInSeconds];
75 | else if (intervalInMinutes >= 1 && intervalInMinutes < 60) return [NSString stringWithFormat:GHIntervalLocalize(@"XMinutesAbbreviated", @"%.0fm"), intervalInMinutes];
76 | else if (intervalInMinutes >= 60 && intervalInMinutes < 1440) return [NSString stringWithFormat:GHIntervalLocalize(@"XHoursAbbreviated", @"%.0fh"), round(intervalInMinutes/60.0)];
77 | else if (intervalInMinutes >= 1440 && intervalInMinutes < 43200) return [NSString stringWithFormat:GHIntervalLocalize(@"XDaysAbbreviated", @"%.0fd"), round(intervalInMinutes/1440.0)];
78 | else if (intervalInMinutes >= 43200 && intervalInMinutes < 525600) return [NSString stringWithFormat:GHIntervalLocalize(@"XMonthsAbbreviated", @"%.0fmo"), round(intervalInMinutes/43200.0)];
79 | else
80 | return [NSString stringWithFormat:GHIntervalLocalize(@"XYearsAbbreviated", @"%.0fy"), floor(intervalInMinutes/525600.0)];
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/GHKit/GHNSString+URL.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSString+URL.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 2/18/09.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSURL+Utils.h"
30 |
31 | /*!
32 | Utilities for URL encoding/decoding.
33 | */
34 | @interface NSString(GHURL)
35 |
36 | /*!
37 | Decode URL encoded string.
38 | @see NSURL#gh_decode:
39 | */
40 | - (NSString *)gh_URLDecode;
41 |
42 | /*!
43 | Encode URL string.
44 |
45 | "~!@#$%^&*(){}[]=:/,;?+'\"\\" => ~!@#$%25%5E&*()%7B%7D%5B%5D=:/,;?+'%22%5C
46 |
47 | Doesn't encode: ~!@#$&*()=:/,;?+'
48 |
49 | Does encode: %^{}[]"\
50 |
51 | Should be the same as javascript's encodeURI().
52 | See http://xkr.us/articles/javascript/encode-compare/
53 |
54 | @see NSURL#gh_encode:
55 | */
56 | - (NSString *)gh_URLEncode;
57 |
58 | /*!
59 | Encode URL string (for escaping URL key/value params).
60 |
61 | "~!@#$%^&*(){}[]=:/,;?+'\"\\" => ~!%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%3A%2F%2C%3B%3F%2B'%22%5C
62 |
63 | Doesn't encode: ~!*()'
64 |
65 | Does encode: @#$%^&{}[]=:/,;?+"\
66 |
67 | Should be the same as javascript's encodeURIComponent().
68 | See http://xkr.us/articles/javascript/encode-compare/
69 |
70 | @see NSURL#gh_encodeComponent
71 | */
72 | - (NSString *)gh_URLEncodeComponent;
73 |
74 | /*!
75 | Encode URL string (all characters).
76 |
77 | Encodes: @#$%^&{}[]=:/,;?+"\~!*()'
78 |
79 | @see NSURL#gh_escapeAll
80 | */
81 | - (NSString *)gh_URLEscapeAll;
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/GHKit/GHNSString+URL.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSString+URL.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 2/18/09.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHNSString+URL.h"
30 |
31 |
32 | @implementation NSString(GHURL)
33 |
34 | - (NSString *)gh_URLDecode {
35 | return [NSURL gh_decode:self];
36 | }
37 |
38 | - (NSString *)gh_URLEncode {
39 | return [NSURL gh_encode:self];
40 | }
41 |
42 | - (NSString *)gh_URLEncodeComponent {
43 | return [NSURL gh_encodeComponent:self];
44 | }
45 |
46 | - (NSString *)gh_URLEscapeAll {
47 | return [NSURL gh_escapeAll:self];
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/GHKit/GHNSStringEnumerator.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSStringEnumerator.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 6/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | For scanning, and enumerating strings.
34 |
35 | NSString *string = @"matz can't\n patch blues";
36 | GHNSStringEnumerator *enumerator = [[GHNSStringEnumerator alloc] initWithString:string separatorCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
37 |
38 | NSArray *results = [enumerator allObjects];
39 | NSArray *expected = [NSArray arrayWithObjects:@"matz", @" ", @"can't", @"\n ", @"patch", @" ", @"blues", nil];
40 | XCTAssertEqualObjects(results, expected, nil);
41 |
42 | */
43 | @interface GHNSStringEnumerator : NSEnumerator {
44 | NSScanner *_scanner;
45 |
46 | NSCharacterSet *_separatorCharacterSet;
47 | NSString *_separatorString;
48 |
49 | BOOL _inSeparator;
50 | }
51 |
52 | @property (readonly, nonatomic, getter=isInSeparator) BOOL inSeparator;
53 |
54 | /*!
55 | Create string enumerator with string and separator character set.
56 |
57 | @param string String
58 | @param separatorCharacterSet Separator characters
59 | */
60 | - (id)initWithString:(NSString *)string separatorCharacterSet:(NSCharacterSet *)separatorCharacterSet;
61 |
62 | /*!
63 | Create string enumerator with string and separator character set.
64 |
65 | @param string String
66 | @param separatorString Separator characters
67 | */
68 | - (id)initWithString:(NSString *)string separatorString:(NSString *)separatorString;
69 |
70 | /*!
71 | Next string.
72 |
73 | @result Next string
74 | */
75 | - (NSString *)nextString;
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/GHKit/GHNSStringEnumerator.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSStringEnumerator.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 6/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 |
31 | #import "GHNSStringEnumerator.h"
32 |
33 |
34 | @implementation GHNSStringEnumerator
35 |
36 | @synthesize inSeparator=_inSeparator;
37 |
38 | - (id)initWithString:(NSString *)string separatorCharacterSet:(NSCharacterSet *)separatorCharacterSet
39 | separatorString:(NSString *)separatorString {
40 |
41 | if ((self = [super init])) {
42 | _scanner = [[NSScanner alloc] initWithString:string];
43 | _scanner.charactersToBeSkipped = nil;
44 | _separatorCharacterSet = separatorCharacterSet;
45 | _separatorString = separatorString;
46 | _inSeparator = YES;
47 | }
48 | return self;
49 | }
50 |
51 | - (id)initWithString:(NSString *)string separatorCharacterSet:(NSCharacterSet *)separatorCharacterSet {
52 | return [self initWithString:string separatorCharacterSet:separatorCharacterSet separatorString:nil];
53 | }
54 |
55 | - (id)initWithString:(NSString *)string separatorString:(NSString *)separatorString {
56 | return [self initWithString:string separatorCharacterSet:nil separatorString:separatorString];
57 | }
58 |
59 | - (NSString *)nextString {
60 | if (_scanner.isAtEnd) return nil;
61 |
62 | NSString *s = nil;
63 | while(s == nil) {
64 | _inSeparator = !_inSeparator;
65 | if (_separatorCharacterSet) {
66 | if (!_inSeparator) {
67 | [_scanner scanUpToCharactersFromSet:_separatorCharacterSet intoString:&s];
68 | } else {
69 | [_scanner scanCharactersFromSet:_separatorCharacterSet intoString:&s];
70 | }
71 | } else if (_separatorString) {
72 | if (!_inSeparator) {
73 | [_scanner scanUpToString:_separatorString intoString:&s];
74 | } else {
75 | [_scanner scanString:_separatorString intoString:&s];
76 | }
77 | }
78 | }
79 | return s;
80 | }
81 |
82 | - (id)nextObject {
83 | return [self nextString];
84 | }
85 |
86 | @end
87 |
--------------------------------------------------------------------------------
/GHKit/GHNSURL+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSURL+Utils.h
3 | //
4 | // Created by Gabe on 3/19/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilities for URLs, for example, encoding, escaping, parsing, splitting out or sorting query params, and more.
33 | */
34 | @interface NSURL(GHUtils)
35 |
36 | /*!
37 | Get dictionary from NSURL query parameter.
38 |
39 | @result Dictionary of key, value pairs from parsing query parameter
40 | */
41 | - (NSMutableDictionary *)gh_queryDictionary;
42 |
43 | /*!
44 | Dictionary to query string. Escapes any encoded characters.
45 |
46 | @param queryDictionary Dictionary of key value params
47 | @result Query string, key1=value1&key2=value2
48 | */
49 | + (NSString *)gh_dictionaryToQueryString:(NSDictionary *)queryDictionary;
50 |
51 | /*!
52 | Convert dictionary to URL query string.
53 | Escapes any encoded characters.
54 |
55 | @param queryDictionary Dictionary
56 | @param sort If YES, will sort items
57 | @result Query string, key1=value1&key2=value2
58 | */
59 | + (NSString *)gh_dictionaryToQueryString:(NSDictionary *)queryDictionary sort:(BOOL)sort;
60 |
61 | /*!
62 | Convert dictionary to array of query strings.
63 |
64 | @param queryDictionary Dictionary
65 | @param sort If YES, will sort items
66 | @param encoded If YES, will be URL component encoded
67 | @result Query strings, ['key1=value1', 'key2=value2']
68 | */
69 | + (NSArray *)gh_dictionaryToQueryArray:(NSDictionary *)queryDictionary sort:(BOOL)sort encoded:(BOOL)encoded;
70 |
71 | /*!
72 | Convert URL query string to dictionary.
73 |
74 | @param string URL params string, key1=value1&key2=value2
75 | @result Dictionary
76 | */
77 | + (NSMutableDictionary *)gh_queryStringToDictionary:(NSString *)string;
78 |
79 | /*!
80 | Get query string, sorted by key.
81 | For example, "b=c&a=d" is returned as "a=d&b=c".
82 |
83 | @result Sorted query string
84 | */
85 | - (NSString *)gh_sortedQuery;
86 |
87 | /*!
88 | Derive new URL with a new query. All other fields should be the same.
89 |
90 | @param query Query string
91 | @result URL with new query
92 | */
93 | - (NSURL *)gh_deriveWithQuery:(NSString *)query;
94 |
95 | /*!
96 | Canonical form of URL.
97 |
98 | @result Canonical URL
99 | */
100 | - (NSURL *)gh_canonical;
101 |
102 | /*!
103 | Canonical form of URL.
104 |
105 | @param ignore Do not include the set of query params
106 | @result Canonical URL
107 | */
108 | - (NSURL *)gh_canonicalWithIgnore:(NSArray *)ignore;
109 |
110 | /*!
111 | Remove query params.
112 |
113 | @param filterQueryParams List of keys to filter
114 | @param sort Whether to sort query params
115 | @result URL without query params.
116 | */
117 | - (NSURL *)gh_filterQueryParams:(NSArray *)filterQueryParams sort:(BOOL)sort;
118 |
119 | /*!
120 | Encode URL string.
121 |
122 | "~!@#$%^&*(){}[]=:/,;?+'\"\\" => ~!@#$%25%5E&*()%7B%7D%5B%5D=:/,;?+'%22%5C
123 |
124 | Doesn't encode: ~!@#$&*()=:/,;?+'
125 |
126 | Does encode: %^{}[]"\
127 |
128 | Should be the same as javascript's encodeURI().
129 | See http://xkr.us/articles/javascript/encode-compare/
130 |
131 | @param s String to escape
132 | @result Encode string
133 | */
134 | + (NSString *)gh_encode:(NSString *)s;
135 |
136 | /*!
137 | Encode URL string (for escaping URL key/value params).
138 |
139 | "~!@#$%^&*(){}[]=:/,;?+'\"\\" => ~!%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%3A%2F%2C%3B%3F%2B'%22%5C
140 |
141 | Doesn't encode: ~!*()'
142 |
143 | Does encode: @#$%^&{}[]=:/,;?+"\
144 |
145 | Should be the same as javascript's encodeURIComponent().
146 | See http://xkr.us/articles/javascript/encode-compare/
147 |
148 | @param s String to encode
149 | @result Encoded string
150 | */
151 | + (NSString *)gh_encodeComponent:(NSString *)s;
152 |
153 | /*!
154 | Encode URL string.
155 |
156 | Encodes: @#$%^&{}[]=:/,;?+"\~!*()'
157 |
158 | @param s String to encode
159 | @result Encoded string
160 | */
161 | + (NSString *)gh_escapeAll:(NSString *)s;
162 |
163 | /*!
164 | Decode URL string.
165 |
166 | @param s String to decode
167 | @result Decoded URL string
168 | */
169 | + (NSString *)gh_decode:(NSString *)s;
170 |
171 | #if TARGET_OS_OSX
172 |
173 | /*!
174 | Copy URL to pasteboard. For Mac OS X only.
175 | */
176 | - (void)gh_copyLinkToPasteboard;
177 |
178 | /*!
179 | Open file URL.
180 | Opens path in Finder or whatever is registered for the file:// scheme.
181 | For Mac OS X only.
182 |
183 | @param path Path to open
184 | @result YES if opened
185 | */
186 | + (BOOL)gh_openFile:(NSString *)path;
187 |
188 | /*!
189 | Opens directory of file at path (or the path itself if it is a directory),
190 | in the Finder or whatever is registered for the file:// scheme.
191 | For Mac OS X only.
192 |
193 | @param path Path
194 | */
195 | + (void)gh_openContainingFolder:(NSString *)path;
196 |
197 | #endif
198 |
199 | @end
200 |
--------------------------------------------------------------------------------
/GHKit/GHNSUserDefaults+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSUserDefaults+Utils.h
3 | // GHKitIOS
4 | //
5 | // Created by Gabriel Handford on 7/21/11.
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Utilities for URLs, for example, encoding, escaping, parsing, splitting out or sorting query params, and more.
33 | */
34 | @interface NSUserDefaults(GHUtils)
35 |
36 | /*!
37 | Check if user defaults contains key.
38 |
39 | @param key Key
40 | @result YES if defaults contains key
41 | */
42 | - (BOOL)gh_containsKey:(NSString *)key;
43 |
44 | /*!
45 | BOOL for key.
46 |
47 | @param key Key
48 | @param withDefault Default value
49 | @result BOOL for key
50 | */
51 | - (BOOL)gh_boolForKey:(id)key withDefault:(BOOL)withDefault;
52 |
53 | /*!
54 | Set BOOL for key.
55 |
56 | @param b Bool
57 | @param forKey Key
58 | */
59 | - (void)gh_setBool:(BOOL)b forKey:(NSString *)forKey;
60 |
61 | /*!
62 | Double for key.
63 |
64 | @param key Key
65 | @param withDefault Value if not in defaults
66 | @result double for key
67 | */
68 | - (double)gh_doubleForKey:(NSString *)key withDefault:(double)withDefault;
69 |
70 | /*!
71 | Set double for key.
72 |
73 | @param d Double
74 | @param forKey Key
75 | */
76 | - (void)gh_setDouble:(double)d forKey:(NSString *)forKey;
77 |
78 | /*!
79 | Integer for key.
80 |
81 | @param key Key
82 | @param withDefault Value if not in defaults
83 | @result Integer for key
84 | */
85 | - (NSInteger)gh_integerForKey:(NSString *)key withDefault:(NSInteger)withDefault;
86 |
87 | /*!
88 | Set integer for key.
89 |
90 | @param integer Integer
91 | @param forKey Key
92 | */
93 | - (void)gh_setInteger:(NSInteger)integer forKey:(NSString *)forKey;
94 |
95 | /*!
96 | Object for key.
97 |
98 | @param key Key
99 | @param withDefault Value if not in defaults
100 | */
101 | - (id)gh_objectForKey:(NSString *)key withDefault:(id)withDefault;
102 |
103 | /*!
104 | Set object (stored as NSData) for key.
105 |
106 | @param obj Object (should be NSCoding)
107 | @param forKey Key
108 | @result Object from data for key
109 | */
110 | - (void)gh_setObjectAsData:(id)obj forKey:(NSString *)forKey;
111 |
112 | /*!
113 | Object from data for key.
114 |
115 | @param key Key
116 | @result Object from data for key
117 | */
118 | - (id)gh_objectFromDataForKey:(NSString *)key;
119 |
120 | @end
121 |
--------------------------------------------------------------------------------
/GHKit/GHNSUserDefaults+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSUserDefaults+Utils.m
3 | // GHKitIOS
4 | //
5 | // Created by Gabriel Handford on 7/21/11.
6 | // Copyright 2011 rel.me. All rights reserved.
7 | //
8 |
9 | #import "GHNSUserDefaults+Utils.h"
10 |
11 |
12 | @implementation NSUserDefaults(GHUtils)
13 |
14 | - (BOOL)gh_containsKey:(NSString *)key {
15 | id value = [self objectForKey:key];
16 | return (value != nil);
17 | }
18 |
19 | - (BOOL)gh_boolForKey:(id)key withDefault:(BOOL)defaultValue {
20 | id value = [self objectForKey:key];
21 | if (!value) return defaultValue;
22 | return [value boolValue];
23 | }
24 |
25 | - (void)gh_setBool:(BOOL)b forKey:(NSString *)key {
26 | [self setObject:[NSNumber numberWithBool:b] forKey:key];
27 | }
28 |
29 | - (double)gh_doubleForKey:(NSString *)key withDefault:(double)defaultValue {
30 | id value = [self objectForKey:key];
31 | if (!value) return defaultValue;
32 | return [value doubleValue];
33 | }
34 |
35 | - (void)gh_setDouble:(double)d forKey:(NSString *)key {
36 | [self setObject:[NSNumber numberWithDouble:d] forKey:key];
37 | }
38 |
39 | - (NSInteger)gh_integerForKey:(NSString *)key withDefault:(NSInteger)defaultValue {
40 | id value = [self objectForKey:key];
41 | if (!value) return defaultValue;
42 | return [value integerValue];
43 | }
44 |
45 | - (void)gh_setInteger:(NSInteger)integer forKey:(NSString *)key {
46 | [self setObject:[NSNumber numberWithInteger:integer] forKey:key];
47 | }
48 |
49 | - (void)gh_setObjectAsData:(id)obj forKey:(NSString *)key {
50 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:obj];
51 | if (!data) {
52 | [NSException raise:NSInvalidArgumentException format:@"Invalid data for key: %@", key];
53 | return;
54 | }
55 | [self setObject:data forKey:key];
56 | }
57 |
58 | - (id)gh_objectFromDataForKey:(NSString *)key {
59 | NSData *data = [self objectForKey:key];
60 | if (!data) return nil;
61 | return [NSKeyedUnarchiver unarchiveObjectWithData:data];
62 | }
63 |
64 | - (id)gh_objectForKey:(NSString *)key withDefault:(id)defaultValue {
65 | id value = [self objectForKey:key];
66 | if (!value) return defaultValue;
67 | return value;
68 | }
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/GHKit/GHReversableDictionary.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHReversableDictionary.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/25/10.
6 | // Copyright 2010. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | /*!
33 | Reversable dictionary, where keys and values point to each other.
34 | */
35 | @interface GHReversableDictionary : NSObject {
36 | NSMutableDictionary *_dict;
37 | NSMutableDictionary *_reversedDict;
38 | }
39 |
40 | /*!
41 | Create with capacity.
42 |
43 | @param capacity Capacity
44 | */
45 | - (id)initWithCapacity:(NSInteger)capacity;
46 |
47 | /*!
48 | Create with objects and keys.
49 |
50 | @param firstObject Objects
51 | @param ... Objects and keys
52 | */
53 | - (id)initWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
54 |
55 | /*!
56 | Key for object.
57 |
58 | @param obj Object
59 | @result Key
60 | */
61 | - (id)keyForObject:(id)obj;
62 |
63 | /*!
64 | Set object for key.
65 |
66 | @param obj Object
67 | @param key Key
68 | */
69 | - (void)setObject:(id)obj forKey:(id)key;
70 |
71 | /*!
72 | Get object for key.
73 |
74 | @param key Key
75 | @result Object for key
76 | */
77 | - (id)objectForKey:(id)key;
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/GHKit/GHReversableDictionary.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHReversableDictionary.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/25/10.
6 | // Copyright 2010. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHReversableDictionary.h"
31 | #import "GHKitDefines.h"
32 |
33 |
34 | @implementation GHReversableDictionary
35 |
36 | - (id)init {
37 | return [self initWithCapacity:10];
38 | }
39 |
40 | - (id)initWithCapacity:(NSInteger)capacity {
41 | if ((self = [super init])) {
42 | _dict = [[NSMutableDictionary alloc] initWithCapacity:capacity];
43 | _reversedDict = [[NSMutableDictionary alloc] initWithCapacity:capacity];
44 | }
45 | return self;
46 | }
47 |
48 | - (id)initWithObjectsAndKeys:(id)firstObject, ... {
49 | GHConvertVarArgs(firstObject);
50 | self = [self init];
51 | for(NSInteger i = 0, count = [arguments count]; i < count; i += 2) {
52 | if ((i + 1) >= [arguments count]) break;
53 | [self setObject:[arguments objectAtIndex:i] forKey:[arguments objectAtIndex:i+1]];
54 | }
55 | return self;
56 | }
57 |
58 | - (void)setObject:(id)obj forKey:(id)key {
59 | [_dict setObject:obj forKey:key];
60 | [_reversedDict setObject:key forKey:obj];
61 | }
62 |
63 | - (id)objectForKey:(id)key {
64 | return [_dict objectForKey:key];
65 | }
66 |
67 | - (id)keyForObject:(id)obj {
68 | return [_reversedDict objectForKey:obj];
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/GHKit/GHValidators.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSString+Validation.h
3 | //
4 | // Created by Gabe on 7/20/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | /*!
32 | Validators for input, such as email addresses.
33 | */
34 | @interface GHValidators : NSObject { }
35 |
36 | /*!
37 | Check if string is a valid email address.
38 |
39 | @param str String to validate
40 | @result YES if string is a valid email address
41 | */
42 | + (BOOL)isEmailAddress:(NSString *)str;
43 |
44 | /*!
45 | Check if credit card number passes Luhn validation.
46 |
47 | @param numberString Credit card number as string
48 | @result YES if passes luhn validation
49 | */
50 | + (BOOL)isCreditCardNumber:(NSString *)numberString;
51 |
52 | /*!
53 | Check if string is a valid credit card expiration.
54 | Accept 1/12, 01/12, or 01/2012, or 01/10/2012.
55 |
56 | @param expiration Expiration string.
57 | @param date Current date, fails if expiration < this date
58 | @result YES if passes validation
59 | */
60 | + (BOOL)isCreditCardExpiration:(NSString *)expiration date:(NSDate *)date;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/GHKit/GHValidators.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHValidators.m
3 | //
4 | // Created by Gabe on 7/20/08.
5 | // Copyright 2008 Gabriel Handford
6 | //
7 | // Permission is hereby granted, free of charge, to any person
8 | // obtaining a copy of this software and associated documentation
9 | // files (the "Software"), to deal in the Software without
10 | // restriction, including without limitation the rights to use,
11 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the
13 | // Software is furnished to do so, subject to the following
14 | // conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 | // OTHER DEALINGS IN THE SOFTWARE.
27 | //
28 |
29 | #import "GHValidators.h"
30 | #import "GHNSDate+Utils.h"
31 |
32 | @implementation GHValidators
33 |
34 | + (BOOL)isEmailAddress:(NSString *)str {
35 | if (!str) return NO;
36 |
37 | NSString *emailRegexPattern = @"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]+$";
38 |
39 | NSError *error = nil;
40 | NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:emailRegexPattern options:NSRegularExpressionCaseInsensitive error:&error];
41 |
42 | NSAssert(!error, @"Error in regex: %@", error);
43 |
44 | NSUInteger matchCount = [regex numberOfMatchesInString:str options:0 range:NSMakeRange(0, [str length])];
45 |
46 | return (matchCount == 1);
47 | }
48 |
49 | + (BOOL)isCreditCardNumber:(NSString *)numberString {
50 | NSInteger digitsLength = [numberString length];
51 | if (digitsLength == 0) return NO;
52 | NSInteger digitsArray[digitsLength];
53 | for (NSInteger i = 0; i < digitsLength; i++) {
54 | NSString *digitString = [numberString substringWithRange:NSMakeRange(i, 1)];
55 | // Check for 0 manually since integerValue returns 0 on failure
56 | if ([digitString isEqual:@"0"]) {
57 | digitsArray[i] = 0;
58 | } else {
59 | NSInteger digit = [digitString integerValue];
60 | if (digit == 0) return NO;
61 | digitsArray[i] = digit;
62 | }
63 | }
64 |
65 | for (NSInteger i = digitsLength - 2; i > -1; i-=2) {
66 | digitsArray[i] *= 2;
67 | if (digitsArray[i] > 9) {
68 | digitsArray[i] -= 9;
69 | }
70 | }
71 |
72 | NSInteger total = 0;
73 | for (NSInteger i = 0; i < digitsLength; i++) {
74 | total += digitsArray[i];
75 | }
76 |
77 | return (total % 10 == 0);
78 | }
79 |
80 | + (BOOL)isCreditCardExpiration:(NSString *)expiration date:(NSDate *)date {
81 | if (!expiration) return NO;
82 | NSArray *split = [expiration componentsSeparatedByString:@"/"];
83 | if ([split count] != 2) return NO;
84 | NSInteger month = [[split objectAtIndex:0] integerValue];
85 | NSInteger year = [[split objectAtIndex:1] integerValue];
86 | if (month <= 0 || year <= 0) return NO;
87 | if (month > 12) return NO;
88 |
89 | if (year >= 0 && year < 100) year += 2000; // TODO(gabe): Y3K
90 |
91 | if (date) {
92 | // Check >= date.
93 | // Comparing date components like this isn't completely precise across time zones
94 | // so we ignore the first day of the month.
95 | NSInteger currentYear = [date gh_year];
96 | if (year < currentYear) return NO;
97 | if (year == currentYear && month < [date gh_month] && [date gh_day] != 1) {
98 | return NO;
99 | }
100 | }
101 | return YES;
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/GHKit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2015 rel.me. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIColor+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Utils.h
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 12/18/08.
6 | // Copyright 2008 Gabriel Handford
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 | #import
32 |
33 | /*!
34 | Macro for UIColor from hex.
35 | UIColor *color = GHUIColorFromRGB(0xBC1128);
36 | */
37 | #define GHUIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
38 |
39 | /*!
40 | Represents an RGBA value.
41 | */
42 | typedef struct {
43 | CGFloat red;
44 | CGFloat green;
45 | CGFloat blue;
46 | CGFloat alpha;
47 | } GH_RGBA;
48 |
49 | /*!
50 | Represents an HSV value.
51 |
52 | HSV is the same as HSB.
53 | */
54 | typedef struct {
55 | float hue;
56 | float saturation;
57 | float value;
58 | } GH_HSV;
59 |
60 |
61 | /*!
62 | Utilities for UIColor.
63 |
64 | @ingroup iPhone
65 | */
66 | @interface UIColor(GHUtils)
67 |
68 | /*!
69 | RGBA value.
70 |
71 | @result RGBA
72 | */
73 | - (GH_RGBA)gh_rgba;
74 |
75 | /*!
76 | HSV value.
77 |
78 | @result HSV
79 | */
80 | - (GH_HSV)gh_hsv;
81 |
82 | /*!
83 | HSV value from RGB.
84 |
85 | @param red Red
86 | @param green Green
87 | @param blue Blue
88 | @result HSV
89 | */
90 | + (GH_HSV)gh_hsvFromRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue;
91 |
92 | // See NSColor#getComponents:
93 | - (void)gh_getComponents:(CGFloat *)components;
94 |
95 | // See NSColor#numberOfComponents
96 | - (NSInteger)gh_numberOfComponents;
97 |
98 | // See NSColor#getRed:green:blue:alpha
99 | - (void)gh_getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;
100 |
101 | - (UIColor *)gh_darkenColor:(CGFloat)value;
102 |
103 | @end
104 |
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIColor+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Utils.m
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 12/18/08.
6 | // Copyright 2008 Gabriel Handford
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import "GHUIColor+Utils.h"
31 |
32 | #import
33 |
34 | @implementation UIColor(GHUtils)
35 |
36 | // From http://www.easyrgb.com/index.php?X=MATH&H=20#text20
37 | + (GH_HSV)gh_hsvFromRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue {
38 |
39 | float min = fminf(fminf(red, green), blue);
40 | float max = fmaxf(fmaxf(red, green), blue);
41 | float delta = max-min;
42 |
43 | float hue = 0.0;
44 | float saturation = 0.0;
45 | float value = max;
46 |
47 | if (delta <= 1.0E-5) {
48 | hue = 0.0;
49 | saturation = 0.0;
50 | } else {
51 | saturation = delta / max;
52 |
53 | float deltaR = (((max - red) / 6.0) + (max/2.0)) / delta;
54 | float deltaG = (((max - green) / 6.0) + (max/2.0)) / delta;
55 | float deltaB = (((max - blue) / 6.0) + (max/2.0)) / delta;
56 |
57 | if (red <= (max+1.0E-5) && red >= (max-1.0E-5)) hue = deltaB - deltaG;
58 | else if (green <= (max+1.0E-5) && green >= (max-1.0E-5)) hue = (1.0/3.0) + deltaR - deltaB;
59 | else if (blue <= (max+1.0E-5) && blue >= (max-1.0E-5)) hue = (2.0/3.0) + deltaG - deltaR;
60 |
61 | if (hue < 0) hue += 1;
62 | if (hue > 1) hue -= 1;
63 | }
64 |
65 | GH_HSV hsv;
66 | hsv.hue = hue;
67 | hsv.saturation = saturation;
68 | hsv.value = value;
69 | return hsv;
70 | }
71 |
72 | - (GH_RGBA)gh_rgba {
73 | const CGFloat *components = CGColorGetComponents(self.CGColor);
74 | GH_RGBA color = { .red = 0, .green = 0, .blue = 0, .alpha = 1 };
75 | CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
76 | if (colorSpaceModel == kCGColorSpaceModelRGB) {
77 | color.red = components[0];
78 | color.green = components[1];
79 | color.blue = components[2];
80 | color.alpha = components[3];
81 | } else if (colorSpaceModel == kCGColorSpaceModelMonochrome) {
82 | color.red = components[0];
83 | color.green = components[0];
84 | color.blue = components[0];
85 | color.alpha = components[1];
86 | } else {
87 | NSAssert(NO, @"Unable to convert to RGBA from color space");
88 | }
89 | return color;
90 | }
91 |
92 | - (GH_HSV)gh_hsv {
93 | GH_RGBA rgba = [self gh_rgba];
94 | return [UIColor gh_hsvFromRed:rgba.red green:rgba.green blue:rgba.blue];
95 | }
96 |
97 | - (void)gh_getComponents:(CGFloat *)components {
98 | memcpy(components, CGColorGetComponents(self.CGColor), CGColorGetNumberOfComponents(self.CGColor) * sizeof(CGFloat));
99 | }
100 |
101 | - (NSInteger)gh_numberOfComponents {
102 | size_t num = CGColorGetNumberOfComponents(self.CGColor);
103 | return (NSInteger)num;
104 | }
105 |
106 | - (void)gh_getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha {
107 | const CGFloat *components = CGColorGetComponents(self.CGColor);
108 | *red = *green = *blue = 0.0;
109 | *alpha = 1.0;
110 | size_t num = CGColorGetNumberOfComponents(self.CGColor);
111 | if (num <= 2) {
112 | *red = components[0];
113 | *green = components[0];
114 | *blue = components[0];
115 | if (num == 2) *alpha = components[1];
116 | } else if (num >= 3) {
117 | *red = components[0];
118 | *green = components[1];
119 | *blue = components[2];
120 | if (num >= 4) *alpha = components[3];
121 | }
122 | }
123 |
124 | - (UIColor *)gh_darkenColor:(CGFloat)value {
125 | NSUInteger totalComponents = CGColorGetNumberOfComponents(self.CGColor);
126 | BOOL isGreyscale = (totalComponents == 2) ? YES : NO;
127 |
128 | CGFloat *oldComponents = (CGFloat *)CGColorGetComponents(self.CGColor);
129 | CGFloat newComponents[4];
130 |
131 | if(isGreyscale) {
132 | newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
133 | newComponents[1] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
134 | newComponents[2] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
135 | newComponents[3] = oldComponents[1];
136 | }
137 | else {
138 | newComponents[0] = oldComponents[0] - value < 0.0f ? 0.0f : oldComponents[0] - value;
139 | newComponents[1] = oldComponents[1] - value < 0.0f ? 0.0f : oldComponents[1] - value;
140 | newComponents[2] = oldComponents[2] - value < 0.0f ? 0.0f : oldComponents[2] - value;
141 | newComponents[3] = oldComponents[3];
142 | }
143 |
144 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
145 | CGColorRef newColor = CGColorCreate(colorSpace, newComponents);
146 | CGColorSpaceRelease(colorSpace);
147 |
148 | UIColor *retColor = [UIColor colorWithCGColor:newColor];
149 | CGColorRelease(newColor);
150 |
151 | return retColor;
152 | }
153 |
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIImage+Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIImage+Utils.h
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 11/26/13.
6 | // Copyright (c) 2013 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 | @interface UIImage (GHUtils)
14 |
15 | + (NSString *)gh_mimeType:(NSString *)name;
16 |
17 | - (UIImage *)gh_imageFlippedHorizontal;
18 |
19 | - (UIImage *)gh_imageMaskWithColor:(UIColor *)maskColor;
20 |
21 | - (UIImage *)gh_imageByRotatingImageUpright;
22 |
23 | - (UIImage *)gh_resizedImageInSize:(CGSize)size contentMode:(UIViewContentMode)contentMode opaque:(BOOL)opaque;
24 |
25 | - (UIImage *)gh_croppedImageFromFrame:(CGRect)frame;
26 |
27 | + (UIImage *)gh_imageFromView:(UIView *)view;
28 |
29 | + (UIImage *)gh_imageFromDrawOperations:(void(^)(CGContextRef context))drawOperations size:(CGSize)size opaque:(BOOL)opaque;
30 |
31 | - (UIImage *)gh_imageScaledToMaxWidth:(CGFloat)scaledToMaxWidth;
32 |
33 | - (UIImage *)gh_imageScaledToWidth:(CGFloat)scaledToWidth;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIImage+Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIImage+Utils.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 11/26/13.
6 | // Copyright (c) 2013 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "GHUIImage+Utils.h"
12 | #import "GHCGUtils.h"
13 |
14 | @implementation UIImage (GHUtils)
15 |
16 | - (UIImage *)gh_imageFlippedHorizontal {
17 | return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:UIImageOrientationUpMirrored];
18 | }
19 |
20 | - (UIImage *)gh_imageMaskWithColor:(UIColor *)maskColor {
21 | CGRect imageRect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);
22 |
23 | UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, self.scale);
24 | CGContextRef ctx = UIGraphicsGetCurrentContext();
25 |
26 | CGContextScaleCTM(ctx, 1.0f, -1.0f);
27 | CGContextTranslateCTM(ctx, 0.0f, -(imageRect.size.height));
28 |
29 | CGContextClipToMask(ctx, imageRect, self.CGImage);
30 | CGContextSetFillColorWithColor(ctx, maskColor.CGColor);
31 | CGContextFillRect(ctx, imageRect);
32 |
33 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
34 | UIGraphicsEndImageContext();
35 |
36 | return newImage;
37 | }
38 |
39 | + (NSString *)gh_mimeType:(NSString *)name {
40 | CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[name pathExtension], NULL);
41 | NSString *mimeType = CFBridgingRelease(UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType));
42 | CFRelease(UTI);
43 | return mimeType;
44 | }
45 |
46 | + (UIImage *)gh_imageFromDrawOperations:(void(^)(CGContextRef context))drawOperations size:(CGSize)size opaque:(BOOL)opaque {
47 | UIGraphicsBeginImageContextWithOptions(size, opaque, [[UIScreen mainScreen] scale]);
48 | CGContextRef context = UIGraphicsGetCurrentContext();
49 | // Flip coordinate system, otherwise image will be drawn upside down
50 | CGContextTranslateCTM(context, 0, size.height);
51 | CGContextScaleCTM (context, 1.0, -1.0);
52 | drawOperations(context);
53 | UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
54 | UIGraphicsEndImageContext();
55 | return renderedImage;
56 | }
57 |
58 | + (UIImage *)gh_imageFromView:(UIView *)view {
59 | [view setNeedsDisplay];
60 | UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, [[UIScreen mainScreen] scale]);
61 | CALayer *layer = view.layer;
62 | CGContextRef context = UIGraphicsGetCurrentContext();
63 | [layer renderInContext:context];
64 | UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
65 | UIGraphicsEndImageContext();
66 | return viewImage;
67 | }
68 |
69 | - (UIImage *)gh_croppedImageFromFrame:(CGRect)frame {
70 | CGFloat scale = [self scale];
71 | frame.origin.x *= scale;
72 | frame.origin.y *= scale;
73 | frame.size.height *= scale;
74 | frame.size.width *= scale;
75 | CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, frame);
76 | UIImage *image = [UIImage imageWithCGImage:imageRef scale:scale orientation:self.imageOrientation];
77 | CGImageRelease(imageRef);
78 | return image;
79 | }
80 |
81 | - (UIImage *)gh_resizedImageInSize:(CGSize)size contentMode:(UIViewContentMode)contentMode opaque:(BOOL)opaque {
82 | CGRect imageRect = GHCGRectConvert(CGRectMake(0, 0, size.width, size.height), self.size, contentMode);
83 |
84 | UIImage *resizedImage = [UIImage gh_imageFromDrawOperations:^(CGContextRef context) {
85 | CGContextDrawImage(context, CGRectMake(0, 0, imageRect.size.width, imageRect.size.height), self.CGImage);
86 | } size:imageRect.size opaque:opaque];
87 |
88 | return resizedImage;
89 | }
90 |
91 | - (UIImage *)gh_imageByRotatingImageUpright {
92 | UIGraphicsBeginImageContextWithOptions(self.size, YES, self.scale);
93 | CGContextRef context = UIGraphicsGetCurrentContext();
94 |
95 | [self drawAtPoint:CGPointZero];
96 |
97 | if (self.imageOrientation == UIImageOrientationRight) {
98 | // Phone is upright
99 | CGContextRotateCTM (context, -M_PI_2);
100 | } else if (self.imageOrientation == UIImageOrientationLeft) {
101 | // Phone is upside down
102 | CGContextRotateCTM (context, M_PI_2);
103 | } else if (self.imageOrientation == UIImageOrientationDown) {
104 | // Phone is in landscape with the volume buttons facing up
105 | CGContextRotateCTM (context, M_PI);
106 | } else if (self.imageOrientation == UIImageOrientationUp) {
107 | // Phone is in landscape with the volume buttons facing down
108 | }
109 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
110 | UIGraphicsEndImageContext();
111 |
112 | return image;
113 | }
114 |
115 | - (UIImage *)gh_imageScaledToMaxWidth:(CGFloat)scaledToMaxWidth {
116 | CGFloat sourceWidth = self.size.width * self.scale;
117 | if (scaledToMaxWidth > sourceWidth) scaledToMaxWidth = sourceWidth;
118 | return [self gh_imageScaledToWidth:scaledToMaxWidth];
119 | }
120 |
121 | - (UIImage *)gh_imageScaledToWidth:(CGFloat)scaledToWidth {
122 | CGFloat sourceWidth = self.size.width * self.scale;
123 | CGFloat sourceHeight = self.size.height * self.scale;
124 | CGRect sourceRect = CGRectMake(0, 0, sourceWidth, sourceHeight);
125 | CGFloat sourceRatio = sourceWidth / sourceHeight;
126 |
127 | CGFloat targetWidth = scaledToWidth;
128 | CGFloat targetHeight = roundf(targetWidth * (1.0/sourceRatio));
129 | CGRect targetRect = CGRectMake(0, 0, targetWidth, targetHeight);
130 |
131 | UIGraphicsBeginImageContextWithOptions(targetRect.size, NO, 1.0); // 0.f for scale means "scale for device's main screen".
132 | CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
133 | UIImage *image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
134 | CGImageRelease(sourceImg);
135 | [image drawInRect:targetRect]; // the actual scaling happens here, and orientation is taken care of automatically.
136 | image = UIGraphicsGetImageFromCurrentImageContext();
137 | UIGraphicsEndImageContext();
138 | return image;
139 | }
140 |
141 | @end
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIUtils.h:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIUtils.h
3 | // GHUIKit
4 | //
5 | // Created by Gabriel Handford on 11/5/13.
6 | // Copyright (c) 2013 Gabriel Handford. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface GHUIUtils : NSObject
13 |
14 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font;
15 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font width:(CGFloat)width;
16 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font width:(CGFloat)width truncate:(BOOL)truncate;
17 |
18 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font size:(CGSize)size;
19 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font size:(CGSize)size truncate:(BOOL)truncate;
20 |
21 | + (NSInteger)fontSizeForText:(NSString *)text minFontSize:(NSInteger)minFontSize maxFontSize:(NSInteger)maxFontSize familyName:(NSString *)familyName size:(CGSize)size;
22 |
23 | + (void)drawText:(NSString *)text rect:(CGRect)rect font:(UIFont *)font color:(UIColor *)color alignment:(NSTextAlignment)alignment truncate:(BOOL)truncate;
24 |
25 | + (UIView *)subview:(UIView *)view forClass:(Class)class;
26 |
27 | + (NSMutableAttributedString *)joinAttributedStrings:(NSArray *)strings delimeter:(NSAttributedString *)delimeter;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/GHKit/iOS/GHUIUtils.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIUtils.m
3 | // GHUIKit
4 | //
5 | // Created by Gabriel Handford on 11/5/13.
6 | // Copyright (c) 2013 Gabriel Handford. All rights reserved.
7 | //
8 |
9 | #import "GHUIUtils.h"
10 |
11 | @implementation GHUIUtils
12 |
13 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font {
14 | return [self sizeWithText:text font:font width:CGFLOAT_MAX];
15 | }
16 |
17 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font width:(CGFloat)width {
18 | return [self sizeWithText:text font:font width:width truncate:NO];
19 | }
20 |
21 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font width:(CGFloat)width truncate:(BOOL)truncate {
22 | return [self sizeWithText:text font:font size:(CGSize){width, CGFLOAT_MAX} truncate:truncate];
23 | }
24 |
25 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font size:(CGSize)size {
26 | return [self sizeWithText:text font:font size:size truncate:NO];
27 | }
28 |
29 | + (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font size:(CGSize)size truncate:(BOOL)truncate {
30 | if (!text) return CGSizeZero;
31 | NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:font}];
32 | NSStringDrawingOptions options = 0;
33 | options |= NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading;
34 | if (truncate) options |= NSStringDrawingTruncatesLastVisibleLine;
35 | CGRect rect = [attributedText boundingRectWithSize:size options:options context:nil];
36 | return rect.size;
37 | }
38 |
39 | + (NSInteger)fontSizeForText:(NSString *)text minFontSize:(NSInteger)minFontSize maxFontSize:(NSInteger)maxFontSize familyName:(NSString *)familyName size:(CGSize)size {
40 | if (maxFontSize < minFontSize) return maxFontSize;
41 | if (!text) return 0;
42 |
43 | NSInteger fontSize = roundf((float)(minFontSize + maxFontSize) / 2.0);
44 |
45 | UIFont *font = [UIFont fontWithName:familyName size:fontSize];
46 | CGSize textSize = [self sizeWithText:text font:font size:CGSizeMake(size.width, CGFLOAT_MAX)];
47 |
48 | if (textSize.height >= (size.height + 10) && textSize.width >= (size.width + 10) && textSize.height <= (size.height) && textSize.width <= (size.width) ) {
49 | return fontSize;
50 | } else if (textSize.height > size.height || textSize.width > size.width) {
51 | return [self fontSizeForText:text minFontSize:minFontSize maxFontSize:(fontSize - 1) familyName:familyName size:size];
52 | } else {
53 | return [self fontSizeForText:text minFontSize:(fontSize + 1) maxFontSize:maxFontSize familyName:familyName size:size];
54 | }
55 | }
56 |
57 | + (void)drawText:(NSString *)text rect:(CGRect)rect font:(UIFont *)font color:(UIColor *)color alignment:(NSTextAlignment)alignment truncate:(BOOL)truncate {
58 | NSStringDrawingOptions options = 0;
59 | options |= NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading;
60 | if (truncate) options |= NSStringDrawingTruncatesLastVisibleLine;
61 | NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
62 | [paragraphStyle setAlignment:alignment];
63 | [text drawWithRect:rect options:options attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle, NSForegroundColorAttributeName:color} context:nil];
64 | }
65 |
66 | + (UIView *)subview:(UIView *)view forClass:(Class)class {
67 | return [self _subview:view forClass:class iteration:0];
68 | }
69 |
70 | + (UIView *)_subview:(UIView *)view forClass:(Class)class iteration:(NSInteger)iteration {
71 | if (iteration > 10) return nil;
72 | if ([view isKindOfClass:class]) return view;
73 |
74 | // Search breadth first since thats more likely
75 | for (UIView *subview in [view subviews]) {
76 | if ([subview isKindOfClass:class]) return subview;
77 | }
78 | ++iteration;
79 | for (UIView *subview in [view subviews]) {
80 | UIView *view = [GHUIUtils _subview:subview forClass:class iteration:iteration];
81 | if (view) return view;
82 | }
83 | return nil;
84 | }
85 |
86 | + (NSMutableAttributedString *)joinAttributedStrings:(NSArray *)strings delimeter:(NSAttributedString *)delimeter {
87 | NSMutableAttributedString *text = [[NSMutableAttributedString alloc] init];
88 | for (NSInteger index = 0; index < strings.count; index++) {
89 | NSAttributedString *as = strings[index];
90 | if (as.length > 0) {
91 | [text appendAttributedString:as];
92 | if (delimeter && index < strings.count - 1) {
93 | [text appendAttributedString:delimeter];
94 | }
95 | }
96 | }
97 | return text;
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/GHKit/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Gabriel Handford
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GHKit
2 |
3 | The GHKit framework is a set of extensions and utilities for Mac OS X and iOS.
4 |
5 | ## Podfile
6 |
7 | pod "GHKit"
8 |
9 | ## Usage
10 |
11 | GHKit defines various categories and general purpose utilities.
12 |
13 | For example, parsing date strings, date math, string manipulations, URL dictionary formatting, etc. Some examples are below.
14 |
15 | All categories are namespaced with gh_ to avoid conflicts.
16 |
17 | ***Import:***
18 |
19 | ```objc
20 | #import
21 | ```
22 |
23 |
24 | ***Dates:***
25 |
26 | `GHNSDate+Formatters.h`: Date parsers, formatting and formatters for ISO8601, RFC822, HTTP (RFC1123, RFC850, asctime) and since epoch.
27 |
28 | ```objc
29 | NSDate *date = [NSDate gh_parseISO8601:@"2010-10-07T04:25Z"];
30 | NSString *dateString = [date gh_formatHTTP]; // Formatted like: Sun, 06 Nov 1994 08:49:37 GMT"
31 | NSDate *date = [NSDate gh_parseTimeSinceEpoch:@(1234567890)];
32 | ```
33 |
34 | `GHNSDate+Utils.h`: For time ago in words and date component arithmentic (adding days), tomorrow, yesterday, and more.
35 |
36 | ```objc
37 | NSDate *date = [NSDate date];
38 | [date gh_isToday]; // YES
39 | [[date gh_yesterday] gh_isToday]; // NO
40 |
41 | date = [date gh_addDays:-1];
42 | [date gh_wasYesterday]; // YES
43 |
44 | [date gh_timeAgo:NO]; // @"1 day"
45 | ```
46 |
47 | ***Arrays:***
48 |
49 | `GHNSArray+Utils.h`: Random object, safe object at index, uniq, compact
50 |
51 | ```objc
52 | [@[@(1), @(2), @(3)] gh_random]; // Random object
53 | [@[@(1), @(1), @(3)] gh_uniq]; // @[@(1), @(3)]
54 | [@[] gh_objectAtIndex:0]; // nil (Safe objectAtIndex)
55 | [@[@(1), NSNull.null] gh_compact]; // @[@(1)]
56 | ```
57 |
58 | ***Dictionaries:***
59 |
60 | `GHDictionary+Utils.h`:
61 |
62 | ```objc
63 | NSDictionary *dict = @{@"key1": @(2), @"key2": @(3.1), @"key3": @YES};
64 | NSString *JSONString = [dict gh_toJSON:NSJSONWritingPrettyPrinted error:nil];
65 | ```
66 |
67 | ***Strings:***
68 |
69 | `GHNSString+Utils.h`: Stripping, reversing, counting and more.
70 |
71 | ```objc
72 | [NSString gh_isBlank:@" "]; // YES
73 | [NSString gh_isBlank:nil]; // YES
74 | [@" some text " gh_strip]; // @"some text"
75 | [@" " gh_isPresent]; // NO
76 | [@"abc" gh_isPresent]; // YES
77 | [@" " gh_present]; // nil
78 | [@"some text" gh_present]; // @"some text"
79 |
80 | [@"abc" gh_reverse]; // @"cba"
81 |
82 | [@"ababababcde" gh_count:@"ab"]; // 4 (@"ab" appears 4 times)
83 |
84 | [NSString gh_localizedStringForTimeInterval:30]; // "half a minute"
85 | [NSString gh_abbreviatedStringForTimeInterval:30]; // @"30s"
86 |
87 | [@"WWW.test.com" gh_startsWith:@"www." options:NSCaseInsensitiveSearch]; // YES
88 | [@"foo:bar" gh_lastSplitWithString:@":" options:NSCaseInsensitiveSearch]; // @"bar"
89 |
90 | [@"e̊gâds" gh_characters]; // @[@"e̊", @"g", @"â", @"d", @"s"];
91 | ```
92 |
93 | ***URLs:***
94 |
95 | `GHNSURL+Utils.h`: Encoding, escaping, parsing, splitting out or sorting query params, and more.
96 |
97 | ```objc
98 | NSDictionary *dict = [@"c=d&a=b" gh_queryStringToDictionary]; // Dictionary with a => b, c => d
99 | [NSDictionary gh_dictionaryToQueryString:dict sort:YES]; // @"a=b&c=d"
100 | ```
101 |
102 | ***Colors:***
103 |
104 | `GHUIColor+Utils.h`: Colors from hex, color space changes, darken.
105 |
106 | ```objc
107 | UIColor *color = GHUIColorFromRGB(0xBC1128);
108 | GH_HSV hsvColor = [color gh_hsv];
109 | UIColor *darkenedColor = [color gh_darkenColor:0.1]; // Darken 10%
110 | ```
111 |
112 | And more...
113 |
--------------------------------------------------------------------------------
/Tests/GHDefinesTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHDefinesTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel on 10/23/14.
6 | // Copyright (c) 2014 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface GHDefinesTest : XCTestCase { }
15 | @end
16 |
17 | @implementation GHDefinesTest
18 |
19 | - (void)testEquals {
20 | XCTAssertTrue(GHEquals((id)nil, nil));
21 | XCTAssertTrue(GHEquals(@(1), @(1)));
22 | XCTAssertFalse(GHEquals((id)nil, @(1)));
23 | XCTAssertFalse(GHEquals(@(1), nil));
24 | }
25 |
26 | - (void)testBase64 {
27 | GHBase64StringFromNSData([NSData data]);
28 | GHNSDataFromBase64String(@"");
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Tests/GHNSStringEnumeratorTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHNSStringEnumeratorTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 6/12/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import
13 |
14 | @interface GHNSStringEnumeratorTest : XCTestCase {}
15 | @end
16 |
17 | @implementation GHNSStringEnumeratorTest
18 |
19 | - (void)testCharacterSet {
20 | NSString *string = @"matz can't\n patch blues";
21 | GHNSStringEnumerator *enumerator = [[GHNSStringEnumerator alloc] initWithString:string
22 | separatorCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
23 |
24 | NSArray *results = [enumerator allObjects];
25 | NSArray *expected = [NSArray arrayWithObjects:@"matz", @" ", @"can't", @"\n ", @"patch", @" ", @"blues", nil];
26 | XCTAssertEqualObjects(results, expected);
27 | }
28 |
29 | - (void)testCharacterSet2 {
30 | NSString *string = @" matz can't\n patch blues";
31 | GHNSStringEnumerator *enumerator = [[GHNSStringEnumerator alloc] initWithString:string
32 | separatorCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
33 |
34 | NSArray *results = [enumerator allObjects];
35 | NSArray *expected = [NSArray arrayWithObjects:@" ", @"matz", @" ", @"can't", @"\n ", @"patch", @" ", @"blues", nil];
36 | XCTAssertEqualObjects(results, expected);
37 | }
38 |
39 | - (void)testString {
40 | NSString *string = @"matz can't\n patch blues";
41 | GHNSStringEnumerator *enumerator = [[GHNSStringEnumerator alloc] initWithString:string
42 | separatorString:@" "];
43 |
44 | NSArray *results = [enumerator allObjects];
45 | NSArray *expected = [NSArray arrayWithObjects:@"matz", @" ", @"can't\n", @" ", @"patch", @" ", @"blues", nil];
46 | XCTAssertEqualObjects(results, expected);
47 | }
48 |
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/Tests/GHReversableDictionaryTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHReversableDictionaryTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/25/10.
6 | // Copyright 2010. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface GHReversableDictionaryTest : XCTestCase { }
15 | @end
16 |
17 | @implementation GHReversableDictionaryTest
18 |
19 | - (void)test {
20 | GHReversableDictionary *dict = [[GHReversableDictionary alloc] initWithObjectsAndKeys:
21 | @"value1", @"key1",
22 | @"value2", @"key2",
23 | nil];
24 | [dict setObject:@"value3" forKey:@"key3"];
25 |
26 | XCTAssertEqualObjects([dict objectForKey:@"key1"], @"value1");
27 | XCTAssertEqualObjects([dict keyForObject:@"value1"], @"key1");
28 | XCTAssertEqualObjects([dict objectForKey:@"key3"], @"value3");
29 | XCTAssertEqualObjects([dict keyForObject:@"value3"], @"key3");
30 |
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/Tests/GHValidatorsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHValidatorsTest.m
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 10/1/10.
6 | // Copyright 2010 Yelp. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface GHValidatorsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation GHValidatorsTest
18 |
19 | - (void)testValidateEmail {
20 | XCTAssertTrue([GHValidators isEmailAddress:@"test@domain.com"]);
21 | XCTAssertFalse([GHValidators isEmailAddress:@"foo"]);
22 | XCTAssertFalse([GHValidators isEmailAddress:@""]);
23 | XCTAssertFalse([GHValidators isEmailAddress:nil]);
24 | XCTAssertFalse([GHValidators isEmailAddress:@"~gabrielh@gmail.com"]);
25 | XCTAssertTrue([GHValidators isEmailAddress:@"gabrielh@gmail.commmmmmm"]);
26 | }
27 |
28 | - (void)testValidateCreditCard {
29 | XCTAssertFalse([GHValidators isCreditCardNumber:@" "]);
30 | XCTAssertFalse([GHValidators isCreditCardNumber:@""]);
31 | XCTAssertFalse([GHValidators isCreditCardNumber:nil]);
32 | XCTAssertTrue([GHValidators isCreditCardNumber:@"49927398716"]);
33 | XCTAssertFalse([GHValidators isCreditCardNumber:@"1234"]);
34 | XCTAssertFalse([GHValidators isCreditCardNumber:@"abc"]);
35 | }
36 |
37 | - (void)testValidateCreditCardExpiration {
38 | NSDate *date = [NSDate gh_dateWithDay:1 month:12 year:2011 timeZone:nil];
39 |
40 | // Valid
41 | XCTAssertTrue([GHValidators isCreditCardExpiration:@"01/12" date:date]);
42 | XCTAssertTrue([GHValidators isCreditCardExpiration:@"1/12" date:date]);
43 | XCTAssertTrue([GHValidators isCreditCardExpiration:@"1/2012" date:date]);
44 | XCTAssertTrue([GHValidators isCreditCardExpiration:@"01/12" date:date]);
45 |
46 | // Empty
47 | XCTAssertFalse([GHValidators isCreditCardExpiration:@" " date:date]);
48 | XCTAssertFalse([GHValidators isCreditCardExpiration:@"" date:date]);
49 | XCTAssertFalse([GHValidators isCreditCardExpiration:nil date:date]);
50 |
51 | // Expired but valid on the one day
52 | XCTAssertTrue([GHValidators isCreditCardExpiration:@"11/11" date:date]);
53 | NSDate *nextDay = [NSDate gh_dateWithDay:2 month:12 year:2011 timeZone:nil];
54 | XCTAssertFalse([GHValidators isCreditCardExpiration:@"11/11" date:nextDay]);
55 |
56 | // Invalid month or year
57 | XCTAssertFalse([GHValidators isCreditCardExpiration:@"13/12" date:date]);
58 | XCTAssertFalse([GHValidators isCreditCardExpiration:@"0/12" date:date]);
59 |
60 | // Expired
61 | XCTAssertFalse([GHValidators isCreditCardExpiration:@"1/2010" date:date]);
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tests/NSArrayUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArrayUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/9/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSArrayUtilsTest : XCTestCase { }
15 | @end
16 |
17 |
18 | @implementation NSArrayUtilsTest
19 |
20 | - (void)testRandom {
21 | NSSet *set = [NSSet setWithObjects:@"1", @"2", @"3", nil];
22 |
23 | NSString *obj = [[set allObjects] gh_randomObject];
24 | XCTAssertTrue([set containsObject:obj]);
25 | }
26 |
27 | - (void)testReversed {
28 | NSArray *array = [[NSArray arrayWithObjects:@"1", @"2", @"3", nil] gh_arrayByReversingArray];
29 | NSArray *expected = [NSArray arrayWithObjects:@"3", @"2", @"1", nil];
30 | XCTAssertEqualObjects(array, expected);
31 | }
32 |
33 | - (void)testSubarrayWithRange {
34 | NSArray *array = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
35 |
36 | // Test 0 length
37 | NSArray *subarray1 = [array gh_subarrayWithRange:NSMakeRange(0, 0)];
38 | NSArray *expected1 = [NSArray array];
39 | XCTAssertEqualObjects(subarray1, expected1);
40 |
41 | // Test equal length
42 | NSArray *subarray2 = [array gh_subarrayWithRange:NSMakeRange(0, 3)];
43 | XCTAssertEqualObjects(subarray2, array);
44 |
45 | // Test normal
46 | NSArray *subarray3 = [array gh_subarrayWithRange:NSMakeRange(1, 2)];
47 | NSArray *expected3 = [NSArray arrayWithObjects:@"2", @"3", nil];
48 | XCTAssertEqualObjects(subarray3, expected3);
49 |
50 | // Test length overflow
51 | NSArray *subarray4 = [array gh_subarrayWithRange:NSMakeRange(1, 4)];
52 | NSArray *expected4 = [NSArray arrayWithObjects:@"2", @"3", nil];
53 | XCTAssertEqualObjects(subarray4, expected4);
54 |
55 | // Test location overflow -> nil
56 | NSArray *subarray5 = [array gh_subarrayWithRange:NSMakeRange(3, 0)];
57 | XCTAssertNil(subarray5);
58 | }
59 |
60 | - (void)testSubarrayFromLocation {
61 | NSArray *array = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
62 |
63 | // Test 0 position
64 | NSArray *subarray1 = [array gh_subarrayFromLocation:0];
65 | XCTAssertEqualObjects(subarray1, array);
66 |
67 | NSArray *subarray2 = [array gh_subarrayFromLocation:1];
68 | NSArray *expected2 = [NSArray arrayWithObjects:@"2", @"3", nil];
69 | XCTAssertEqualObjects(subarray2, expected2);
70 |
71 | NSArray *subarray3 = [array gh_subarrayFromLocation:2];
72 | NSArray *expected3 = [NSArray arrayWithObjects:@"3", nil];
73 | XCTAssertEqualObjects(subarray3, expected3);
74 |
75 | // Test location == count
76 | NSArray *subarray4 = [array gh_subarrayFromLocation:3];
77 | NSArray *expected4 = [NSArray array];
78 | XCTAssertEqualObjects(subarray4, expected4);
79 |
80 | // Test location overflow
81 | NSArray *subarray5 = [array gh_subarrayFromLocation:4];
82 | NSArray *expected5 = [NSArray array];
83 | XCTAssertEqualObjects(subarray5, expected5);
84 | }
85 |
86 | - (void)testCompact {
87 | NSArray *array = [[NSArray arrayWithObjects:@"1", @"2", [NSNull null], nil] gh_compact];
88 | NSArray *expected = [NSArray arrayWithObjects:@"1", @"2", nil];
89 | XCTAssertEqualObjects(array, expected);
90 |
91 | NSArray *array2 = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
92 | NSArray *compactArray2 = [array2 gh_compact];
93 | NSArray *expected2 = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
94 | XCTAssertEqualObjects(compactArray2, expected2);
95 | XCTAssertEqual(array2, compactArray2); // Will also be ==
96 |
97 | NSArray *array3 = [NSArray array];
98 | NSArray *compactArray3 = [array3 gh_compact];
99 | NSArray *expected3 = [NSArray array];
100 | XCTAssertEqualObjects(compactArray3, expected3);
101 | XCTAssertEqual(array3, compactArray3); // Will also be ==
102 |
103 | NSArray *array4 = [NSArray arrayWithObject:[NSNull null]];
104 | NSArray *compactArray4 = [array4 gh_compact];
105 | NSArray *expected4 = [NSArray array];
106 | XCTAssertEqualObjects(compactArray4, expected4);
107 | }
108 |
109 | - (void)testObjectAtIndex {
110 | id value1 = [[NSArray array] gh_objectAtIndex:0 withDefault:@"default"];
111 | XCTAssertEqualObjects(value1, @"default");
112 |
113 | id value2 = [[NSArray array] gh_objectAtIndex:1];
114 | XCTAssertNil(value2);
115 |
116 | id value3 = [[NSArray array] gh_objectAtIndex:-1];
117 | XCTAssertNil(value3);
118 |
119 | id value4 = [[NSArray arrayWithObject:@"0"] gh_objectAtIndex:0];
120 | XCTAssertEqualObjects(value4, @"0");
121 |
122 | id value5 = [[NSArray arrayWithObject:@"0"] gh_objectAtIndex:1];
123 | XCTAssertNil(value5);
124 |
125 | id value6 = [[NSArray arrayWithObject:@"0"] gh_objectAtIndex:-1];
126 | XCTAssertNil(value6);
127 |
128 | id value7 = [[NSArray arrayWithObjects:@"0", @"1", nil] gh_objectAtIndex:2];
129 | XCTAssertNil(value7);
130 |
131 | id value8 = [[NSArray arrayWithObjects:@"0", @"1", nil] gh_objectAtIndex:1];
132 | XCTAssertEqualObjects(value8, @"1");
133 | }
134 |
135 | - (void)testJSON {
136 | NSString *JSONString = [@[@"string", @(2), @(3.1), @YES] gh_toJSON:0 error:nil];
137 | XCTAssertEqualObjects(@"[\"string\",2,3.1,true]", JSONString);
138 | }
139 |
140 | - (void)testUniq {
141 | NSArray *uniq = [@[@(1), @(1), @(3)] gh_uniq];
142 | NSArray *expected = @[@(1), @(3)];
143 | XCTAssertEqualObjects(uniq, expected);
144 | }
145 |
146 | @end
147 |
--------------------------------------------------------------------------------
/Tests/NSDataUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDataUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/14/14.
6 | // Copyright (c) 2014 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSDataUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSDataUtilsTest
18 |
19 | - (void)testHexString {
20 | NSString *testString = @"test string";
21 | NSData *data = [testString dataUsingEncoding:NSUTF8StringEncoding];
22 | XCTAssertEqualObjects(@"7465737420737472696E67", [data gh_hexString]);
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Tests/NSDateParsingTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDateParsingTest.m
3 | // GHKit
4 | //
5 | // Created by Gabe on 6/30/08.
6 | // Copyright 2008 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSDateParsingTest : XCTestCase { }
15 | @end
16 |
17 | @interface NSDate (Private)
18 | - (id)initWithString:(NSString *)s;
19 | @end
20 |
21 | @implementation NSDateParsingTest
22 |
23 | - (void)testFormatRFC822 {
24 | NSString *rfc822 = @"Sun, 06 Nov 1994 08:49:37 +0000";
25 | NSDate *date = [[NSDate alloc] initWithString:@"1994-11-06 08:49:37 +0000"];
26 | NSString *formatted = [date gh_formatRFC822];
27 | XCTAssertEqualObjects(formatted, rfc822);
28 | }
29 |
30 | - (void)testParseHTTPDate {
31 | NSDate *date = [[NSDate alloc] initWithString:@"1994-11-06 08:49:37 +0000"];
32 |
33 | NSString *rfc1123 = @"Sun, 06 Nov 1994 08:49:37 GMT"; //; RFC 822, updated by RFC 1123
34 | NSString *rfc850 = @"Sunday, 06-Nov-94 08:49:37 GMT"; //; RFC 850, obsoleted by RFC 1036
35 | NSString *ascTime = @"Sun Nov 6 08:49:37 1994"; //; ANSI C's asctime() format
36 |
37 | NSDate *parsed = nil;
38 |
39 | parsed = [NSDate gh_parseHTTP:rfc1123];
40 | XCTAssertEqualObjects(parsed, date);
41 |
42 | parsed = [NSDate gh_parseHTTP:rfc850];
43 | XCTAssertEqualObjects(parsed, date);
44 |
45 | parsed = [NSDate gh_parseHTTP:ascTime];
46 | XCTAssertEqualObjects(parsed, date);
47 | }
48 |
49 | - (void)testOffset {
50 | // Set local time zone to eastern time
51 | [NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithName:@"America/New_York"]];
52 | NSDate *date = [NSDate date];
53 | NSDate *newDate = [NSDate gh_parseTimeSinceEpoch:[NSNumber numberWithDouble:[date timeIntervalSince1970]] withDefault:nil offsetForTimeZone:[NSTimeZone timeZoneWithName:@"America/Los_Angeles"]];
54 | // Times should be three hours (in seconds) apart
55 | XCTAssertEqualWithAccuracy(([newDate timeIntervalSince1970] - [date timeIntervalSince1970]), (3.0 * 60.0 * 60.0), 0.01);
56 | }
57 |
58 | - (void)testTimestamp {
59 | NSDate *date = [NSDate gh_parseTimeSinceEpoch:@(1234567890)];
60 | XCTAssertEqualObjects(@(1234567890), [NSNumber numberWithUnsignedLongLong:[date timeIntervalSince1970]]);
61 | }
62 |
63 | - (void)testISO8601 {
64 | NSDate *date = [NSDate gh_parseISO8601:@"1997-07-16T19:20:30.045Z"];
65 | XCTAssertEqual(869080830.045, [date timeIntervalSince1970]);
66 |
67 | NSDate *date2 = [NSDate gh_parseISO8601:@"1997-07-16T19:20:30Z"];
68 | XCTAssertEqual((NSTimeInterval)869080830, [date2 timeIntervalSince1970]);
69 |
70 | NSDate *date3 = [NSDate gh_parseISO8601:@"2014-01-28T16:44:58-08:00"];
71 | XCTAssertEqual((NSTimeInterval)1390956298, [date3 timeIntervalSince1970]);
72 |
73 | NSDate *date4 = [NSDate gh_parseISO8601:@"2014-01-28T16:44:58+01:00"];
74 | XCTAssertEqual((NSTimeInterval)1390923898, [date4 timeIntervalSince1970]);
75 |
76 | NSDate *date5 = [NSDate gh_parseISO8601:@"2014-01-28T16:44:58.045+01:00"];
77 | XCTAssertEqual((NSTimeInterval)1390923898.045, [date5 timeIntervalSince1970]);
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/Tests/NSDateUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+UtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 2/18/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSDateUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSDateUtilsTest
18 |
19 | - (void)testYesterday {
20 | NSDate *date = [[NSDate date] dateByAddingTimeInterval:-(60 * 60 * 24)]; // This could fail daylight savings
21 | XCTAssertTrue([date gh_wasYesterday]);
22 | }
23 |
24 | - (void)testTomorrow {
25 | NSDate *date = [[NSDate date] dateByAddingTimeInterval:(60 * 60 * 24)]; // This could fail daylight savings
26 | XCTAssertTrue([date gh_isTomorrow]);
27 | }
28 |
29 | - (void)testWeekday {
30 | NSLog(@"[NSDate gh_tomorrow]: %@", [NSDate gh_tomorrow]);
31 | XCTAssertEqualObjects([[NSDate gh_yesterday] gh_weekday:nil], @"Yesterday");
32 | XCTAssertEqualObjects([[NSDate gh_tomorrow] gh_weekday:nil], @"Tomorrow");
33 | XCTAssertEqualObjects([[NSDate date] gh_weekday:nil], @"Today");
34 |
35 | NSDate *date = [[NSDate date] gh_addDays:-3];
36 |
37 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
38 | [dateFormatter setDateFormat:@"EEEE"];
39 | NSString *weekday = [dateFormatter stringFromDate:date];
40 | XCTAssertEqualObjects(weekday, [date gh_weekday:dateFormatter]);
41 | }
42 |
43 | - (void)testDate {
44 | NSInteger year = [[NSDate date] gh_year] - 1930;
45 |
46 | NSDate *date = [NSDate gh_dateWithDay:1 month:1 year:0 addDay:0 addMonth:0 addYear:-30 timeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
47 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
48 | [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
49 | [dateFormatter setDateStyle:NSDateFormatterShortStyle];
50 | NSString *dateString = [dateFormatter stringFromDate:date];
51 | NSString *expected = [NSString stringWithFormat:@"1/1/%ld", (long)year];
52 | XCTAssertEqualObjects(dateString, expected);
53 | }
54 |
55 | - (void)testComponents {
56 | NSDate *date = [NSDate gh_dateWithDay:1 month:2 year:2012 timeZone:nil];
57 | XCTAssertTrue([date gh_day] == 1);
58 | XCTAssertTrue([date gh_month] == 2);
59 | XCTAssertTrue([date gh_year] == 2012);
60 | }
61 |
62 | - (void)testMonthSymbolsForFormat {
63 | NSArray *monthSymbols = [NSDate gh_monthSymbols];
64 | NSLog(@"%@", [monthSymbols description]);
65 | }
66 |
67 | @end
--------------------------------------------------------------------------------
/Tests/NSDictionaryNSNullTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionaryNSNullTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/1/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSDictionaryNSNullTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSDictionaryNSNullTest
18 |
19 | - (void)testNilValues {
20 | NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
21 | NSDictionary *expected = [NSDictionary dictionaryWithObjectsAndKeys:[NSNull null], @"key1", @"value2", @"key2", [NSNull null], @"key3", nil];
22 | XCTAssertEqualObjects(dict, expected);
23 | }
24 |
25 | - (void)testPrematureNilKeyDoesntCrash {
26 | NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", nil, nil, @"", @"", nil, nil];
27 | NSDictionary *expected = [NSDictionary dictionaryWithObjectsAndKeys:[NSNull null], @"key1", nil];
28 | XCTAssertEqualObjects(dict, expected);
29 | }
30 |
31 | //- (void)testValueForKey {
32 | // NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
33 | // id value = [dict valueForKey:@"key1"];
34 | // XCTAssertNil(value, @"Should handle in KVC");
35 | //}
36 |
37 | - (void)testEmpty {
38 | NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:nil];
39 | NSDictionary *expected = [NSDictionary dictionary];
40 | XCTAssertEqualObjects(dict, expected);
41 | }
42 |
43 | - (NSDictionary *)_testVAList:(id)obj ignoreNil:(BOOL)ignoreNil keysAndObjects:(id)firstKey, ... {
44 | va_list args;
45 | va_start(args, firstKey);
46 | NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNilWithKey:firstKey args:args ignoreNil:ignoreNil];
47 | va_end(args);
48 | return dict;
49 | }
50 |
51 | - (void)testVAList {
52 | NSDictionary *dict = [self _testVAList:nil ignoreNil:NO keysAndObjects:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
53 | NSDictionary *expected = [NSDictionary dictionaryWithObjectsAndKeys:[NSNull null], @"key1", @"value2", @"key2", [NSNull null], @"key3", nil];
54 | XCTAssertEqualObjects(dict, expected);
55 |
56 | NSDictionary *dict2 = [self _testVAList:nil ignoreNil:YES keysAndObjects:@"key1", nil, @"key2", @"value2", @"key3", nil, nil];
57 | NSDictionary *expected2 = [NSDictionary dictionaryWithObjectsAndKeys:@"value2", @"key2", nil];
58 | XCTAssertEqualObjects(dict2, expected2);
59 |
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/Tests/NSDictionaryUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionaryUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 6/4/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSDictionaryUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSDictionaryUtilsTest
18 |
19 | - (void)testBoolValue {
20 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
21 | @"1", @"key1",
22 | [NSNumber numberWithBool:YES], @"key2",
23 | [NSNumber numberWithBool:NO], @"key3",
24 | [NSNull null], @"key4",
25 | nil];
26 |
27 | XCTAssertTrue([[dict gh_boolValueForKey:@"key1"] boolValue]);
28 | XCTAssertTrue([[dict gh_boolValueForKey:@"key2"] boolValue]);
29 | XCTAssertFalse([[dict gh_boolValueForKey:@"key3"] boolValue]);
30 | XCTAssertFalse([[dict gh_boolValueForKey:@"key4"] boolValue]);
31 | }
32 |
33 | - (void)testDataValue {
34 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
35 | @"hwLWnp0tXoCzs+W0UdVPUaBSfiW1Q5B9m6xzDPFXvJqpqXvk1nnmMBNziXJWE4M823j8oSRl0uLhCAhxJW6ah7/a25DjGzwa", @"key1",
36 | nil];
37 | NSData *data = [dict gh_dataAsBase64ForKey:@"key1" options:0];
38 | NSData *expected = [[NSData alloc] initWithBase64EncodedString:@"hwLWnp0tXoCzs+W0UdVPUaBSfiW1Q5B9m6xzDPFXvJqpqXvk1nnmMBNziXJWE4M823j8oSRl0uLhCAhxJW6ah7/a25DjGzwa" options:0];
39 | XCTAssertEqualObjects(data, expected);
40 | }
41 |
42 | - (void)testHasAllKeys {
43 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
44 | @"1", @"key1",
45 | [NSNumber numberWithBool:YES], @"key2",
46 | [NSNumber numberWithBool:NO], @"key3",
47 | [NSNull null], @"key4",
48 | nil];
49 |
50 | BOOL b;
51 | b = [dict gh_hasAllKeys:nil];
52 | XCTAssertTrue(b);
53 | b = [dict gh_hasAllKeys:@"key1", nil];
54 | XCTAssertTrue(b);
55 | b = [dict gh_hasAllKeys:@"key1", @"key3", nil];
56 | XCTAssertTrue(b);
57 | b = [dict gh_hasAllKeys:@"key1", @"key4", nil];
58 | XCTAssertFalse(b);
59 | b = [dict gh_hasAllKeys:@"key1", @"key5", nil];
60 | XCTAssertFalse(b);
61 | b = [dict gh_hasAllKeys:@"key5", @"key1", nil];
62 | XCTAssertFalse(b);
63 | }
64 |
65 | - (void)testSubsetWithKeys {
66 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
67 | @"1", @"key1",
68 | @"2", @"key2",
69 | nil];
70 |
71 | NSDictionary *dictSubset = [dict gh_dictionarySubsetWithKeys:[NSArray arrayWithObject:@"key1"]];
72 | NSDictionary *expected = [NSDictionary dictionaryWithObjectsAndKeys:@"1", @"key1", nil];
73 | XCTAssertEqualObjects(dictSubset, expected);
74 |
75 | // Test missing key
76 | NSDictionary *dictSubset2 = [dict gh_dictionarySubsetWithKeys:[NSArray arrayWithObject:@"key3"]];
77 | NSDictionary *expected2 = [NSDictionary dictionary];
78 | XCTAssertEqualObjects(dictSubset2, expected2);
79 | }
80 |
81 | - (void)testCompact {
82 | NSMutableDictionary *dict = [@{@"key1": @"1", @"key2": [NSNull null]} mutableCopy];
83 |
84 | NSMutableDictionary *expected = [@{@"key1": @"1"} mutableCopy];
85 |
86 | NSDictionary *after = [dict gh_compactDictionary];
87 | XCTAssertEqualObjects(after, expected);
88 | }
89 |
90 | - (void)testJSON {
91 | NSDictionary *dict = @{@"key1": @(2), @"key2": @(3.1), @"key3": @YES};
92 | NSString *JSONString = [dict gh_toJSON:NSJSONWritingPrettyPrinted error:nil];
93 | NSLog(@"%@", JSONString);
94 | NSDictionary *dict2 = [NSJSONSerialization JSONObjectWithData:[JSONString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
95 | XCTAssertEqualObjects(dict, dict2);
96 | }
97 |
98 | @end
--------------------------------------------------------------------------------
/Tests/NSErrorUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSErrorUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/7/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSErrorUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSErrorUtilsTest
18 |
19 | //- (void)testErrorFromException {
20 | // @try {
21 | // [NSException raise:NSGenericException format:@"my reason"];
22 | // } @catch(NSException *e) {
23 | // NSError *error = [NSError gh_errorFromException:e];
24 | // NSLog(@"Error: %@", error);
25 | // }
26 | //}
27 |
28 | - (void)testFullDescription {
29 | NSError *detailedError = [NSError errorWithDomain:@"Detail" code:-2 userInfo:nil];
30 |
31 | NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSArray arrayWithObject:detailedError] forKey:@"NSDetailedErrors"];
32 | NSError *error = [NSError errorWithDomain:@"Test" code:-1 userInfo:userInfo];
33 | NSString *fullDescription = [error gh_fullDescription];
34 | NSLog(@"Full description: %@", fullDescription);
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/Tests/NSFileManagerUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSFileManager+UtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 3/9/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSFileManagerUtilsTest : XCTestCase { }
15 | @end
16 |
17 |
18 | @implementation NSFileManagerUtilsTest
19 |
20 | - (void)testEnsureDirectory {
21 | NSError *error = nil;
22 | NSString *path = [NSFileManager gh_temporaryFile:@"Test" deleteIfExists:YES error:&error];
23 | if (error) XCTFail(@"Error: %@", error);
24 | BOOL success = [NSFileManager gh_ensureDirectoryExists:path created:nil error:&error];
25 | if (error) XCTFail(@"Error: %@", error);
26 | XCTAssertTrue(success);
27 | }
28 |
29 | - (void)testFileSize {
30 | NSString *path = [NSFileManager gh_pathToResource:@"test.file"];
31 | XCTAssertTrue([NSFileManager gh_exist:path]);
32 | NSNumber *fileSize = [NSFileManager gh_fileSize:path error:nil];
33 | XCTAssertEqual([fileSize longValue], 10L);
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/Tests/NSMutableArrayUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArrayUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/1/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSMutableArrayUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSMutableArrayUtilsTest
18 |
19 | - (void)testInsertObjectsAtIndex {
20 | NSArray *objects = [NSArray arrayWithObjects:@"2", @"3", nil];
21 |
22 | NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1", nil];
23 | [array gh_insertObjects:objects atIndex:1];
24 |
25 | NSArray *expected = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
26 | XCTAssertEqualObjects(array, expected);
27 | }
28 |
29 | - (void)testInsertObjectsAtIndexEmpty {
30 | NSArray *objects = [NSArray array];
31 |
32 | NSMutableArray *array = [NSMutableArray array];
33 | [array gh_insertObjects:objects atIndex:0];
34 |
35 | NSArray *expected = [NSArray array];
36 | XCTAssertEqualObjects(array, expected);
37 | }
38 |
39 | - (void)testCompact {
40 | NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1", @"2", [NSNull null], nil];
41 | [array gh_mutableCompact];
42 | NSMutableArray *expected = [NSMutableArray arrayWithObjects:@"1", @"2", nil];
43 | XCTAssertEqualObjects(array, expected);
44 |
45 | NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", nil];
46 | [array2 gh_mutableCompact];
47 | NSMutableArray *expected2 = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", nil];
48 | XCTAssertEqualObjects(array2, expected2);
49 |
50 | NSMutableArray *array3 = [NSMutableArray array];
51 | [array3 gh_mutableCompact];
52 | NSMutableArray *expected3 = [NSMutableArray array];
53 | XCTAssertEqualObjects(array3, expected3);
54 |
55 | NSMutableArray *array4 = [NSMutableArray arrayWithObject:[NSNull null]];
56 | [array4 gh_mutableCompact];
57 | NSMutableArray *expected4 = [NSMutableArray array];
58 | XCTAssertEqualObjects(array4, expected4);
59 | }
60 |
61 | - (void)testAddObjectIfNotNil {
62 | NSMutableArray *array = [NSMutableArray array];
63 | [array gh_addObject:nil];
64 | [array gh_addObject:@"1"];
65 | XCTAssertTrue([array count] == 1);
66 | }
67 |
68 | - (void)testReplaceObject {
69 | NSUInteger index;
70 |
71 | NSMutableArray *emptyArray = [NSMutableArray array];
72 | index = [emptyArray gh_replaceObject:@"1" withObject:nil];
73 | XCTAssertEqual(index, (NSUInteger)NSNotFound);
74 |
75 | NSMutableArray *array = [NSMutableArray arrayWithObject:@"1"];
76 | index = [array gh_replaceObject:@"1" withObject:@"2"];
77 | XCTAssertEqual(index, (NSUInteger)0);
78 | NSMutableArray *expected1 = [NSMutableArray arrayWithObject:@"2"];
79 | XCTAssertEqualObjects(array, expected1);
80 |
81 | index = [array gh_replaceObject:@"1" withObject:@"3"];
82 | XCTAssertEqual(index, (NSUInteger)NSNotFound);
83 | XCTAssertEqualObjects(array, expected1);
84 | }
85 |
86 | - (void)testRemoveLastObject {
87 | NSMutableArray *array = [NSMutableArray arrayWithObject:@"1"];
88 | id obj = [array gh_removeLastObject];
89 | XCTAssertEqualObjects(obj, @"1");
90 | NSMutableArray *expected = [NSMutableArray array];
91 | XCTAssertEqualObjects(array, expected);
92 | XCTAssertNil([array gh_removeLastObject]);
93 | }
94 |
95 | @end
96 |
97 |
--------------------------------------------------------------------------------
/Tests/NSMutableDictionaryUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableDictionaryUtilsTest.m
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 7/1/10.
6 | // Copyright 2010. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSMutableDictionaryUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSMutableDictionaryUtilsTest
18 |
19 | - (void)testMutableCompact {
20 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
21 | @"1", @"key1",
22 | [NSNull null], @"key2",
23 | nil];
24 |
25 | NSMutableDictionary *expected = [NSMutableDictionary dictionaryWithObjectsAndKeys:
26 | @"1", @"key1",
27 | nil];
28 |
29 | [dict gh_mutableCompact];
30 | XCTAssertEqualObjects(dict, expected);
31 |
32 | NSMutableDictionary *dict2 = [@{@"key2": NSNull.null, @"key1": @"1"} mutableCopy];
33 |
34 | NSMutableDictionary *expected2 = [@{@"key1": @"1"} mutableCopy];
35 | [dict2 gh_mutableCompact];
36 | XCTAssertEqualObjects(dict2, expected2);
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/Tests/NSNumberUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumberUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/9/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSNumberUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSNumberUtilsTest
18 |
19 | - (void)testHumanSize {
20 | long long l = 5028463290;
21 | NSNumber *n = [NSNumber numberWithLongLong:l];
22 | NSString *sizeString = [n gh_humanSize];
23 | XCTAssertEqualObjects(sizeString, @"4.68 GB");
24 |
25 | long long maxll = 9223372036854775807; // LLONG_MAX
26 | NSNumber *mll = [NSNumber numberWithLongLong:maxll];
27 | XCTAssertNotNil(mll);
28 | NSString *maxllSizeString = [mll gh_humanSize];
29 | XCTAssertEqualObjects(maxllSizeString, @"8589934592.00 GB");
30 | NSLog(@"maxllSizeString=%@", maxllSizeString);
31 | }
32 |
33 | - (void)testOrdinalize {
34 | XCTAssertEqualObjects([[NSNumber numberWithInteger:1] gh_ordinalize], @"1st");
35 | XCTAssertEqualObjects([[NSNumber numberWithInteger:2] gh_ordinalize], @"2nd");
36 | XCTAssertEqualObjects([[NSNumber numberWithInteger:3] gh_ordinalize], @"3rd");
37 | XCTAssertEqualObjects([[NSNumber numberWithInteger:4] gh_ordinalize], @"4th");
38 | XCTAssertEqualObjects([[NSNumber numberWithInteger:5] gh_ordinalize], @"5th");
39 | XCTAssertEqualObjects([[NSNumber numberWithInteger:6] gh_ordinalize], @"6th");
40 | XCTAssertEqualObjects([[NSNumber numberWithInteger:7] gh_ordinalize], @"7th");
41 | XCTAssertEqualObjects([[NSNumber numberWithInteger:8] gh_ordinalize], @"8th");
42 | XCTAssertEqualObjects([[NSNumber numberWithInteger:9] gh_ordinalize], @"9th");
43 | XCTAssertEqualObjects([[NSNumber numberWithInteger:10] gh_ordinalize], @"10th");
44 | XCTAssertEqualObjects([[NSNumber numberWithInteger:11] gh_ordinalize], @"11th");
45 | XCTAssertEqualObjects([[NSNumber numberWithInteger:12] gh_ordinalize], @"12th");
46 | XCTAssertEqualObjects([[NSNumber numberWithInteger:13] gh_ordinalize], @"13th");
47 | XCTAssertEqualObjects([[NSNumber numberWithInteger:14] gh_ordinalize], @"14th");
48 | XCTAssertEqualObjects([[NSNumber numberWithInteger:111] gh_ordinalize], @"111th");
49 | XCTAssertEqualObjects([[NSNumber numberWithInteger:212] gh_ordinalize], @"212th");
50 | XCTAssertEqualObjects([[NSNumber numberWithInteger:313] gh_ordinalize], @"313th");
51 | XCTAssertEqualObjects([[NSNumber numberWithInteger:221] gh_ordinalize], @"221st");
52 | XCTAssertEqualObjects([[NSNumber numberWithInteger:222] gh_ordinalize], @"222nd");
53 |
54 | XCTAssertEqualObjects([NSNumber gh_ordinalize:1], @"1st");
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Tests/NSObjectUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObjectUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 7/8/09.
6 | // Copyright 2009. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @import GHKit;
13 |
14 | @interface NSObjectUtilsTest : XCTestCase { }
15 | @end
16 |
17 | @implementation NSObjectUtilsTest
18 |
19 | - (void)testNotNSNull {
20 | id foo = nil;
21 | XCTAssertFalse([foo gh_isNotNSNull]);
22 | foo = [NSNull null];
23 | XCTAssertFalse([foo gh_isNotNSNull]);
24 | foo = @"1";
25 | XCTAssertTrue([foo gh_isNotNSNull]);
26 | }
27 |
28 | @end
--------------------------------------------------------------------------------
/Tests/NSStringTimeIntervalTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSStringTimeIntervalTest.m
3 | //
4 | // Created by Gabe on 6/6/08.
5 | // Copyright 2008 rel.me. Some rights reserved.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | @import GHKit;
12 |
13 | @interface NSStringTimeIntervalTest : XCTestCase { }
14 | @end
15 |
16 | @implementation NSStringTimeIntervalTest
17 |
18 | - (void)testStringForTimeInterval {
19 | XCTAssertEqualObjects(@"less than a minute", [NSString gh_stringForTimeInterval:29.0 includeSeconds:NO]);
20 | XCTAssertEqualObjects(@"1 minute", [NSString gh_stringForTimeInterval:30.0 includeSeconds:NO]);
21 |
22 | XCTAssertEqualObjects(@"less than 5 seconds", [NSString gh_stringForTimeInterval:4.0 includeSeconds:YES]);
23 | XCTAssertEqualObjects(@"less than 10 seconds", [NSString gh_stringForTimeInterval:5.0 includeSeconds:YES]);
24 | XCTAssertEqualObjects(@"less than 20 seconds", [NSString gh_stringForTimeInterval:19.0 includeSeconds:YES]);
25 | XCTAssertEqualObjects(@"half a minute", [NSString gh_stringForTimeInterval:29.0 includeSeconds:YES]);
26 | XCTAssertEqualObjects(@"less than a minute", [NSString gh_stringForTimeInterval:59.0 includeSeconds:YES]);
27 | XCTAssertEqualObjects(@"1 minute", [NSString gh_stringForTimeInterval:60.0 includeSeconds:YES]);
28 |
29 | XCTAssertEqualObjects(@"1 minute", [NSString gh_stringForTimeInterval:89.0 includeSeconds:YES]);
30 | XCTAssertEqualObjects(@"2 minutes", [NSString gh_stringForTimeInterval:90.0 includeSeconds:YES]);
31 |
32 | XCTAssertEqualObjects(@"44 minutes", [NSString gh_stringForTimeInterval:(44.0 * 60.0) includeSeconds:YES]);
33 | XCTAssertEqualObjects(@"about 1 hour", [NSString gh_stringForTimeInterval:(45.0 * 60.0) includeSeconds:YES]);
34 | XCTAssertEqualObjects(@"about 1 hour", [NSString gh_stringForTimeInterval:(89.0 * 60.0) includeSeconds:YES]);
35 | XCTAssertEqualObjects(@"about 2 hours", [NSString gh_stringForTimeInterval:(90.0 * 60.0) includeSeconds:YES]);
36 | XCTAssertEqualObjects(@"1 day", [NSString gh_stringForTimeInterval:(47.0 * 60.0 * 60.0) includeSeconds:YES]);
37 | XCTAssertEqualObjects(@"2 days", [NSString gh_stringForTimeInterval:(48.0 * 60.0 * 60.0) includeSeconds:YES]);
38 | XCTAssertEqualObjects(@"3 days", [NSString gh_stringForTimeInterval:(60.0 * 60.0 * 60.0) includeSeconds:YES]);
39 | XCTAssertEqualObjects(@"3 days", [NSString gh_stringForTimeInterval:(72.0 * 60.0 * 60.0) includeSeconds:YES]);
40 | XCTAssertEqualObjects(@"15 days", [NSString gh_stringForTimeInterval:(15.0 * 24.0 * 60.0 * 60.0) includeSeconds:YES]);
41 | XCTAssertEqualObjects(@"about 1 month", [NSString gh_stringForTimeInterval:(30.0 * 24.0 * 60.0 * 60.0) includeSeconds:YES]);
42 | XCTAssertEqualObjects(@"2 months", [NSString gh_stringForTimeInterval:(60.0 * 24.0 * 60.0 * 60.0) includeSeconds:YES]);
43 |
44 | XCTAssertEqualObjects(@"about 1 year", [NSString gh_stringForTimeInterval:(365.0 * 24.0 * 60.0 * 60.0) includeSeconds:YES]);
45 | XCTAssertEqualObjects(@"over 2 years", [NSString gh_stringForTimeInterval:(2.0 * 365.0 * 24.0 * 60.0 * 60.0) includeSeconds:YES]);
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Tests/NSURLUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSURL+UtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel Handford on 1/13/09.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | @import GHKit;
12 |
13 | @interface NSURLUtilsTest : XCTestCase { }
14 | @end
15 |
16 | @implementation NSURLUtilsTest
17 |
18 | - (void)testEncode {
19 | NSString *test1 = @"~!@#$%^&*(){}[]=:/,;?+'\"\\";
20 | NSString *escaped1 = [NSURL gh_encode:test1];
21 | NSString *expected1 = @"~!@#$%25%5E&*()%7B%7D%5B%5D=:/,;?+'%22%5C";
22 | XCTAssertEqualObjects(escaped1, expected1);
23 | }
24 |
25 | - (void)testEncodeComponent {
26 | NSString *test1 = @"~!@#$%^&*(){}[]=:/,;?+'\"\\";
27 | NSString *escaped1 = [NSURL gh_encodeComponent:test1];
28 | NSString *expected1 = @"~!%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%3A%2F%2C%3B%3F%2B'%22%5C";
29 | XCTAssertEqualObjects(escaped1, expected1);
30 | }
31 |
32 | - (void)testEscapeAll {
33 | NSString *test1 = @"~!@#$%^&*(){}[]=:/,;?+'\"\\~!*()'";
34 | NSString *escaped1 = [NSURL gh_escapeAll:test1];
35 | NSString *expected1 = @"%7E%21%40%23%24%25%5E%26%2A%28%29%7B%7D%5B%5D%3D%3A%2F%2C%3B%3F%2B%27%22%5C%7E%21%2A%28%29%27";
36 | XCTAssertEqualObjects(escaped1, expected1);
37 | }
38 |
39 | - (void)testDictionaryToQueryString {
40 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
41 | NSString *s = [NSURL gh_dictionaryToQueryString:dict sort:YES];
42 | XCTAssertEqualObjects(s, @"key1=value1&key2=value2");
43 |
44 | NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"AAA", @"value2", @"BBB", @"value3", @"CCC", nil];
45 | NSString *s2 = [NSURL gh_dictionaryToQueryString:dict2 sort:YES];
46 | XCTAssertEqualObjects(s2, @"AAA=value1&BBB=value2&CCC=value3");
47 | }
48 |
49 | - (void)testDictionaryWithObjectsToQueryString {
50 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:1], @"key1", @"[]", @"key2", nil];
51 | NSString *s = [NSURL gh_dictionaryToQueryString:dict sort:YES];
52 | XCTAssertEqualObjects(s, @"key1=1&key2=%5B%5D");
53 | }
54 |
55 | - (void)testDictionaryWithNSNull {
56 | NSDictionary *dict = [NSDictionary gh_dictionaryWithKeysAndObjectsMaybeNil:@"key1", @"value1", @"key2", nil, nil];
57 | NSString *s = [NSURL gh_dictionaryToQueryString:dict sort:YES];
58 | XCTAssertEqualObjects(s, @"key1=value1");
59 | }
60 |
61 | - (void)testQueryStringToDictionary {
62 | NSDictionary *dict = [NSURL gh_queryStringToDictionary:@"key1=value1&key2=value2"];
63 | XCTAssertEqualObjects(@"value1", [dict objectForKey:@"key1"]);
64 | XCTAssertEqualObjects(@"value2", [dict objectForKey:@"key2"]);
65 |
66 | NSDictionary *dict2 = [NSURL gh_queryStringToDictionary:@"key1==value1&&key2=value2%20&key3=value3=more"];
67 | XCTAssertEqualObjects(@"=value1", [dict2 objectForKey:@"key1"]);
68 | XCTAssertEqualObjects(@"value2 ", [dict2 objectForKey:@"key2"]);
69 | XCTAssertEqualObjects(@"value3=more", [dict2 objectForKey:@"key3"]);
70 | }
71 |
72 | - (void)testDeriveWithQuery {
73 | NSURL *URL = [NSURL URLWithString:@"http://api.yelp.com/path?key1=value1&key2=value2"];
74 | NSURL *derivedURL = [URL gh_deriveWithQuery:@"key3=value3&key4=value4"];
75 | XCTAssertEqualObjects([derivedURL description], @"http://api.yelp.com/path?key3=value3&key4=value4");
76 | }
77 |
78 | - (void)testDeriveComplexWithQuery {
79 | NSURL *URL = [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?key1=value1&key2=value2#myfrag"];
80 | NSURL *derivedURL = [URL gh_deriveWithQuery:@"key3=value3&key4=value4"];
81 | XCTAssertEqualObjects([derivedURL description], @"https://user:pass@api.yelp.com:400/path?key3=value3&key4=value4#myfrag");
82 | }
83 |
84 | - (void)testCanonical {
85 | NSURL *URL = [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?b=c&a=d#myfrag"];
86 | NSURL *canonical = [URL gh_canonical];
87 | XCTAssertEqualObjects(canonical, [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?a=d&b=c#myfrag"]);
88 |
89 | NSURL *URL2 = [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?b=c&a=d&ignore=ignored#myfrag"];
90 | NSURL *canonical2 = [URL2 gh_canonicalWithIgnore:[NSArray arrayWithObject:@"ignore"]];
91 | XCTAssertEqualObjects(canonical2, [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?a=d&b=c#myfrag"]);
92 | }
93 |
94 | - (void)testFilter {
95 | NSURL *URL = [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?b=c&a=d&ignore=ignored#myfrag"];
96 | NSURL *filtered = [URL gh_filterQueryParams:[NSArray arrayWithObjects:@"ignore", @"ignore2", nil] sort:YES];
97 | XCTAssertEqualObjects(filtered, [NSURL URLWithString:@"https://user:pass@api.yelp.com:400/path?a=d&b=c#myfrag"]);
98 | }
99 |
100 | - (void)testQueryDictionaryWithArray {
101 | NSArray *array1 = [NSArray arrayWithObjects:@"va", @"vb", @"vc", nil];
102 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:array1, @"key1", @"value2", @"key2", nil];
103 | NSString *s = [NSURL gh_dictionaryToQueryString:dict sort:YES];
104 | XCTAssertEqualObjects(s, @"key1=va%2Cvb%2Cvc&key2=value2");
105 | }
106 |
107 | - (void)testQueryDictionaryWithSet {
108 | NSSet *set1 = [NSSet setWithObjects:@"va", @"vb", nil];
109 | NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:set1, @"key1", nil];
110 | NSString *s = [NSURL gh_dictionaryToQueryString:dict sort:YES];
111 | XCTAssertTrue([s isEqualToString:@"key1=va%2Cvb"] || [s isEqualToString:@"key1=vb%2Cva"]);
112 | }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/Tests/iOS/GHUIColorUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIColor+UtilsTest.m
3 | // GHKitIPhone
4 | //
5 | // Created by Gabriel Handford on 12/18/08.
6 | // Copyright 2008 Gabriel Handford
7 | //
8 | // Permission is hereby granted, free of charge, to any person
9 | // obtaining a copy of this software and associated documentation
10 | // files (the "Software"), to deal in the Software without
11 | // restriction, including without limitation the rights to use,
12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the
14 | // Software is furnished to do so, subject to the following
15 | // conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be
18 | // included in all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | // OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | #import
31 |
32 | #import
33 |
34 | @interface GHUIColorUtilsTest : XCTestCase { }
35 | @end
36 |
37 | @implementation GHUIColorUtilsTest
38 |
39 | - (void)testHSV {
40 | UIColor *color = [[UIColor alloc] initWithRed:0.20 green:0.4 blue:0.6 alpha:1.0];
41 | GH_HSV hsv = [color gh_hsv];
42 | // h=0.58, s=0.67, v=0.60
43 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.hue]), @"0.58");
44 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.saturation]), @"0.67");
45 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.value]), @"0.60");
46 | }
47 |
48 |
49 | - (void)testHSVRed {
50 | UIColor *color = [[UIColor alloc] initWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];
51 | GH_HSV hsv = [color gh_hsv];
52 | // h=0.00, s=1.00, v=1.00
53 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.hue]), @"0.00");
54 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.saturation]), @"1.00");
55 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", hsv.value]), @"1.00");
56 | }
57 |
58 | - (void)testGetComponents {
59 | CGFloat info[4];
60 | [[UIColor magentaColor] gh_getComponents:info];
61 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", info[0]]), @"1.00");
62 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", info[1]]), @"0.00");
63 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", info[2]]), @"1.00");
64 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", info[3]]), @"1.00");
65 | }
66 |
67 | - (void)testGetRGB {
68 | CGFloat red, green, blue, alpha;
69 | [[UIColor magentaColor] gh_getRed:&red green:&green blue:&blue alpha:&alpha];
70 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", red]), @"1.00");
71 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", green]), @"0.00");
72 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", blue]), @"1.00");
73 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", alpha]), @"1.00");
74 |
75 | [[UIColor grayColor] gh_getRed:&red green:&green blue:&blue alpha:&alpha];
76 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", red]), @"0.50");
77 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", green]), @"0.50");
78 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", blue]), @"0.50");
79 | XCTAssertEqualObjects(([NSString stringWithFormat:@"%0.2f", alpha]), @"1.00");
80 | }
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/Tests/iOS/GHUIImageUtilsTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // GHUIImageUtilsTest.m
3 | // GHKit
4 | //
5 | // Created by Gabriel on 1/27/16.
6 | // Copyright © 2016 rel.me. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GHUIImageUtilsTest : XCTestCase
12 | @end
13 |
14 | @implementation GHUIImageUtilsTest
15 |
16 | // TODO
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Tests/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------