├── .travis.yml
├── Assets
└── logo.sketch
│ ├── Data
│ ├── QuickLook
│ ├── Preview.png
│ └── Thumbnail.png
│ ├── fonts
│ ├── metadata
│ └── version
├── CHANGELOG.md
├── Classes
├── NSArray+ObjectiveSugar.h
├── NSArray+ObjectiveSugar.m
├── NSDictionary+ObjectiveSugar.h
├── NSDictionary+ObjectiveSugar.m
├── NSMutableArray+ObjectiveSugar.h
├── NSMutableArray+ObjectiveSugar.m
├── NSNumber+ObjectiveSugar.h
├── NSNumber+ObjectiveSugar.m
├── NSSet+ObjectiveSugar.h
├── NSSet+ObjectiveSugar.m
├── NSString+ObjectiveSugar.h
├── NSString+ObjectiveSugar.m
└── ObjectiveSugar.h
├── Example
├── .gitignore
├── Makefile
├── ObjectiveSugar.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── ObjectiveSugar.xcscheme
├── ObjectiveSugar.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── ObjectiveSugar.xccheckout
├── ObjectiveSugar
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Default-568h@2x.png
│ ├── Default.png
│ ├── Default@2x.png
│ ├── ObjectiveSugar-Info.plist
│ ├── ObjectiveSugar-Prefix.pch
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ └── main.m
├── ObjectiveSugarTests
│ ├── CAdditionsTests.m
│ ├── NSArrayTests.m
│ ├── NSDictionaryTests.m
│ ├── NSMutableArrayTests.m
│ ├── NSNumberTests.m
│ ├── NSSetTests.m
│ ├── NSStringTests.m
│ ├── ObjectiveSugarTests-Info.plist
│ └── en.lproj
│ │ └── InfoPlist.strings
├── Podfile
└── Podfile.lock
├── LICENSE
├── ObjectiveSugar.podspec
└── README.md
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 |
3 | before_install:
4 | - cd Example
5 |
6 | install: make install
7 |
8 | script: make ci
9 |
10 |
--------------------------------------------------------------------------------
/Assets/logo.sketch/Data:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Assets/logo.sketch/Data
--------------------------------------------------------------------------------
/Assets/logo.sketch/QuickLook/Preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Assets/logo.sketch/QuickLook/Preview.png
--------------------------------------------------------------------------------
/Assets/logo.sketch/QuickLook/Thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Assets/logo.sketch/QuickLook/Thumbnail.png
--------------------------------------------------------------------------------
/Assets/logo.sketch/fonts:
--------------------------------------------------------------------------------
1 | HelveticaNeue-UltraLight
--------------------------------------------------------------------------------
/Assets/logo.sketch/metadata:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | app
6 | com.bohemiancoding.sketch
7 | build
8 | 5302
9 | commit
10 | 9460a4bc62af5e9ba50dd4143578fd9401710ce5
11 | version
12 | 18
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Assets/logo.sketch/version:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # master
2 | ##### Enhancements
3 | - added `-reduce` method on NSArray and NSSet
4 |
5 | ##### Bug Fixes
6 |
7 | - NSMutableArray -keepIf was mutating the collection while iterating
8 | - !!BREAKING `-map` on NSArray now puts NSNulls if the block returns nil
9 | - !!BREAKING `-map` on NSSet doesn't blow up if the block returns nil.
10 |
11 |
12 | # 1.1.1
13 |
14 | ##### Bug Fixes
15 |
16 | - Array range accesors with backwards range (e.g. array[@"0..-2"])
17 |
18 | # 1.1.0
19 |
20 | ##### Enhancements
21 |
22 | - `until` keyword, and improved `unless` (it allows you to pass args) |
23 | [C0deH4cker #61](https://github.com/supermarin/ObjectiveSugar/pull/61)
24 | - Force the library to load under ARC |
25 | [mickeyreiss #62](https://github.com/supermarin/ObjectiveSugar/pull/62)
26 |
27 | # 1.0.0
28 |
29 | * The library is stable, warning-less and production-ready
30 |
31 | * Thanks everybody for contributing and all the great PRs.
32 | Since the library is stable enough and we almost never had to fix things,
33 | it's time to release 1.0.
34 |
35 | * Documentation could be better, and we encourage you to write some.
36 | Thanks [@orta](https://github.com/orta) for initiating that.
37 |
38 |
--------------------------------------------------------------------------------
/Classes/NSArray+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ObjectiveSugar.h
3 | // Objective Sugar
4 | //
5 | // Created by Marin Usalj on 5/7/12.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | // For an overview see http://cocoadocs.org/docsets/ObjectiveSugar/
10 |
11 | #import
12 |
13 | @interface NSArray (ObjectiveSugar)
14 |
15 | /**
16 | The first item in the array, or nil.
17 |
18 | @return The first item in the array, or nil.
19 | */
20 | - (id)first DEPRECATED_MSG_ATTRIBUTE("Please use -firstObject instead");
21 |
22 | /**
23 | The last item in the array, or nil.
24 |
25 | @return The last item in the array, or nil.
26 | */
27 | - (id)last DEPRECATED_MSG_ATTRIBUTE("Please use -lastObject instead");
28 |
29 | /**
30 | A random element in the array, or nil.
31 |
32 | @return A random element in the array, or nil.
33 | */
34 | - (id)sample;
35 |
36 | /// Alias for -sample
37 | - (id)anyObject;
38 |
39 |
40 | /**
41 | Allow subscripting to fetch elements within the specified range
42 |
43 | @param key An NSString or NSValue wrapping an NSRange. It's intended to behave like Ruby's array range accessors.
44 |
45 | Given array of 10 elements, e.g. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], you can perform these operations:
46 | array[@"1..3"] will give you [2, 3, 4]
47 | array[@"1...3"] will give you [2, 3] (last value excluded)
48 | array[@"1,3"] implies NSRange(location: 1, length: 3), and gives you [2, 3, 4]
49 |
50 |
51 | @return An array with elements within the specified range
52 | */
53 | - (id)objectForKeyedSubscript:(id )key;
54 |
55 |
56 | /**
57 | A simpler alias for `enumerateObjectsUsingBlock`
58 |
59 | @param block A block with the object in its arguments.
60 | */
61 | - (void)each:(void (^)(id object))block;
62 |
63 | /**
64 | A simpler alias for `enumerateObjectsUsingBlock` which also passes in an index
65 |
66 | @param block A block with the object in its arguments.
67 | */
68 | - (void)eachWithIndex:(void (^)(id object, NSUInteger index))block;
69 |
70 | /**
71 | A simpler alias for `enumerateObjectsWithOptions:usingBlock:`
72 |
73 | @param block A block with the object in its arguments.
74 | @param options Enumerating options.
75 | */
76 |
77 | - (void)each:(void (^)(id object))block options:(NSEnumerationOptions)options;
78 |
79 | /**
80 | A simpler alias for `enumerateObjectsWithOptions:usingBlock:` which also passes in an index
81 |
82 | @param block A block with the object in its arguments.
83 | @param options Enumerating options.
84 | */
85 |
86 | - (void)eachWithIndex:(void (^)(id object, NSUInteger index))block options:(NSEnumerationOptions)options;
87 |
88 |
89 | /**
90 | An alias for `containsObject`
91 |
92 | @param object An object that the array may or may not contain.
93 | */
94 | - (BOOL)includes:(id)object;
95 |
96 | /**
97 | Take the first `numberOfElements` out of the array, or the maximum amount of
98 | elements if it is less.
99 |
100 | @param numberOfElements Number of elements to take from array
101 | @return An array of elements
102 | */
103 | - (NSArray *)take:(NSUInteger)numberOfElements;
104 |
105 | /**
106 | Passes elements to the `block` until the block returns NO,
107 | then stops iterating and returns an array of all prior elements.
108 |
109 | @param block A block that returns YES/NO
110 | @return An array of elements
111 | */
112 | - (NSArray *)takeWhile:(BOOL (^)(id object))block;
113 |
114 | /**
115 | Iterate through the current array running the block on each object and
116 | returning an array of the changed objects.
117 |
118 | @param block A block that passes in each object and returns a modified object
119 | @return An array of modified elements
120 | */
121 | - (NSArray *)map:(id (^)(id object))block;
122 |
123 | /**
124 | Iterate through current array asking whether to keep each element.
125 |
126 | @param block A block that returns YES/NO for whether the object should stay
127 | @return An array of elements selected
128 | */
129 | - (NSArray *)select:(BOOL (^)(id object))block;
130 |
131 | /**
132 | Iterate through current array returning the first element meeting a criteria.
133 |
134 | @param block A block that returns YES/NO
135 | @return The first matching element
136 | */
137 | - (id)detect:(BOOL (^)(id object))block;
138 |
139 |
140 | /**
141 | Alias for `detect`. Iterate through current array returning the first element
142 | meeting a criteria.
143 |
144 | @param block A block that returns YES/NO
145 | @return The first matching element
146 | */
147 | - (id)find:(BOOL (^)(id object))block;
148 |
149 | /**
150 | Iterate through current array asking whether to remove each element.
151 |
152 | @param block A block that returns YES/NO for whether the object should be removed
153 | @return An array of elements not rejected
154 | */
155 | - (NSArray *)reject:(BOOL (^)(id object))block;
156 |
157 | /**
158 | Recurse through self checking for NSArrays and extract all elements into one single array
159 |
160 | @return An array of all held arrays merged
161 | */
162 | - (NSArray *)flatten;
163 |
164 | /**
165 | Remove all the nulls from array
166 |
167 | @return A copy of the given array without NSNulls
168 | */
169 | - (NSArray *)compact;
170 |
171 | /**
172 | Alias for `componentsJoinedByString` with a default of no seperator
173 |
174 | @return A string of all objects joined with an empty string
175 | */
176 | - (NSString *)join;
177 |
178 | /**
179 | Alias for `componentsJoinedByString`
180 |
181 | @return A string of all objects joined with the `seperator` string
182 | */
183 | - (NSString *)join:(NSString *)separator;
184 |
185 | /**
186 | Run the default comparator on each object in the array
187 |
188 | @return A sorted copy of the array
189 | */
190 | - (NSArray *)sort;
191 |
192 | /**
193 | Sorts the array using the the default comparator on the given key
194 |
195 | @return A sorted copy of the array
196 | */
197 | - (NSArray *)sortBy:(NSString *)key;
198 |
199 | /**
200 | Alias for reverseObjectEnumerator.allObjects
201 |
202 | Returns a reversed array
203 | */
204 | - (NSArray *)reverse;
205 |
206 | /**
207 | Return all the objects that are in both self and `array`.
208 | Alias for Ruby's & operator
209 |
210 | @return An array of objects common to both arrays
211 | */
212 | - (NSArray *)intersectionWithArray:(NSArray *)array;
213 |
214 | /**
215 | Return all the objects that in both self and `array` combined.
216 | Alias for Ruby's | operator
217 |
218 | @return An array of the two arrays combined
219 | */
220 |
221 | - (NSArray *)unionWithArray:(NSArray *)array;
222 |
223 | /**
224 | Return all the objects in self that are not in `array`.
225 | Alias for Ruby's - operator
226 |
227 | @return An array of the self without objects in `array`
228 | */
229 |
230 | - (NSArray *)relativeComplement:(NSArray *)array;
231 |
232 | /**
233 | Return all the objects that are unique to each array individually
234 | Alias for Ruby's ^ operator. Equivalent of a - b | b - a
235 |
236 | @return An array of elements which are in either of the arrays and not in their intersection.
237 | */
238 | - (NSArray *)symmetricDifference:(NSArray *)array;
239 |
240 | /**
241 | Return a single value from an array by iterating through the elements and transforming a running total.
242 |
243 | @return A single value that is the end result of apply the block function to each element successively.
244 | **/
245 | - (id)reduce:(id (^)(id accumulator, id object))block;
246 |
247 | /**
248 | Same as -reduce, with initial value provided by yourself
249 | **/
250 | - (id)reduce:(id)initial withBlock:(id (^)(id accumulator, id object))block;
251 |
252 | /**
253 | Produces a duplicate-free version of the array
254 |
255 | @return a new array with all unique elements
256 | **/
257 | - (NSArray *)unique;
258 |
259 | @end
260 |
261 |
--------------------------------------------------------------------------------
/Classes/NSArray+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+ObjectiveSugar.m
3 | // WidgetPush
4 | //
5 | // Created by Marin Usalj on 5/7/12.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "NSArray+ObjectiveSugar.h"
10 | #import "NSMutableArray+ObjectiveSugar.h"
11 | #import "NSString+ObjectiveSugar.h"
12 |
13 | static NSString * const OSMinusString = @"-";
14 |
15 | @implementation NSArray (ObjectiveSugar)
16 |
17 | - (id)sample {
18 | if (self.count == 0) return nil;
19 |
20 | NSUInteger index = arc4random_uniform((u_int32_t)self.count);
21 | return self[index];
22 | }
23 |
24 | - (id)objectForKeyedSubscript:(id)key {
25 | if ([key isKindOfClass:[NSString class]])
26 | return [self subarrayWithRange:[self rangeFromString:key]];
27 |
28 | else if ([key isKindOfClass:[NSValue class]])
29 | return [self subarrayWithRange:[key rangeValue]];
30 |
31 | else
32 | [NSException raise:NSInvalidArgumentException format:@"expected NSString or NSValue argument, got %@ instead", [key class]];
33 |
34 | return nil;
35 | }
36 |
37 | - (NSRange)rangeFromString:(NSString *)string {
38 | NSRange range = NSRangeFromString(string);
39 |
40 | if ([string containsString:@"..."]) {
41 | range.length = isBackwardsRange(string) ? (self.count - 2) - range.length : range.length - range.location;
42 |
43 | } else if ([string containsString:@".."]) {
44 | range.length = isBackwardsRange(string) ? (self.count - 1) - range.length : range.length - range.location + 1;
45 | }
46 |
47 | return range;
48 | }
49 |
50 | - (void)each:(void (^)(id object))block {
51 | [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
52 | block(obj);
53 | }];
54 | }
55 |
56 | - (void)eachWithIndex:(void (^)(id object, NSUInteger index))block {
57 | [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
58 | block(obj, idx);
59 | }];
60 | }
61 |
62 | - (void)each:(void (^)(id object))block options:(NSEnumerationOptions)options {
63 | [self enumerateObjectsWithOptions:options usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
64 | block(obj);
65 | }];
66 | }
67 |
68 | - (void)eachWithIndex:(void (^)(id object, NSUInteger index))block options:(NSEnumerationOptions)options {
69 | [self enumerateObjectsWithOptions:options usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
70 | block(obj, idx);
71 | }];
72 | }
73 |
74 | - (BOOL)includes:(id)object {
75 | return [self containsObject:object];
76 | }
77 |
78 | - (NSArray *)take:(NSUInteger)numberOfElements {
79 | return [self subarrayWithRange:NSMakeRange(0, MIN(numberOfElements, [self count]))];
80 | }
81 |
82 | - (NSArray *)takeWhile:(BOOL (^)(id object))block {
83 | NSMutableArray *array = [NSMutableArray array];
84 |
85 | for (id arrayObject in self) {
86 | if (block(arrayObject))
87 | [array addObject:arrayObject];
88 |
89 | else break;
90 | }
91 |
92 | return array;
93 | }
94 |
95 | - (NSArray *)map:(id (^)(id object))block {
96 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
97 |
98 | for (id object in self) {
99 | [array addObject:block(object) ?: [NSNull null]];
100 | }
101 |
102 | return array;
103 | }
104 |
105 | - (NSArray *)select:(BOOL (^)(id object))block {
106 | return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
107 | return block(evaluatedObject);
108 | }]];
109 | }
110 |
111 | - (NSArray *)reject:(BOOL (^)(id object))block {
112 | return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
113 | return !block(evaluatedObject);
114 | }]];
115 | }
116 |
117 | - (id)detect:(BOOL (^)(id object))block {
118 | for (id object in self) {
119 | if (block(object))
120 | return object;
121 | }
122 | return nil;
123 | }
124 |
125 | - (id)find:(BOOL (^)(id object))block {
126 | return [self detect:block];
127 | }
128 |
129 | - (NSArray *)flatten {
130 | NSMutableArray *array = [NSMutableArray array];
131 |
132 | for (id object in self) {
133 | if ([object isKindOfClass:NSArray.class]) {
134 | [array concat:[object flatten]];
135 | } else {
136 | [array addObject:object];
137 | }
138 | }
139 |
140 | return array;
141 | }
142 |
143 | - (NSArray *)compact {
144 | return [self select:^BOOL(id object) {
145 | return object != [NSNull null];
146 | }];
147 | }
148 |
149 | - (NSString *)join {
150 | return [self componentsJoinedByString:@""];
151 | }
152 |
153 | - (NSString *)join:(NSString *)separator {
154 | return [self componentsJoinedByString:separator];
155 | }
156 |
157 | - (NSArray *)sort {
158 | return [self sortedArrayUsingSelector:@selector(compare:)];
159 | }
160 |
161 | - (NSArray *)sortBy:(NSString*)key; {
162 | NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:YES];
163 | return [self sortedArrayUsingDescriptors:@[descriptor]];
164 | }
165 |
166 | - (NSArray *)reverse {
167 | return self.reverseObjectEnumerator.allObjects;
168 | }
169 |
170 | - (id)reduce:(id (^)(id accumulator, id object))block {
171 | return [self reduce:nil withBlock:block];
172 | }
173 |
174 | - (id)reduce:(id)initial withBlock:(id (^)(id accumulator, id object))block {
175 | id accumulator = initial;
176 |
177 | for(id object in self)
178 | accumulator = accumulator ? block(accumulator, object) : object;
179 |
180 | return accumulator;
181 | }
182 |
183 | - (NSArray *)unique
184 | {
185 | return [[NSOrderedSet orderedSetWithArray:self] array];
186 | }
187 |
188 | #pragma mark - Set operations
189 |
190 | - (NSArray *)intersectionWithArray:(NSArray *)array {
191 | NSPredicate *intersectPredicate = [NSPredicate predicateWithFormat:@"SELF IN %@", array];
192 | return [self filteredArrayUsingPredicate:intersectPredicate];
193 | }
194 |
195 | - (NSArray *)unionWithArray:(NSArray *)array {
196 | NSArray *complement = [self relativeComplement:array];
197 | return [complement arrayByAddingObjectsFromArray:array];
198 | }
199 |
200 | - (NSArray *)relativeComplement:(NSArray *)array {
201 | NSPredicate *relativeComplementPredicate = [NSPredicate predicateWithFormat:@"NOT SELF IN %@", array];
202 | return [self filteredArrayUsingPredicate:relativeComplementPredicate];
203 | }
204 |
205 | - (NSArray *)symmetricDifference:(NSArray *)array {
206 | NSArray *aSubtractB = [self relativeComplement:array];
207 | NSArray *bSubtractA = [array relativeComplement:self];
208 | return [aSubtractB unionWithArray:bSubtractA];
209 | }
210 |
211 | #pragma mark - Private
212 |
213 | static inline BOOL isBackwardsRange(NSString *rangeString) {
214 | return [rangeString containsString:OSMinusString];
215 | }
216 |
217 | #pragma mark - Aliases
218 |
219 | - (id)anyObject {
220 | return [self sample];
221 | }
222 |
223 | - (id)first DEPRECATED_ATTRIBUTE {
224 | return [self firstObject];
225 | }
226 |
227 | - (id)last DEPRECATED_ATTRIBUTE {
228 | return [self lastObject];
229 | }
230 |
231 | @end
232 |
233 |
--------------------------------------------------------------------------------
/Classes/NSDictionary+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+ObjectiveSugar.h
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSDictionary (ObjectiveSugar)
12 |
13 | - (void)each:(void (^)(id key, id value))block;
14 | - (void)eachKey:(void (^)(id key))block;
15 | - (void)eachValue:(void (^)(id value))block;
16 | - (NSArray *)map:(id (^)(id key, id value))block;
17 | - (BOOL)hasKey:(id)key;
18 | - (NSDictionary *)pick:(NSArray *)keys;
19 | - (NSDictionary *)omit:(NSArray *)keys;
20 | - (NSDictionary *)merge:(NSDictionary *)dictionary;
21 | - (NSDictionary *)merge:(NSDictionary *)dictionary block:(id(^)(id key, id oldVal, id newVal))block;
22 | - (NSDictionary *)invert;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Classes/NSDictionary+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+ObjectiveSugar.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "NSDictionary+ObjectiveSugar.h"
10 |
11 | #import "NSArray+ObjectiveSugar.h"
12 |
13 | @implementation NSDictionary (Rubyfy)
14 |
15 | - (void)each:(void (^)(id k, id v))block {
16 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
17 | block(key, obj);
18 | }];
19 | }
20 |
21 | - (void)eachKey:(void (^)(id k))block {
22 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
23 | block(key);
24 | }];
25 | }
26 |
27 | - (void)eachValue:(void (^)(id v))block {
28 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
29 | block(obj);
30 | }];
31 | }
32 |
33 | - (NSArray *)map:(id (^)(id key, id value))block {
34 | NSMutableArray *array = [NSMutableArray array];
35 |
36 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
37 | id object = block(key, obj);
38 | if (object) {
39 | [array addObject:object];
40 | }
41 | }];
42 |
43 | return array;
44 | }
45 |
46 | - (BOOL)hasKey:(id)key {
47 | return !!self[key];
48 | }
49 |
50 | - (NSDictionary *)pick:(NSArray *)keys {
51 | NSMutableDictionary *picked = [[NSMutableDictionary alloc] initWithCapacity:keys.count];
52 |
53 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
54 | if ([keys containsObject:key]) {
55 | picked[key] = obj;
56 | }
57 | }];
58 |
59 | return picked;
60 | }
61 |
62 | - (NSDictionary *)omit:(NSArray *)keys {
63 | NSMutableDictionary *omitted = [[NSMutableDictionary alloc] initWithCapacity:([self allKeys].count - keys.count)];
64 |
65 | [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
66 | if (![keys containsObject:key]) {
67 | omitted[key] = obj;
68 | }
69 | }];
70 |
71 | return omitted;
72 | }
73 |
74 | - (NSDictionary *)merge:(NSDictionary *)dictionary {
75 | NSMutableDictionary *merged = [NSMutableDictionary dictionaryWithDictionary:self];
76 | [merged addEntriesFromDictionary:dictionary];
77 | return merged;
78 | }
79 |
80 | - (NSDictionary *)merge:(NSDictionary *)dictionary block:(id(^)(id key, id oldVal, id newVal))block {
81 | NSMutableDictionary *merged = [NSMutableDictionary dictionary];
82 | [[[self allKeys] relativeComplement:[dictionary allKeys]] each:^(id key) {
83 | merged[key] = self[key];
84 | }];
85 |
86 | [[[dictionary allKeys] relativeComplement:[self allKeys]] each:^(id key) {
87 | merged[key] = dictionary[key];
88 | }];
89 |
90 | [[[self allKeys] intersectionWithArray:[dictionary allKeys]] each:^(id key) {
91 | merged[key] = block(key, self[key], dictionary[key]);
92 | }];
93 | return merged;
94 | }
95 |
96 | - (NSDictionary *)invert {
97 | NSMutableDictionary *inverted = [NSMutableDictionary dictionary];
98 | for (id key in [self allKeys]) {
99 | inverted[self[key]] = key;
100 | }
101 | return inverted;
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/Classes/NSMutableArray+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArray+ObjectiveSugar.h
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSMutableArray (ObjectiveSugar)
12 |
13 | /// Alias for -addObject. Appends the given object at the end
14 | - (void)push:(id)object;
15 |
16 | /**
17 | Removes the last item of the array, and returns that item
18 | Note: This method changes the length of the array!
19 |
20 | @return First array item or nil.
21 | */
22 | - (id)pop;
23 |
24 |
25 | /**
26 | Removes the last n items of the array, and returns that item
27 | Note: This method changes the length of the array!
28 |
29 | @return First array item or nil.
30 | */
31 | - (NSArray *)pop:(NSUInteger)numberOfElements;
32 | - (void)concat:(NSArray *)array;
33 |
34 |
35 | /**
36 | Removes the first item of the array, and returns that item
37 | Note: This method changes the length of the array!
38 |
39 | @return First array item or nil.
40 | */
41 | - (id)shift;
42 |
43 |
44 | /**
45 | Removes N first items of the array, and returns that items
46 | Note: This method changes the length of the array!
47 |
48 | @return Array of first N items or empty array.
49 | */
50 | - (NSArray *)shift:(NSUInteger)numberOfElements;
51 |
52 |
53 | /**
54 | Deletes every element of the array for which the given block evaluates to NO.
55 |
56 | @param block block that returns YES/NO
57 | @return An array of elements
58 | */
59 | - (NSArray *)keepIf:(BOOL (^)(id object))block;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/Classes/NSMutableArray+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArray+ObjectiveSugar.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "NSMutableArray+ObjectiveSugar.h"
10 | #import "NSArray+ObjectiveSugar.h"
11 |
12 | @implementation NSMutableArray (ObjectiveSugar)
13 |
14 | - (void)push:(id)object {
15 | [self addObject:object];
16 | }
17 |
18 | - (id)pop {
19 | id object = [self lastObject];
20 | [self removeLastObject];
21 |
22 | return object;
23 | }
24 |
25 | - (NSArray *)pop:(NSUInteger)numberOfElements {
26 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:numberOfElements];
27 |
28 | for (NSUInteger i = 0; i < numberOfElements; i++)
29 | [array insertObject:[self pop] atIndex:0];
30 |
31 | return array;
32 | }
33 |
34 | - (void)concat:(NSArray *)array {
35 | [self addObjectsFromArray:array];
36 | }
37 |
38 | - (id)shift {
39 | NSArray *result = [self shift:1];
40 | return [result firstObject];
41 | }
42 |
43 | - (NSArray *)shift:(NSUInteger)numberOfElements {
44 | NSUInteger shiftLength = MIN(numberOfElements, [self count]);
45 |
46 | NSRange range = NSMakeRange(0, shiftLength);
47 | NSArray *result = [self subarrayWithRange:range];
48 | [self removeObjectsInRange:range];
49 |
50 | return result;
51 | }
52 |
53 | - (NSArray *)keepIf:(BOOL (^)(id object))block {
54 | [self filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
55 | return block(evaluatedObject);
56 | }]];
57 | return self;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/Classes/NSNumber+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumber+Rubyfy.h
3 | // Domainchy
4 | //
5 | // Created by Marin Usalj on 11/15/12.
6 | // Copyright (c) 2012 supermar.in | @supermarin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSNumber (ObjectiveSugar)
12 |
13 | - (void)times:(void(^)(void))block;
14 | - (void)timesWithIndex:(void(^)(NSUInteger index))block;
15 |
16 | - (void)upto:(int)number do:(void(^)(NSInteger number))block;
17 | - (void)downto:(int)number do:(void(^)(NSInteger number))block;
18 |
19 | // Numeric inflections
20 | - (NSNumber *)seconds;
21 | - (NSNumber *)minutes;
22 | - (NSNumber *)hours;
23 | - (NSNumber *)days;
24 | - (NSNumber *)weeks;
25 | - (NSNumber *)fortnights;
26 | - (NSNumber *)months;
27 | - (NSNumber *)years;
28 |
29 | // There are singular aliases for the above methods
30 | - (NSNumber *)second;
31 | - (NSNumber *)minute;
32 | - (NSNumber *)hour;
33 | - (NSNumber *)day;
34 | - (NSNumber *)week;
35 | - (NSNumber *)fortnight;
36 | - (NSNumber *)month;
37 | - (NSNumber *)year;
38 |
39 | - (NSDate *)ago;
40 | - (NSDate *)ago:(NSDate *)time;
41 | - (NSDate *)since:(NSDate *)time;
42 | - (NSDate *)until:(NSDate *)time;
43 | - (NSDate *)fromNow;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Classes/NSNumber+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumber+Rubyfy.m
3 | // Domainchy
4 | //
5 | // Created by Marin Usalj on 11/15/12.
6 | // Copyright (c) 2012 supermar.in | @supermarin. All rights reserved.
7 | //
8 |
9 | #import "NSNumber+ObjectiveSugar.h"
10 |
11 | @implementation NSNumber (ObjectiveSugar)
12 |
13 | - (void)times:(void (^)(void))block {
14 | for (int i = 0; i < self.integerValue; i++)
15 | block();
16 | }
17 |
18 | - (void)timesWithIndex:(void (^)(NSUInteger))block {
19 | for (NSUInteger i = 0; i < self.unsignedIntegerValue; i++)
20 | block(i);
21 | }
22 |
23 | - (void)upto:(int)number do:(void (^)(NSInteger))block {
24 | for (NSInteger i = self.integerValue; i <= number; i++)
25 | block(i);
26 | }
27 |
28 | - (void)downto:(int)number do:(void (^)(NSInteger))block {
29 | for (NSInteger i = self.integerValue; i >= number; i--)
30 | block(i);
31 | }
32 |
33 | - (NSNumber *)second {
34 | return self.seconds;
35 | }
36 |
37 | - (NSNumber *)seconds {
38 | return self;
39 | }
40 |
41 | - (NSNumber *)minute {
42 | return self.minutes;
43 | }
44 |
45 | - (NSNumber *)minutes {
46 | return @(self.floatValue * 60);
47 | }
48 |
49 | - (NSNumber *)hour {
50 | return self.hours;
51 | }
52 |
53 | - (NSNumber *)hours {
54 | return @(self.floatValue * [@60 minutes].integerValue);
55 | }
56 |
57 | - (NSNumber *)day {
58 | return self.days;
59 | }
60 |
61 | - (NSNumber *)days {
62 | return @(self.floatValue * [@24 hours].integerValue);
63 | }
64 |
65 | - (NSNumber *)week {
66 | return self.weeks;
67 | }
68 |
69 | - (NSNumber *)weeks {
70 | return @(self.floatValue * [@7 days].integerValue);
71 | }
72 |
73 | - (NSNumber *)fortnight {
74 | return self.fortnights;
75 | }
76 |
77 | - (NSNumber *)fortnights {
78 | return @(self.floatValue * [@2 weeks].integerValue);
79 | }
80 |
81 | - (NSNumber *)month {
82 | return self.months;
83 | }
84 |
85 | - (NSNumber *)months {
86 | return @(self.floatValue * [@30 days].integerValue);
87 | }
88 |
89 | - (NSNumber *)year {
90 | return self.years;
91 | }
92 |
93 | - (NSNumber *)years {
94 | return @(self.floatValue * [@(365.25) days].integerValue);
95 | }
96 |
97 | - (NSDate *)ago {
98 | return [self ago:[NSDate date]];
99 | }
100 |
101 | - (NSDate *)ago:(NSDate *)time {
102 | return [NSDate dateWithTimeIntervalSince1970:([time timeIntervalSince1970] - self.floatValue)];
103 | }
104 |
105 | - (NSDate *)since:(NSDate *)time {
106 | return [NSDate dateWithTimeIntervalSince1970:([time timeIntervalSince1970] + self.floatValue)];
107 | }
108 |
109 | - (NSDate *)until:(NSDate *)time {
110 | return [self ago:time];
111 | }
112 |
113 | - (NSDate *)fromNow {
114 | return [self since:[NSDate date]];
115 | }
116 |
117 | @end
118 |
--------------------------------------------------------------------------------
/Classes/NSSet+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+Accessors.h
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSSet (Accessors)
12 |
13 | /// Returns the first object of a given set.
14 | /// Note that sets are unordered, so this method won't always return the same thing
15 | @property(readonly) id firstObject;
16 |
17 | /// Returns the last object of a given set.
18 | /// Note that sets are unordered, so this method won't always return the same thing
19 | @property(readonly) id lastObject;
20 |
21 |
22 | /// Alias for -anyObject. Returns a random object from a given set
23 | @property(readonly) id sample;
24 |
25 | /// Alias for -anyObject. Returns a random object from a given set
26 | - (void)each:(void (^)(id object))block;
27 | - (void)eachWithIndex:(void (^)(id object, NSUInteger index))block;
28 |
29 | /// Filters the given set using provided block, and returns an array copy
30 | - (NSArray *)select:(BOOL (^)(id object))block;
31 |
32 | /// Keeps the objects passing the given block, and returns an array copy
33 | - (NSArray *)reject:(BOOL (^)(id object))block;
34 |
35 | /// Returns a sorted array copy of the given set
36 | - (NSArray *)sort;
37 |
38 | /**
39 | * Maps the given NSSet to NSArray.
40 | * NOTE: If the block returns `-nil`, values are ignored.
41 | * This is intentional to keep the behavior of `-valueForKeyPath`.
42 | * This is different from NSArray `-map`, which puts NSNulls in the given case.
43 | * If you want to preserve the count and use NSNulls, use `set.allObjects -map:`
44 | *
45 | * @param block - a transform block
46 | *
47 | * @return An NSArray copy of the transformed set.
48 | */
49 | - (NSArray *)map:(id (^)(id object))block;
50 |
51 | /**
52 | Return a single value from an array by iterating through the elements and transforming a running total.
53 |
54 | @return A single value that is the end result of apply the block function to each element successively.
55 | **/
56 | - (id)reduce:(id (^)(id accumulator, id object))block;
57 |
58 | /**
59 | Same as -reduce, with initial value provided by yourself
60 | **/
61 | - (id)reduce:(id)initial withBlock:(id (^)(id accumulator, id object))block;
62 |
63 |
64 | #pragma mark - Deprecations
65 |
66 | @property(readonly) id first DEPRECATED_MSG_ATTRIBUTE("Please use -firstObject");
67 | @property(readonly) id last DEPRECATED_MSG_ATTRIBUTE("Please use -lastObject");
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/Classes/NSSet+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+ObjectiveSugar.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "NSSet+ObjectiveSugar.h"
10 | #import "NSArray+ObjectiveSugar.h"
11 |
12 | @implementation NSSet (ObjectiveSugar)
13 |
14 | - (id)firstObject {
15 | NSArray *allObjects = self.allObjects;
16 |
17 | if (allObjects.count > 0)
18 | return allObjects[0];
19 | return nil;
20 | }
21 |
22 | - (id)lastObject {
23 | return self.allObjects.lastObject;
24 | }
25 |
26 | - (id)sample {
27 | return [self anyObject];
28 | }
29 |
30 | - (void)each:(void (^)(id))block {
31 | [self enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
32 | block(obj);
33 | }];
34 | }
35 |
36 | - (void)eachWithIndex:(void (^)(id, int))block {
37 | __block int counter = 0;
38 | [self enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
39 | block(obj, counter);
40 | counter ++;
41 | }];
42 | }
43 |
44 | - (NSArray *)map:(id (^)(id object))block {
45 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
46 |
47 |
48 | for (id object in self) {
49 | id mappedObject = block(object);
50 | if(mappedObject) {
51 | [array addObject:mappedObject];
52 | }
53 | }
54 |
55 | return array;
56 | }
57 |
58 | - (NSArray *)select:(BOOL (^)(id object))block {
59 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
60 |
61 | for (id object in self) {
62 | if (block(object)) {
63 | [array addObject:object];
64 | }
65 | }
66 |
67 | return array;
68 | }
69 |
70 | - (NSArray *)reject:(BOOL (^)(id object))block {
71 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:self.count];
72 |
73 | for (id object in self) {
74 | if (block(object) == NO) {
75 | [array addObject:object];
76 | }
77 | }
78 |
79 | return array;
80 | }
81 |
82 | - (NSArray *)sort {
83 | NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
84 | return [self sortedArrayUsingDescriptors:@[sortDescriptor]];
85 | }
86 |
87 | - (id)reduce:(id(^)(id accumulator, id object))block {
88 | return [self reduce:nil withBlock:block];
89 | }
90 |
91 | - (id)reduce:(id)initial withBlock:(id(^)(id accumulator, id object))block {
92 | id accumulator = initial;
93 |
94 | for(id object in self)
95 | accumulator = accumulator ? block(accumulator, object) : object;
96 |
97 | return accumulator;
98 | }
99 |
100 |
101 | #pragma mark - Deprecations
102 |
103 | - (id)first DEPRECATED_ATTRIBUTE {
104 | return [self firstObject];
105 | }
106 |
107 | - (id)last DEPRECATED_ATTRIBUTE {
108 | return [self lastObject];
109 | }
110 |
111 | @end
112 |
113 |
--------------------------------------------------------------------------------
/Classes/NSString+ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+ObjectiveSugar.h
3 | // SampleProject
4 | //
5 | // Created by Neil on 05/12/2012.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NSString *NSStringWithFormat(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
12 |
13 | @interface NSString(ObjectiveSugar)
14 |
15 | /**
16 | Returns an array containing substrings from the receiver that have been divided by a whitespace delimiter
17 |
18 | @return An array containing substrings that have been divided by a whitespace delimiter
19 | */
20 | - (NSArray *)split;
21 |
22 |
23 | /**
24 | Returns an array containing substrings from the receiver that have been divided by a given delimiter
25 |
26 | @param delimiter The delimiter string
27 | @return An array containing substrings that have been divided by delimiter
28 | */
29 | - (NSArray *)split:(NSString *)delimiter;
30 |
31 |
32 | /**
33 | Returns a new string made by converting a snake_case_string to CamelCaseString
34 |
35 | @return A string made by converting a snake_case_string to CamelCaseString
36 | */
37 | - (NSString *)camelCase;
38 |
39 |
40 | /**
41 | Returns a new string made by converting a snake_case_string to lowerCamelCaseString
42 |
43 | @return A string made by converting a snake_case_string to CamelCaseString
44 | */
45 | - (NSString *)lowerCamelCase;
46 |
47 |
48 | /**
49 | Returns a Boolean value that indicates whether a given string is a substring of the receiver
50 |
51 | @return YES if 'string' is a substring of the receiver, otherwise NO
52 | */
53 | - (BOOL)containsString:(NSString *)string;
54 |
55 |
56 | /**
57 | Returns a new string made by removing whitespaces and newlines from both ends of the receiver
58 |
59 | @return A string without trailing or leading whitespaces and newlines
60 | */
61 | - (NSString *)strip;
62 |
63 | /**
64 | Returns a new string that matches the passed in pattern
65 |
66 | @return A String matching the regex or nil if no match is found
67 | */
68 | - (NSString *)match:(NSString *)pattern;
69 |
70 | @end
71 |
72 |
--------------------------------------------------------------------------------
/Classes/NSString+ObjectiveSugar.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+ObjectiveSugar.m
3 | // SampleProject
4 | //
5 | // Created by Neil on 05/12/2012.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "NSString+ObjectiveSugar.h"
10 | #import "NSArray+ObjectiveSugar.h"
11 |
12 | static NSString *const UNDERSCORE = @"_";
13 | static NSString *const SPACE = @" ";
14 | static NSString *const EMPTY_STRING = @"";
15 |
16 | NSString *NSStringWithFormat(NSString *formatString, ...) {
17 | va_list args;
18 | va_start(args, formatString);
19 |
20 | NSString *string = [[NSString alloc] initWithFormat:formatString arguments:args];
21 |
22 | va_end(args);
23 |
24 | #if defined(__has_feature) && __has_feature(objc_arc)
25 | return string;
26 | #else
27 | return [string autorelease];
28 | #endif
29 | }
30 |
31 |
32 | @implementation NSString(Additions)
33 |
34 | - (NSArray *)split {
35 | NSArray *result = [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
36 | return [result select:^BOOL(NSString *string) {
37 | return string.length > 0;
38 | }];
39 | }
40 |
41 | - (NSArray *)split:(NSString *)delimiter {
42 | return [self componentsSeparatedByString:delimiter];
43 | }
44 |
45 | - (NSString *)camelCase {
46 | NSString *spaced = [self stringByReplacingOccurrencesOfString:UNDERSCORE withString:SPACE];
47 | NSString *capitalized = [spaced capitalizedString];
48 |
49 | return [capitalized stringByReplacingOccurrencesOfString:SPACE withString:EMPTY_STRING];
50 | }
51 |
52 | - (NSString *)lowerCamelCase {
53 | NSString *upperCamelCase = [self camelCase];
54 | NSString *firstLetter = [upperCamelCase substringToIndex:1];
55 | return [upperCamelCase stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstLetter.lowercaseString];
56 | }
57 |
58 | - (BOOL)containsString:(NSString *) string {
59 | NSRange range = [self rangeOfString:string options:NSCaseInsensitiveSearch];
60 | return range.location != NSNotFound;
61 | }
62 |
63 | - (NSString *)strip {
64 | return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
65 | }
66 |
67 | - (NSString *)match:(NSString *)pattern {
68 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
69 | NSTextCheckingResult *match = [regex firstMatchInString:self options:0 range:NSMakeRange(0, self.length)];
70 |
71 | return (match != nil) ? [self substringWithRange:[match range]] : nil;
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/Classes/ObjectiveSugar.h:
--------------------------------------------------------------------------------
1 | // C SUGAR
2 | #define unless(condition...) if(!(condition))
3 | #define until(condition...) while(!(condition))
4 |
5 | // OBJC SUGAR
6 | #import "NSNumber+ObjectiveSugar.h"
7 | #import "NSArray+ObjectiveSugar.h"
8 | #import "NSMutableArray+ObjectiveSugar.h"
9 | #import "NSDictionary+ObjectiveSugar.h"
10 | #import "NSSet+ObjectiveSugar.h"
11 | #import "NSString+ObjectiveSugar.h"
12 |
--------------------------------------------------------------------------------
/Example/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | build/*
3 | *.pbxuser
4 | !default.pbxuser
5 | *.mode1v3
6 | !default.mode1v3
7 | *.mode2v3
8 | !default.mode2v3
9 | *.perspectivev3
10 | !default.perspectivev3
11 | !default.xcworkspace
12 | xcuserdata
13 | *.xccheckout
14 | profile
15 | *.moved-aside
16 | .idea
17 | Pods
18 |
19 | *.log
20 |
21 |
--------------------------------------------------------------------------------
/Example/Makefile:
--------------------------------------------------------------------------------
1 | project_name = ObjectiveSugar
2 | workspace = $(project_name).xcworkspace
3 | xcodebuild = xcodebuild -workspace $(workspace) -scheme $(project_name) -sdk iphonesimulator
4 |
5 | clean:
6 | $(xcodebuild) clean
7 |
8 | test:
9 | $(xcodebuild) test | tee xcodebuild.log
10 |
11 | install:
12 | gem install cocoapods --no-ri --no-rdoc
13 | gem install xcpretty --no-ri --no-rdoc
14 | pod install
15 |
16 | ci:
17 | $(xcodebuild) test | xcpretty -c
18 |
19 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | archiveVersion
6 | 1
7 | classes
8 |
9 | objectVersion
10 | 46
11 | objects
12 |
13 | 0D82F54D4F82F5960EA2CBA9
14 |
15 | includeInIndex
16 | 1
17 | isa
18 | PBXFileReference
19 | lastKnownFileType
20 | text.xcconfig
21 | name
22 | Pods-ObjectiveSugarTests.release.xcconfig
23 | path
24 | Pods/Target Support Files/Pods-ObjectiveSugarTests/Pods-ObjectiveSugarTests.release.xcconfig
25 | sourceTree
26 | <group>
27 |
28 | 11566D315A504F04BFD15074
29 |
30 | fileRef
31 | 32DEFD3FCB544122AD940C8F
32 | isa
33 | PBXBuildFile
34 |
35 | 13656AD991424BF58F43F5B7
36 |
37 | buildActionMask
38 | 2147483647
39 | files
40 |
41 | inputPaths
42 |
43 | isa
44 | PBXShellScriptBuildPhase
45 | name
46 | Copy Pods Resources
47 | outputPaths
48 |
49 | runOnlyForDeploymentPostprocessing
50 | 0
51 | shellPath
52 | /bin/sh
53 | shellScript
54 | "${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh"
55 |
56 |
57 | 174A1F9A81B44DC6B8B6DFD9
58 |
59 | buildActionMask
60 | 2147483647
61 | files
62 |
63 | inputPaths
64 |
65 | isa
66 | PBXShellScriptBuildPhase
67 | name
68 | Copy Pods Resources
69 | outputPaths
70 |
71 | runOnlyForDeploymentPostprocessing
72 | 0
73 | shellPath
74 | /bin/sh
75 | shellScript
76 | "${SRCROOT}/Pods/Target Support Files/Pods-ObjectiveSugarTests/Pods-ObjectiveSugarTests-resources.sh"
77 |
78 |
79 | 32DEFD3FCB544122AD940C8F
80 |
81 | explicitFileType
82 | archive.ar
83 | includeInIndex
84 | 0
85 | isa
86 | PBXFileReference
87 | path
88 | libPods.a
89 | sourceTree
90 | BUILT_PRODUCTS_DIR
91 |
92 | 468DABF301EC4EC1A00CC4C2
93 |
94 | buildActionMask
95 | 2147483647
96 | files
97 |
98 | inputPaths
99 |
100 | isa
101 | PBXShellScriptBuildPhase
102 | name
103 | Check Pods Manifest.lock
104 | outputPaths
105 |
106 | runOnlyForDeploymentPostprocessing
107 | 0
108 | shellPath
109 | /bin/sh
110 | shellScript
111 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
112 | if [[ $? != 0 ]] ; then
113 | cat << EOM
114 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
115 | EOM
116 | exit 1
117 | fi
118 |
119 |
120 | 893C6A18A162B9FB06935ED4
121 |
122 | includeInIndex
123 | 1
124 | isa
125 | PBXFileReference
126 | lastKnownFileType
127 | text.xcconfig
128 | name
129 | Pods-ObjectiveSugarTests.debug.xcconfig
130 | path
131 | Pods/Target Support Files/Pods-ObjectiveSugarTests/Pods-ObjectiveSugarTests.debug.xcconfig
132 | sourceTree
133 | <group>
134 |
135 | 89690120173C0E4B00B403D2
136 |
137 | children
138 |
139 | 89690132173C0E4C00B403D2
140 | 89690150173C0E4C00B403D2
141 | 8969012B173C0E4C00B403D2
142 | 8969012A173C0E4C00B403D2
143 | 9ADDC0C494D895C067A28C9A
144 |
145 | isa
146 | PBXGroup
147 | sourceTree
148 | <group>
149 |
150 | 89690121173C0E4B00B403D2
151 |
152 | attributes
153 |
154 | LastUpgradeCheck
155 | 0460
156 | ORGANIZATIONNAME
157 | supermar.in
158 |
159 | buildConfigurationList
160 | 89690124173C0E4B00B403D2
161 | compatibilityVersion
162 | Xcode 3.2
163 | developmentRegion
164 | English
165 | hasScannedForEncodings
166 | 0
167 | isa
168 | PBXProject
169 | knownRegions
170 |
171 | en
172 |
173 | mainGroup
174 | 89690120173C0E4B00B403D2
175 | productRefGroup
176 | 8969012A173C0E4C00B403D2
177 | projectDirPath
178 |
179 | projectReferences
180 |
181 | projectRoot
182 |
183 | targets
184 |
185 | 89690128173C0E4C00B403D2
186 | 89690148173C0E4C00B403D2
187 |
188 |
189 | 89690124173C0E4B00B403D2
190 |
191 | buildConfigurations
192 |
193 | 89690159173C0E4C00B403D2
194 | 8969015A173C0E4C00B403D2
195 |
196 | defaultConfigurationIsVisible
197 | 0
198 | defaultConfigurationName
199 | Release
200 | isa
201 | XCConfigurationList
202 |
203 | 89690125173C0E4C00B403D2
204 |
205 | buildActionMask
206 | 2147483647
207 | files
208 |
209 | 89690139173C0E4C00B403D2
210 | 8969013D173C0E4C00B403D2
211 |
212 | isa
213 | PBXSourcesBuildPhase
214 | runOnlyForDeploymentPostprocessing
215 | 0
216 |
217 | 89690126173C0E4C00B403D2
218 |
219 | buildActionMask
220 | 2147483647
221 | files
222 |
223 | 8969012D173C0E4C00B403D2
224 | 8969012F173C0E4C00B403D2
225 | 89690131173C0E4C00B403D2
226 | 11566D315A504F04BFD15074
227 |
228 | isa
229 | PBXFrameworksBuildPhase
230 | runOnlyForDeploymentPostprocessing
231 | 0
232 |
233 | 89690127173C0E4C00B403D2
234 |
235 | buildActionMask
236 | 2147483647
237 | files
238 |
239 | 89690137173C0E4C00B403D2
240 | 8969013F173C0E4C00B403D2
241 | 89690141173C0E4C00B403D2
242 | 89690143173C0E4C00B403D2
243 |
244 | isa
245 | PBXResourcesBuildPhase
246 | runOnlyForDeploymentPostprocessing
247 | 0
248 |
249 | 89690128173C0E4C00B403D2
250 |
251 | buildConfigurationList
252 | 8969015B173C0E4C00B403D2
253 | buildPhases
254 |
255 | 468DABF301EC4EC1A00CC4C2
256 | 89690125173C0E4C00B403D2
257 | 89690126173C0E4C00B403D2
258 | 89690127173C0E4C00B403D2
259 | 13656AD991424BF58F43F5B7
260 |
261 | buildRules
262 |
263 | dependencies
264 |
265 | isa
266 | PBXNativeTarget
267 | name
268 | ObjectiveSugar
269 | productName
270 | ObjectiveSugar
271 | productReference
272 | 89690129173C0E4C00B403D2
273 | productType
274 | com.apple.product-type.application
275 |
276 | 89690129173C0E4C00B403D2
277 |
278 | explicitFileType
279 | wrapper.application
280 | includeInIndex
281 | 0
282 | isa
283 | PBXFileReference
284 | path
285 | ObjectiveSugar.app
286 | sourceTree
287 | BUILT_PRODUCTS_DIR
288 |
289 | 8969012A173C0E4C00B403D2
290 |
291 | children
292 |
293 | 89690129173C0E4C00B403D2
294 | 89690149173C0E4C00B403D2
295 |
296 | isa
297 | PBXGroup
298 | name
299 | Products
300 | sourceTree
301 | <group>
302 |
303 | 8969012B173C0E4C00B403D2
304 |
305 | children
306 |
307 | 8969012C173C0E4C00B403D2
308 | 8969012E173C0E4C00B403D2
309 | 89690130173C0E4C00B403D2
310 | 32DEFD3FCB544122AD940C8F
311 | D3D0B2406C7A45249244F020
312 |
313 | isa
314 | PBXGroup
315 | name
316 | Frameworks
317 | sourceTree
318 | <group>
319 |
320 | 8969012C173C0E4C00B403D2
321 |
322 | isa
323 | PBXFileReference
324 | lastKnownFileType
325 | wrapper.framework
326 | name
327 | UIKit.framework
328 | path
329 | System/Library/Frameworks/UIKit.framework
330 | sourceTree
331 | SDKROOT
332 |
333 | 8969012D173C0E4C00B403D2
334 |
335 | fileRef
336 | 8969012C173C0E4C00B403D2
337 | isa
338 | PBXBuildFile
339 |
340 | 8969012E173C0E4C00B403D2
341 |
342 | isa
343 | PBXFileReference
344 | lastKnownFileType
345 | wrapper.framework
346 | name
347 | Foundation.framework
348 | path
349 | System/Library/Frameworks/Foundation.framework
350 | sourceTree
351 | SDKROOT
352 |
353 | 8969012F173C0E4C00B403D2
354 |
355 | fileRef
356 | 8969012E173C0E4C00B403D2
357 | isa
358 | PBXBuildFile
359 |
360 | 89690130173C0E4C00B403D2
361 |
362 | isa
363 | PBXFileReference
364 | lastKnownFileType
365 | wrapper.framework
366 | name
367 | CoreGraphics.framework
368 | path
369 | System/Library/Frameworks/CoreGraphics.framework
370 | sourceTree
371 | SDKROOT
372 |
373 | 89690131173C0E4C00B403D2
374 |
375 | fileRef
376 | 89690130173C0E4C00B403D2
377 | isa
378 | PBXBuildFile
379 |
380 | 89690132173C0E4C00B403D2
381 |
382 | children
383 |
384 | 8969013B173C0E4C00B403D2
385 | 8969013C173C0E4C00B403D2
386 | 89690133173C0E4C00B403D2
387 |
388 | isa
389 | PBXGroup
390 | path
391 | ObjectiveSugar
392 | sourceTree
393 | <group>
394 |
395 | 89690133173C0E4C00B403D2
396 |
397 | children
398 |
399 | 89690134173C0E4C00B403D2
400 | 89690135173C0E4C00B403D2
401 | 89690138173C0E4C00B403D2
402 | 8969013A173C0E4C00B403D2
403 | 8969013E173C0E4C00B403D2
404 | 89690140173C0E4C00B403D2
405 | 89690142173C0E4C00B403D2
406 |
407 | isa
408 | PBXGroup
409 | name
410 | Supporting Files
411 | sourceTree
412 | <group>
413 |
414 | 89690134173C0E4C00B403D2
415 |
416 | isa
417 | PBXFileReference
418 | lastKnownFileType
419 | text.plist.xml
420 | path
421 | ObjectiveSugar-Info.plist
422 | sourceTree
423 | <group>
424 |
425 | 89690135173C0E4C00B403D2
426 |
427 | children
428 |
429 | 89690136173C0E4C00B403D2
430 |
431 | isa
432 | PBXVariantGroup
433 | name
434 | InfoPlist.strings
435 | sourceTree
436 | <group>
437 |
438 | 89690136173C0E4C00B403D2
439 |
440 | isa
441 | PBXFileReference
442 | lastKnownFileType
443 | text.plist.strings
444 | name
445 | en
446 | path
447 | en.lproj/InfoPlist.strings
448 | sourceTree
449 | <group>
450 |
451 | 89690137173C0E4C00B403D2
452 |
453 | fileRef
454 | 89690135173C0E4C00B403D2
455 | isa
456 | PBXBuildFile
457 |
458 | 89690138173C0E4C00B403D2
459 |
460 | isa
461 | PBXFileReference
462 | lastKnownFileType
463 | sourcecode.c.objc
464 | path
465 | main.m
466 | sourceTree
467 | <group>
468 |
469 | 89690139173C0E4C00B403D2
470 |
471 | fileRef
472 | 89690138173C0E4C00B403D2
473 | isa
474 | PBXBuildFile
475 |
476 | 8969013A173C0E4C00B403D2
477 |
478 | isa
479 | PBXFileReference
480 | lastKnownFileType
481 | sourcecode.c.h
482 | path
483 | ObjectiveSugar-Prefix.pch
484 | sourceTree
485 | <group>
486 |
487 | 8969013B173C0E4C00B403D2
488 |
489 | isa
490 | PBXFileReference
491 | lastKnownFileType
492 | sourcecode.c.h
493 | path
494 | AppDelegate.h
495 | sourceTree
496 | <group>
497 |
498 | 8969013C173C0E4C00B403D2
499 |
500 | isa
501 | PBXFileReference
502 | lastKnownFileType
503 | sourcecode.c.objc
504 | path
505 | AppDelegate.m
506 | sourceTree
507 | <group>
508 |
509 | 8969013D173C0E4C00B403D2
510 |
511 | fileRef
512 | 8969013C173C0E4C00B403D2
513 | isa
514 | PBXBuildFile
515 |
516 | 8969013E173C0E4C00B403D2
517 |
518 | isa
519 | PBXFileReference
520 | lastKnownFileType
521 | image.png
522 | path
523 | Default.png
524 | sourceTree
525 | <group>
526 |
527 | 8969013F173C0E4C00B403D2
528 |
529 | fileRef
530 | 8969013E173C0E4C00B403D2
531 | isa
532 | PBXBuildFile
533 |
534 | 89690140173C0E4C00B403D2
535 |
536 | isa
537 | PBXFileReference
538 | lastKnownFileType
539 | image.png
540 | path
541 | Default@2x.png
542 | sourceTree
543 | <group>
544 |
545 | 89690141173C0E4C00B403D2
546 |
547 | fileRef
548 | 89690140173C0E4C00B403D2
549 | isa
550 | PBXBuildFile
551 |
552 | 89690142173C0E4C00B403D2
553 |
554 | isa
555 | PBXFileReference
556 | lastKnownFileType
557 | image.png
558 | path
559 | Default-568h@2x.png
560 | sourceTree
561 | <group>
562 |
563 | 89690143173C0E4C00B403D2
564 |
565 | fileRef
566 | 89690142173C0E4C00B403D2
567 | isa
568 | PBXBuildFile
569 |
570 | 89690144173C0E4C00B403D2
571 |
572 | buildActionMask
573 | 2147483647
574 | files
575 |
576 | 89690168173C16A100B403D2
577 | 89690169173C16A100B403D2
578 | 8969016A173C16A100B403D2
579 | 8969016B173C16A100B403D2
580 | 8969016C173C16A100B403D2
581 | 8969016D173C16A100B403D2
582 | 8969016E173C16A100B403D2
583 |
584 | isa
585 | PBXSourcesBuildPhase
586 | runOnlyForDeploymentPostprocessing
587 | 0
588 |
589 | 89690145173C0E4C00B403D2
590 |
591 | buildActionMask
592 | 2147483647
593 | files
594 |
595 | 8969014C173C0E4C00B403D2
596 | 8969014D173C0E4C00B403D2
597 | A06180063BF14EB68414F45F
598 |
599 | isa
600 | PBXFrameworksBuildPhase
601 | runOnlyForDeploymentPostprocessing
602 | 0
603 |
604 | 89690146173C0E4C00B403D2
605 |
606 | buildActionMask
607 | 2147483647
608 | files
609 |
610 | 89690155173C0E4C00B403D2
611 |
612 | isa
613 | PBXResourcesBuildPhase
614 | runOnlyForDeploymentPostprocessing
615 | 0
616 |
617 | 89690147173C0E4C00B403D2
618 |
619 | buildActionMask
620 | 2147483647
621 | files
622 |
623 | inputPaths
624 |
625 | isa
626 | PBXShellScriptBuildPhase
627 | outputPaths
628 |
629 | runOnlyForDeploymentPostprocessing
630 | 0
631 | shellPath
632 | /bin/sh
633 | shellScript
634 | # Run the unit tests in this test bundle.
635 | "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests"
636 |
637 |
638 | 89690148173C0E4C00B403D2
639 |
640 | buildConfigurationList
641 | 8969015E173C0E4C00B403D2
642 | buildPhases
643 |
644 | BC624B20376C4C728DE6A392
645 | 89690144173C0E4C00B403D2
646 | 89690145173C0E4C00B403D2
647 | 89690146173C0E4C00B403D2
648 | 89690147173C0E4C00B403D2
649 | 174A1F9A81B44DC6B8B6DFD9
650 |
651 | buildRules
652 |
653 | dependencies
654 |
655 | 8969014F173C0E4C00B403D2
656 |
657 | isa
658 | PBXNativeTarget
659 | name
660 | ObjectiveSugarTests
661 | productName
662 | ObjectiveSugarTests
663 | productReference
664 | 89690149173C0E4C00B403D2
665 | productType
666 | com.apple.product-type.bundle.unit-test
667 |
668 | 89690149173C0E4C00B403D2
669 |
670 | explicitFileType
671 | wrapper.cfbundle
672 | includeInIndex
673 | 0
674 | isa
675 | PBXFileReference
676 | path
677 | ObjectiveSugarTests.octest
678 | sourceTree
679 | BUILT_PRODUCTS_DIR
680 |
681 | 8969014C173C0E4C00B403D2
682 |
683 | fileRef
684 | 8969012C173C0E4C00B403D2
685 | isa
686 | PBXBuildFile
687 |
688 | 8969014D173C0E4C00B403D2
689 |
690 | fileRef
691 | 8969012E173C0E4C00B403D2
692 | isa
693 | PBXBuildFile
694 |
695 | 8969014E173C0E4C00B403D2
696 |
697 | containerPortal
698 | 89690121173C0E4B00B403D2
699 | isa
700 | PBXContainerItemProxy
701 | proxyType
702 | 1
703 | remoteGlobalIDString
704 | 89690128173C0E4C00B403D2
705 | remoteInfo
706 | ObjectiveSugar
707 |
708 | 8969014F173C0E4C00B403D2
709 |
710 | isa
711 | PBXTargetDependency
712 | target
713 | 89690128173C0E4C00B403D2
714 | targetProxy
715 | 8969014E173C0E4C00B403D2
716 |
717 | 89690150173C0E4C00B403D2
718 |
719 | children
720 |
721 | 89690161173C16A100B403D2
722 | 89690162173C16A100B403D2
723 | 89690163173C16A100B403D2
724 | 89690164173C16A100B403D2
725 | 89690165173C16A100B403D2
726 | 89690166173C16A100B403D2
727 | 89690167173C16A100B403D2
728 | 89690151173C0E4C00B403D2
729 |
730 | isa
731 | PBXGroup
732 | path
733 | ObjectiveSugarTests
734 | sourceTree
735 | <group>
736 |
737 | 89690151173C0E4C00B403D2
738 |
739 | children
740 |
741 | 89690152173C0E4C00B403D2
742 | 89690153173C0E4C00B403D2
743 |
744 | isa
745 | PBXGroup
746 | name
747 | Supporting Files
748 | sourceTree
749 | <group>
750 |
751 | 89690152173C0E4C00B403D2
752 |
753 | isa
754 | PBXFileReference
755 | lastKnownFileType
756 | text.plist.xml
757 | path
758 | ObjectiveSugarTests-Info.plist
759 | sourceTree
760 | <group>
761 |
762 | 89690153173C0E4C00B403D2
763 |
764 | children
765 |
766 | 89690154173C0E4C00B403D2
767 |
768 | isa
769 | PBXVariantGroup
770 | name
771 | InfoPlist.strings
772 | sourceTree
773 | <group>
774 |
775 | 89690154173C0E4C00B403D2
776 |
777 | isa
778 | PBXFileReference
779 | lastKnownFileType
780 | text.plist.strings
781 | name
782 | en
783 | path
784 | en.lproj/InfoPlist.strings
785 | sourceTree
786 | <group>
787 |
788 | 89690155173C0E4C00B403D2
789 |
790 | fileRef
791 | 89690153173C0E4C00B403D2
792 | isa
793 | PBXBuildFile
794 |
795 | 89690159173C0E4C00B403D2
796 |
797 | buildSettings
798 |
799 | ALWAYS_SEARCH_USER_PATHS
800 | NO
801 | CLANG_CXX_LANGUAGE_STANDARD
802 | gnu++0x
803 | CLANG_CXX_LIBRARY
804 | libc++
805 | CLANG_ENABLE_OBJC_ARC
806 | YES
807 | CLANG_WARN_CONSTANT_CONVERSION
808 | YES
809 | CLANG_WARN_EMPTY_BODY
810 | YES
811 | CLANG_WARN_ENUM_CONVERSION
812 | YES
813 | CLANG_WARN_INT_CONVERSION
814 | YES
815 | CLANG_WARN__DUPLICATE_METHOD_MATCH
816 | YES
817 | CODE_SIGN_IDENTITY[sdk=iphoneos*]
818 | iPhone Developer
819 | COPY_PHASE_STRIP
820 | NO
821 | GCC_C_LANGUAGE_STANDARD
822 | gnu99
823 | GCC_DYNAMIC_NO_PIC
824 | NO
825 | GCC_OPTIMIZATION_LEVEL
826 | 0
827 | GCC_PREPROCESSOR_DEFINITIONS
828 |
829 | DEBUG=1
830 | $(inherited)
831 |
832 | GCC_SYMBOLS_PRIVATE_EXTERN
833 | NO
834 | GCC_WARN_ABOUT_RETURN_TYPE
835 | YES
836 | GCC_WARN_UNINITIALIZED_AUTOS
837 | YES
838 | GCC_WARN_UNUSED_VARIABLE
839 | YES
840 | IPHONEOS_DEPLOYMENT_TARGET
841 | 6.1
842 | ONLY_ACTIVE_ARCH
843 | YES
844 | SDKROOT
845 | iphoneos
846 |
847 | isa
848 | XCBuildConfiguration
849 | name
850 | Debug
851 |
852 | 8969015A173C0E4C00B403D2
853 |
854 | buildSettings
855 |
856 | ALWAYS_SEARCH_USER_PATHS
857 | NO
858 | CLANG_CXX_LANGUAGE_STANDARD
859 | gnu++0x
860 | CLANG_CXX_LIBRARY
861 | libc++
862 | CLANG_ENABLE_OBJC_ARC
863 | YES
864 | CLANG_WARN_CONSTANT_CONVERSION
865 | YES
866 | CLANG_WARN_EMPTY_BODY
867 | YES
868 | CLANG_WARN_ENUM_CONVERSION
869 | YES
870 | CLANG_WARN_INT_CONVERSION
871 | YES
872 | CLANG_WARN__DUPLICATE_METHOD_MATCH
873 | YES
874 | CODE_SIGN_IDENTITY[sdk=iphoneos*]
875 | iPhone Developer
876 | COPY_PHASE_STRIP
877 | YES
878 | GCC_C_LANGUAGE_STANDARD
879 | gnu99
880 | GCC_WARN_ABOUT_RETURN_TYPE
881 | YES
882 | GCC_WARN_UNINITIALIZED_AUTOS
883 | YES
884 | GCC_WARN_UNUSED_VARIABLE
885 | YES
886 | IPHONEOS_DEPLOYMENT_TARGET
887 | 6.1
888 | OTHER_CFLAGS
889 | -DNS_BLOCK_ASSERTIONS=1
890 | SDKROOT
891 | iphoneos
892 | VALIDATE_PRODUCT
893 | YES
894 |
895 | isa
896 | XCBuildConfiguration
897 | name
898 | Release
899 |
900 | 8969015B173C0E4C00B403D2
901 |
902 | buildConfigurations
903 |
904 | 8969015C173C0E4C00B403D2
905 | 8969015D173C0E4C00B403D2
906 |
907 | defaultConfigurationIsVisible
908 | 0
909 | defaultConfigurationName
910 | Release
911 | isa
912 | XCConfigurationList
913 |
914 | 8969015C173C0E4C00B403D2
915 |
916 | baseConfigurationReference
917 | 94C453035CB8232DD1A5513E
918 | buildSettings
919 |
920 | CODE_SIGN_IDENTITY
921 | iPhone Developer
922 | GCC_PRECOMPILE_PREFIX_HEADER
923 | YES
924 | GCC_PREFIX_HEADER
925 | ObjectiveSugar/ObjectiveSugar-Prefix.pch
926 | INFOPLIST_FILE
927 | ObjectiveSugar/ObjectiveSugar-Info.plist
928 | IPHONEOS_DEPLOYMENT_TARGET
929 | 4.3
930 | PRODUCT_NAME
931 | $(TARGET_NAME)
932 | WRAPPER_EXTENSION
933 | app
934 |
935 | isa
936 | XCBuildConfiguration
937 | name
938 | Debug
939 |
940 | 8969015D173C0E4C00B403D2
941 |
942 | baseConfigurationReference
943 | 9FAA69FB133006101A9A7843
944 | buildSettings
945 |
946 | CODE_SIGN_IDENTITY
947 | iPhone Developer
948 | GCC_PRECOMPILE_PREFIX_HEADER
949 | YES
950 | GCC_PREFIX_HEADER
951 | ObjectiveSugar/ObjectiveSugar-Prefix.pch
952 | INFOPLIST_FILE
953 | ObjectiveSugar/ObjectiveSugar-Info.plist
954 | IPHONEOS_DEPLOYMENT_TARGET
955 | 4.3
956 | PRODUCT_NAME
957 | $(TARGET_NAME)
958 | WRAPPER_EXTENSION
959 | app
960 |
961 | isa
962 | XCBuildConfiguration
963 | name
964 | Release
965 |
966 | 8969015E173C0E4C00B403D2
967 |
968 | buildConfigurations
969 |
970 | 8969015F173C0E4C00B403D2
971 | 89690160173C0E4C00B403D2
972 |
973 | defaultConfigurationIsVisible
974 | 0
975 | defaultConfigurationName
976 | Release
977 | isa
978 | XCConfigurationList
979 |
980 | 8969015F173C0E4C00B403D2
981 |
982 | baseConfigurationReference
983 | 893C6A18A162B9FB06935ED4
984 | buildSettings
985 |
986 | BUNDLE_LOADER
987 | $(BUILT_PRODUCTS_DIR)/ObjectiveSugar.app/ObjectiveSugar
988 | FRAMEWORK_SEARCH_PATHS
989 |
990 | $(inherited)
991 | "$(SDKROOT)/Developer/Library/Frameworks"
992 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks"
993 |
994 | GCC_PRECOMPILE_PREFIX_HEADER
995 | YES
996 | GCC_PREFIX_HEADER
997 | ObjectiveSugar/ObjectiveSugar-Prefix.pch
998 | INFOPLIST_FILE
999 | ObjectiveSugarTests/ObjectiveSugarTests-Info.plist
1000 | PRODUCT_NAME
1001 | $(TARGET_NAME)
1002 | TEST_HOST
1003 | $(BUNDLE_LOADER)
1004 |
1005 | isa
1006 | XCBuildConfiguration
1007 | name
1008 | Debug
1009 |
1010 | 89690160173C0E4C00B403D2
1011 |
1012 | baseConfigurationReference
1013 | 0D82F54D4F82F5960EA2CBA9
1014 | buildSettings
1015 |
1016 | BUNDLE_LOADER
1017 | $(BUILT_PRODUCTS_DIR)/ObjectiveSugar.app/ObjectiveSugar
1018 | FRAMEWORK_SEARCH_PATHS
1019 |
1020 | $(inherited)
1021 | "$(SDKROOT)/Developer/Library/Frameworks"
1022 | "$(DEVELOPER_LIBRARY_DIR)/Frameworks"
1023 |
1024 | GCC_PRECOMPILE_PREFIX_HEADER
1025 | YES
1026 | GCC_PREFIX_HEADER
1027 | ObjectiveSugar/ObjectiveSugar-Prefix.pch
1028 | INFOPLIST_FILE
1029 | ObjectiveSugarTests/ObjectiveSugarTests-Info.plist
1030 | PRODUCT_NAME
1031 | $(TARGET_NAME)
1032 | TEST_HOST
1033 | $(BUNDLE_LOADER)
1034 |
1035 | isa
1036 | XCBuildConfiguration
1037 | name
1038 | Release
1039 |
1040 | 89690161173C16A100B403D2
1041 |
1042 | fileEncoding
1043 | 4
1044 | isa
1045 | PBXFileReference
1046 | lastKnownFileType
1047 | sourcecode.c.objc
1048 | path
1049 | CAdditionsTests.m
1050 | sourceTree
1051 | <group>
1052 |
1053 | 89690162173C16A100B403D2
1054 |
1055 | fileEncoding
1056 | 4
1057 | isa
1058 | PBXFileReference
1059 | lastKnownFileType
1060 | sourcecode.c.objc
1061 | path
1062 | NSArrayTests.m
1063 | sourceTree
1064 | <group>
1065 |
1066 | 89690163173C16A100B403D2
1067 |
1068 | fileEncoding
1069 | 4
1070 | isa
1071 | PBXFileReference
1072 | lastKnownFileType
1073 | sourcecode.c.objc
1074 | path
1075 | NSDictionaryTests.m
1076 | sourceTree
1077 | <group>
1078 |
1079 | 89690164173C16A100B403D2
1080 |
1081 | fileEncoding
1082 | 4
1083 | isa
1084 | PBXFileReference
1085 | lastKnownFileType
1086 | sourcecode.c.objc
1087 | path
1088 | NSMutableArrayTests.m
1089 | sourceTree
1090 | <group>
1091 |
1092 | 89690165173C16A100B403D2
1093 |
1094 | fileEncoding
1095 | 4
1096 | isa
1097 | PBXFileReference
1098 | lastKnownFileType
1099 | sourcecode.c.objc
1100 | path
1101 | NSNumberTests.m
1102 | sourceTree
1103 | <group>
1104 |
1105 | 89690166173C16A100B403D2
1106 |
1107 | fileEncoding
1108 | 4
1109 | isa
1110 | PBXFileReference
1111 | lastKnownFileType
1112 | sourcecode.c.objc
1113 | path
1114 | NSSetTests.m
1115 | sourceTree
1116 | <group>
1117 |
1118 | 89690167173C16A100B403D2
1119 |
1120 | fileEncoding
1121 | 4
1122 | isa
1123 | PBXFileReference
1124 | lastKnownFileType
1125 | sourcecode.c.objc
1126 | path
1127 | NSStringTests.m
1128 | sourceTree
1129 | <group>
1130 |
1131 | 89690168173C16A100B403D2
1132 |
1133 | fileRef
1134 | 89690161173C16A100B403D2
1135 | isa
1136 | PBXBuildFile
1137 |
1138 | 89690169173C16A100B403D2
1139 |
1140 | fileRef
1141 | 89690162173C16A100B403D2
1142 | isa
1143 | PBXBuildFile
1144 |
1145 | 8969016A173C16A100B403D2
1146 |
1147 | fileRef
1148 | 89690163173C16A100B403D2
1149 | isa
1150 | PBXBuildFile
1151 |
1152 | 8969016B173C16A100B403D2
1153 |
1154 | fileRef
1155 | 89690164173C16A100B403D2
1156 | isa
1157 | PBXBuildFile
1158 |
1159 | 8969016C173C16A100B403D2
1160 |
1161 | fileRef
1162 | 89690165173C16A100B403D2
1163 | isa
1164 | PBXBuildFile
1165 |
1166 | 8969016D173C16A100B403D2
1167 |
1168 | fileRef
1169 | 89690166173C16A100B403D2
1170 | isa
1171 | PBXBuildFile
1172 |
1173 | 8969016E173C16A100B403D2
1174 |
1175 | fileRef
1176 | 89690167173C16A100B403D2
1177 | isa
1178 | PBXBuildFile
1179 |
1180 | 94C453035CB8232DD1A5513E
1181 |
1182 | includeInIndex
1183 | 1
1184 | isa
1185 | PBXFileReference
1186 | lastKnownFileType
1187 | text.xcconfig
1188 | name
1189 | Pods.debug.xcconfig
1190 | path
1191 | Pods/Target Support Files/Pods/Pods.debug.xcconfig
1192 | sourceTree
1193 | <group>
1194 |
1195 | 9ADDC0C494D895C067A28C9A
1196 |
1197 | children
1198 |
1199 | 94C453035CB8232DD1A5513E
1200 | 9FAA69FB133006101A9A7843
1201 | 893C6A18A162B9FB06935ED4
1202 | 0D82F54D4F82F5960EA2CBA9
1203 |
1204 | isa
1205 | PBXGroup
1206 | name
1207 | Pods
1208 | sourceTree
1209 | <group>
1210 |
1211 | 9FAA69FB133006101A9A7843
1212 |
1213 | includeInIndex
1214 | 1
1215 | isa
1216 | PBXFileReference
1217 | lastKnownFileType
1218 | text.xcconfig
1219 | name
1220 | Pods.release.xcconfig
1221 | path
1222 | Pods/Target Support Files/Pods/Pods.release.xcconfig
1223 | sourceTree
1224 | <group>
1225 |
1226 | A06180063BF14EB68414F45F
1227 |
1228 | fileRef
1229 | D3D0B2406C7A45249244F020
1230 | isa
1231 | PBXBuildFile
1232 |
1233 | BC624B20376C4C728DE6A392
1234 |
1235 | buildActionMask
1236 | 2147483647
1237 | files
1238 |
1239 | inputPaths
1240 |
1241 | isa
1242 | PBXShellScriptBuildPhase
1243 | name
1244 | Check Pods Manifest.lock
1245 | outputPaths
1246 |
1247 | runOnlyForDeploymentPostprocessing
1248 | 0
1249 | shellPath
1250 | /bin/sh
1251 | shellScript
1252 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
1253 | if [[ $? != 0 ]] ; then
1254 | cat << EOM
1255 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
1256 | EOM
1257 | exit 1
1258 | fi
1259 |
1260 |
1261 | D3D0B2406C7A45249244F020
1262 |
1263 | explicitFileType
1264 | archive.ar
1265 | includeInIndex
1266 | 0
1267 | isa
1268 | PBXFileReference
1269 | path
1270 | libPods-ObjectiveSugarTests.a
1271 | sourceTree
1272 | BUILT_PRODUCTS_DIR
1273 |
1274 |
1275 | rootObject
1276 | 89690121173C0E4B00B403D2
1277 |
1278 |
1279 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar.xcodeproj/xcshareddata/xcschemes/ObjectiveSugar.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
57 |
63 |
64 |
65 |
66 |
67 |
72 |
73 |
75 |
81 |
82 |
83 |
84 |
85 |
91 |
92 |
93 |
94 |
95 |
96 |
106 |
108 |
114 |
115 |
116 |
117 |
118 |
119 |
125 |
127 |
133 |
134 |
135 |
136 |
138 |
139 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar.xcworkspace/xcshareddata/ObjectiveSugar.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | D33A2B74-EF5E-434B-9D41-0462E9F67889
9 | IDESourceControlProjectName
10 | ObjectiveSugar
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | A903A85C48C7E54B4809BF250D9264F78D3D0DB1
14 | ssh://github.com/supermarin/ObjectiveSugar.git
15 |
16 | IDESourceControlProjectPath
17 | Example/ObjectiveSugar.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | A903A85C48C7E54B4809BF250D9264F78D3D0DB1
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | ssh://github.com/supermarin/ObjectiveSugar.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | A903A85C48C7E54B4809BF250D9264F78D3D0DB1
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | A903A85C48C7E54B4809BF250D9264F78D3D0DB1
36 | IDESourceControlWCCName
37 | ObjectiveSugar
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ObjectiveSugar
4 | //
5 | // Created by Marin Usalj on 5/9/13.
6 | // Copyright (c) 2013 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ObjectiveSugar
4 | //
5 | // Created by Marin Usalj on 5/9/13.
6 | // Copyright (c) 2013 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @implementation AppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | return YES;
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Example/ObjectiveSugar/Default-568h@2x.png
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Example/ObjectiveSugar/Default.png
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supermarin/ObjectiveSugar/3d1c39adb701938ce2e19f8e5a789c72450f18ed/Example/ObjectiveSugar/Default@2x.png
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/ObjectiveSugar-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | in.supermar.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/ObjectiveSugar-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'ObjectiveSugar' target in the 'ObjectiveSugar' project
3 | //
4 |
5 | #import
6 |
7 | #ifndef __IPHONE_3_0
8 | #warning "This project uses features only available in iOS SDK 3.0 and later."
9 | #endif
10 |
11 | #ifdef __OBJC__
12 | #import
13 | #import
14 | #endif
15 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugar/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ObjectiveSugar
4 | //
5 | // Created by Marin Usalj on 5/9/13.
6 | // Copyright (c) 2013 supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "AppDelegate.h"
12 |
13 | int main(int argc, char *argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/CAdditionsTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAdditionsTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 1/15/13.
6 | // Copyright 2013 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ObjectiveSugar.h"
11 |
12 | SPEC_BEGIN(c_additions_tests)
13 |
14 | describe(@"unless", ^{
15 | __block BOOL wasExecuted;
16 | beforeEach(^{
17 | wasExecuted = NO;
18 | });
19 |
20 | context(@"condition is false", ^{
21 | it(@"executes the body", ^{
22 | unless(NO) {
23 | wasExecuted = YES;
24 | }
25 | [[@(wasExecuted) should] beYes];
26 | });
27 | it(@"works with inline conditions", ^{
28 | unless((1 == 4)) {
29 | wasExecuted = YES;
30 | }
31 | [[@(wasExecuted) should] beYes];
32 | });
33 | it(@"works with inline conditions without extra parenthesies", ^{
34 | unless(1 == 4) {
35 | wasExecuted = YES;
36 | }
37 | [[@(wasExecuted) should] beYes];
38 | });
39 | it(@"works with the comma operator", ^{
40 | int i = 1;
41 | unless(i++, 1 == 4) {
42 | wasExecuted = YES;
43 | }
44 | [[@(i) should] equal:@2];
45 | [[@(wasExecuted) should] beYes];
46 | });
47 | });
48 |
49 | context(@"condition is true", ^{
50 | it(@"doesn't execute the body", ^{
51 | unless(YES) {
52 | [[@(YES) should] beNo];
53 | }
54 | });
55 | });
56 | });
57 |
58 | describe(@"until", ^{
59 | __block int condCount;
60 | __block int bodyCount;
61 |
62 | beforeEach(^{
63 | condCount = 0;
64 | bodyCount = 0;
65 | });
66 |
67 | context(@"In an until loop", ^{
68 | context(@"condition is true", ^{
69 | it(@"evaluates the condition once", ^{
70 | int i = 1;
71 | until(--i == 0) {
72 | [[@(YES) should] beNo];
73 | }
74 | [[@(i) should] equal:@0];
75 | });
76 | it(@"doesn't execute the body", ^{
77 | until(YES) {
78 | [[@(YES) should] beNo];
79 | }
80 | });
81 | it(@"works with the comma operator", ^{
82 | BOOL didEval = NO;
83 | until(didEval = YES, YES) {
84 | [[@(YES) should] beNo];
85 | }
86 | [[@(didEval) should] beYes];
87 | });
88 | });
89 |
90 | context(@"condition starts false and later changes to true", ^{
91 | it(@"evaluates the condition one fewer time than the body", ^{
92 | int iterations = 10;
93 | until(condCount++, iterations == 0) {
94 | bodyCount++;
95 | iterations--;
96 | }
97 | [[@(iterations) should] equal:@0];
98 | [[@(bodyCount) should] equal:@10];
99 | [[@(condCount) should] equal:@(bodyCount + 1)];
100 | });
101 | it(@"allows early breaking out of the loop", ^{
102 | until(condCount++, bodyCount == 100) {
103 | bodyCount++;
104 | unless(bodyCount < 50)
105 | break;
106 | }
107 | [[@(bodyCount) should] equal:@50];
108 | [[@(condCount) should] equal:@(bodyCount)];
109 | });
110 | });
111 | });
112 |
113 | context(@"In a do-until loop", ^{
114 | context(@"condition is true", ^{
115 | it(@"both evaluates the condition and executes the body exactly once", ^{
116 | do {
117 | bodyCount++;
118 | } until(condCount++, YES);
119 | [[@(bodyCount) should] equal:@1];
120 | [[@(condCount) should] equal:@(bodyCount)];
121 | });
122 | it(@"allows breaking out of the loop without ever evaluating the condition", ^{
123 | do {
124 | bodyCount++;
125 | break;
126 | } until(condCount++, YES);
127 | [[@(bodyCount) should] equal:@1];
128 | [[@(condCount) should] equal:@0];
129 | });
130 | });
131 |
132 | context(@"condition starts false and later changes to true", ^{
133 | it(@"evaluates the condition and the body the same number of times", ^{
134 | int iterations = 10;
135 | do {
136 | bodyCount++;
137 | iterations--;
138 | } until(condCount++, iterations == 0);
139 | [[@(iterations) should] equal:@0];
140 | [[@(bodyCount) should] equal:@10];
141 | [[@(condCount) should] equal:@(bodyCount)];
142 | });
143 | it(@"allows breaking out of the loop early without evaluating the condition again", ^{
144 | do {
145 | bodyCount++;
146 | if(bodyCount == 50)
147 | break;
148 | } until(condCount++, bodyCount == 100);
149 | [[@(bodyCount) should] equal:@50];
150 | [[@(condCount) should] equal:@(bodyCount - 1)];
151 | });
152 | it(@"allows continuing to next loop iteration", ^{
153 | int a = 2, b = 3;
154 | do {
155 | bodyCount++;
156 | a++;
157 | unless(a - b >= 4)
158 | continue;
159 | b += a;
160 | } until(condCount++, a == 13);
161 | [[@(a) should] equal:@13];
162 | [[@(b) should] equal:@10];
163 | [[@(bodyCount) should] equal:@11];
164 | [[@(condCount) should] equal:@(bodyCount)];
165 | });
166 | });
167 |
168 | context(@"condition is always false", ^{
169 | it(@"allows breaking out of the loop to avoid an infinite loop", ^{
170 | do {
171 | bodyCount++;
172 | unless(bodyCount < 42)
173 | break;
174 | } until(condCount++, NO);
175 | [[@(bodyCount) should] equal:@42];
176 | [[@(condCount) should] equal:@(bodyCount - 1)];
177 | });
178 | });
179 | });
180 | });
181 |
182 | SPEC_END
183 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSArrayTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSArrayCategoriesTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 7/13/12.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "ObjectiveSugar.h"
10 | #import "Kiwi.h"
11 |
12 | SPEC_BEGIN(ArrayAdditions)
13 |
14 | describe(@"NSArray categories", ^{
15 |
16 | NSArray *sampleArray = @[@"first", @"second", @"third"];
17 | NSArray *oneToTen = @[ @1, @2, @3, @4, @5, @6, @7, @8, @9, @10 ];
18 | let(duplicate, ^{ return [NSMutableArray new]; });
19 |
20 | it(@"aliases -anyObject to -sample", ^{
21 | [[sampleArray should] receive:@selector(sample)];
22 | [sampleArray anyObject];
23 | });
24 |
25 | it(@"-sample returns a random object", ^{
26 | [[theValue([sampleArray indexOfObject:sampleArray.sample]) shouldNot] equal:theValue(NSNotFound)];
27 | });
28 |
29 | it(@"-sample of empty array returns nil", ^{
30 | NSArray *emptyArray = @[];
31 | [emptyArray.sample shouldBeNil];
32 | });
33 |
34 | context(@"Iterating using block", ^{
35 |
36 | it(@"iterates using -each:^", ^{
37 | [sampleArray each:^(id object) {
38 | [duplicate addObject:object];
39 | }];
40 | [[duplicate should] equal:sampleArray];
41 | });
42 |
43 | it(@"iterates using -eachWithIndex:^", ^{
44 | [sampleArray eachWithIndex:^(id object, NSUInteger index) {
45 | [[object should] equal:[sampleArray objectAtIndex:index]];
46 | [duplicate addObject:object];
47 | }];
48 | [[duplicate should] equal:sampleArray];
49 | });
50 |
51 | it(@"iterates using -each:^withOptions:", ^{
52 | [sampleArray each:^(id object) {
53 | [duplicate addObject:object];
54 | } options:NSEnumerationReverse];
55 |
56 | [[duplicate should] equal:[sampleArray reverse]];
57 | });
58 |
59 | it(@"iterates using -eachWithIndex:^withOptions:", ^{
60 | [sampleArray eachWithIndex:^(id object, NSUInteger index) {
61 | [[object should] equal:[sampleArray objectAtIndex:index]];
62 | [duplicate addObject:object];
63 | } options:NSEnumerationReverse];
64 |
65 | [[duplicate should] equal:[sampleArray reverse]];
66 | });
67 |
68 | });
69 |
70 | it(@"aliases -containsObject to -includes", ^{
71 | [[@([sampleArray includes:@"second"]) should] equal:@(YES)];
72 | });
73 |
74 | it(@"-map returns an array of objects returned by the block", ^{
75 | NSArray *mapped = [sampleArray map:^id(id object) {
76 | return [NSNumber numberWithBool:[object isEqualToString:@"second"]];
77 | }];
78 |
79 | [[mapped should] containObjects:@(NO), @(YES), @(NO), nil];
80 | });
81 |
82 | it(@"-map treats nils the same way as -valueForKeyPath:", ^{
83 | NSArray *users = @[@{@"name": @"Marin"},@{},@{@"name": @"Neil"}];
84 | [[[users map:^id(NSDictionary *user) {
85 | return user[@"name"];
86 | }] should] equal:[users valueForKeyPath:@"name"]];
87 | });
88 |
89 | it(@"-select returns an array containing all the elements of NSArray for which block is not false", ^{
90 | [[[oneToTen select:^BOOL(id object) {
91 | return [object integerValue] % 3 == 0;
92 | }] should] equal:@[ @3, @6, @9 ]];
93 | });
94 |
95 | it(@"-detect returns the first element in NSArray for which block is true", ^{
96 | [[[oneToTen detect:^BOOL(id object) {
97 | return [object intValue] % 3 == 0;
98 | }] should] equal:@3];
99 | });
100 |
101 | it(@"-detect is safe", ^{
102 | [[[oneToTen detect:^BOOL(id object) {
103 | return [object intValue] == 1232132143;
104 | }] should] beNil];
105 | });
106 |
107 | it(@"-find aliases detect", ^{
108 | [[[oneToTen find:^BOOL(id object) {
109 | return [object intValue] % 3 == 0;
110 | }] should] equal:@3];
111 | });
112 |
113 | it(@"-reject returns an array containing all the elements of NSArray for which block is false", ^{
114 | [[[oneToTen reject:^BOOL(id object) {
115 | return [object integerValue] % 3 == 0;
116 | }] should] equal:@[ @1, @2, @4, @5, @7, @8, @10 ]];
117 | });
118 |
119 | it(@"-flatten returns a one-dimensional array that is a recursive flattening of the array", ^{
120 | NSArray *multiDimensionalArray = @[ @[ @1, @2, @3 ], @[ @4, @5, @6, @[ @7, @8 ] ], @9, @10 ];
121 | [[[multiDimensionalArray flatten] should] equal:oneToTen];
122 | });
123 |
124 | it(@"-compact removes NSNull objects", ^{
125 | NSArray *arrayWithNulls = @[@1, @2, [NSNull null], @3, [NSNull null], @4];
126 | [[[arrayWithNulls compact] should] equal:@[@1, @2, @3, @4]];
127 | });
128 |
129 | it(@"-reduce returns a result of all the elements", ^{
130 | [[[sampleArray reduce:^id(NSString *accumulator, NSString *word) {
131 | return [accumulator stringByAppendingString:word.uppercaseString];
132 | }] should] equal:@"firstSECONDTHIRD"];
133 |
134 | [[[oneToTen reduce:^id(NSNumber *accumulator, NSNumber *numbah) {
135 | return @(accumulator.intValue + numbah.intValue);
136 | }] should] equal:@55];
137 | });
138 |
139 | it(@"-reduce:withBlock with accumulator behaves like -reduce and starts with user provided element", ^{
140 | [[[sampleArray reduce:@"" withBlock:^id(NSString *accumulator, NSString *word) {
141 | return [accumulator stringByAppendingString:word.uppercaseString];
142 | }] should] equal:@"FIRSTSECONDTHIRD"];
143 |
144 | [[[oneToTen reduce:@5 withBlock:^id(NSNumber *accumulator, NSNumber *numbah) {
145 | return @(accumulator.intValue + numbah.intValue);
146 | }] should] equal:@60];
147 | });
148 |
149 | it(@"-unique produces a duplicate-free array", ^{
150 | NSArray *arrayWithDuplicates = @[@1, @1, @"something", @"something"];
151 | [[[arrayWithDuplicates unique] should] equal:@[@1, @"something"]];
152 | });
153 |
154 | context(@"array subsets", ^{
155 |
156 | it(@"creates subset of array", ^{
157 | [[[sampleArray take:2] should] equal:@[ @"first", @"second" ]];
158 | });
159 |
160 |
161 | it(@"creates subset of array and shouldn't raise exeption", ^{
162 | [[[sampleArray take:[sampleArray count]+1] should] equal:sampleArray];
163 | });
164 |
165 | it(@"creates subset of array using block", ^{
166 | [[[sampleArray takeWhile:^BOOL(id object) {
167 |
168 | return ![object isEqualToString:@"third"];
169 |
170 | }] should] equal:@[ @"first", @"second" ]];
171 | });
172 |
173 | });
174 |
175 | context(@"array range subscripting", ^{
176 |
177 | it(@"returns an array containing elements at the specified range when passing an NSValue containing an NSRange", ^{
178 | NSValue *range = [NSValue valueWithRange: NSMakeRange(2, 5)];
179 | [[oneToTen[range] should] equal:@[@3, @4, @5, @6, @7]];
180 | });
181 |
182 | it(@"returns subarray with NSRange in string format", ^{
183 | [[oneToTen[@"2,5"] should] equal:@[@3, @4, @5, @6, @7]];
184 | });
185 |
186 | it(@"returns subarray with inclusive range", ^{
187 | [[oneToTen[@"2..5"] should] equal:@[@3, @4, @5, @6]];
188 | });
189 |
190 | it(@"returns subarray with inclusive range but excludes the end value", ^{
191 | [[oneToTen[@"2...5"] should] equal:@[@3, @4, @5]];
192 | });
193 |
194 | it(@"returns subarray with inclusive range up to the end element", ^{
195 | [[oneToTen[@"2..-1"] should] equal:@[@3, @4, @5, @6, @7, @8, @9, @10]];
196 | });
197 |
198 | it(@"returns subarray with inclusive range up to the element before end element", ^{
199 | [[oneToTen[@"2...-1"] should] equal:@[@3, @4, @5, @6, @7, @8, @9]];
200 | });
201 |
202 | it(@"returns an empty array when passing an invalid or empty range", ^{
203 | [[oneToTen[@"notarange"] should] equal:@[]];
204 | });
205 |
206 | it(@"throws an invalid argument exception when passing anything other than an NSString or NSValue", ^{
207 | [[theBlock(^{
208 | [oneToTen[[[NSSet alloc] initWithArray:@[@1, @2]]] description];
209 | }) should] raiseWithName:NSInvalidArgumentException reason:@"expected NSString or NSValue argument, got __NSSetI instead"];
210 | });
211 |
212 | it(@"shouldn't break existing indexed subscripting", ^{
213 | [[oneToTen[1] should] equal:@2];
214 | });
215 | });
216 |
217 | context(@"join elements", ^{
218 |
219 | it(@"join the array with elements ", ^{
220 | [[[oneToTen join] should] equal:@"12345678910"];
221 | });
222 |
223 | it(@"join the array with elements separated by a dash", ^{
224 | [[[sampleArray join:@"-"] should] equal:@"first-second-third"];
225 | });
226 |
227 | });
228 |
229 | context(@"reverse elements", ^{
230 | it(@"reverses the elements in the array", ^{
231 | [[[oneToTen reverse] should] equal:@[@10, @9, @8, @7, @6, @5, @4, @3, @2, @1]];
232 | });
233 | });
234 |
235 | context(@"sorting", ^{
236 |
237 | it(@"-sort aliases -sortUsingComparator:", ^{
238 | [[[@[ @4, @1, @3, @2 ] sort] should] equal:@[ @1, @2, @3, @4 ]];
239 | });
240 |
241 | it(@"-sortsortBy sorts using the default comparator on the given key:", ^{
242 | NSDictionary *dict_1 = @{@"name": @"1"};
243 | NSDictionary *dict_2 = @{@"name": @"2"};
244 | NSDictionary *dict_3 = @{@"name": @"3"};
245 | NSDictionary *dict_4 = @{@"name": @"3"};
246 | [[[@[ dict_4, dict_1, dict_3, dict_2 ] sortBy:@"name"] should] equal:@[ dict_1, dict_2, dict_3, dict_4 ]];
247 | });
248 |
249 | });
250 |
251 | });
252 |
253 |
254 | describe(@"Set operations", ^{
255 |
256 | NSArray *a = @[ @1, @2 ];
257 | NSArray *b = @[ @2, @3 ];
258 |
259 | it(@"return the elements common to both arrays ", ^{
260 | [[[a intersectionWithArray:b] should] equal:@[ @2 ]];
261 | });
262 |
263 | it(@"combine the two arrays, removing duplicate elements", ^{
264 | [[[a unionWithArray:b] should] equal:@[ @1, @2, @3 ]];
265 | });
266 |
267 | it(@"return the elements in a that are not in b", ^{
268 | [[[a relativeComplement:b] should] equal:@[ @1 ]];
269 | });
270 |
271 | it(@"return the elements in b that are not in a", ^{
272 | [[[b relativeComplement:a] should] equal:@[ @3 ]];
273 | });
274 |
275 | it(@"return the elements unique to both arrays", ^{
276 | [[[a symmetricDifference:b] should] equal:@[ @1, @3 ]];
277 | });
278 | });
279 |
280 |
281 | SPEC_END
282 |
283 |
284 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSDictionaryTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionaryTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "Kiwi.h"
10 | #import "ObjectiveSugar.h"
11 |
12 | SPEC_BEGIN(DictionaryAdditions)
13 |
14 | describe(@"Iterators", ^{
15 |
16 | NSDictionary *sampleDict = @{
17 | @"one" : @1,
18 | @"two" : @2,
19 | @"three" : @3
20 | };
21 | __block NSInteger counter;
22 |
23 | beforeEach(^{
24 | counter = 0;
25 | });
26 |
27 | afterEach(^{
28 | [[@(counter) should] equal:@(sampleDict.allKeys.count)];
29 | });
30 |
31 |
32 | it(@"iterates each key and value", ^{
33 | [sampleDict each:^(id key, id value) {
34 | [[sampleDict.allKeys[counter] should] equal:key];
35 | [[sampleDict.allValues[counter] should] equal:value];
36 | counter ++;
37 | }];
38 | });
39 |
40 | it(@"iterates all keys", ^{
41 | [sampleDict eachKey:^(id key){
42 | [[sampleDict.allKeys[counter] should] equal:key];
43 | counter ++;
44 | }];
45 | });
46 |
47 | it(@"iterates all values", ^{
48 | [sampleDict eachValue:^(id value){
49 | [[sampleDict.allValues[counter] should] equal:value];
50 | counter ++;
51 | }];
52 | });
53 |
54 | it(@"iterates all keys when mapping", ^{
55 | NSArray *mapped = [sampleDict map:^id(id key, id value) {
56 | counter ++;
57 | return key;
58 | }];
59 |
60 | [[mapped should] equal:sampleDict.allKeys];
61 | });
62 |
63 | it(@"iterates all values when mapping", ^{
64 | NSArray *mapped = [sampleDict map:^id(id key, id value) {
65 | counter ++;
66 | return value;
67 | }];
68 |
69 | [[mapped should] equal:sampleDict.allValues];
70 | });
71 | });
72 |
73 | describe(@"Keys", ^{
74 |
75 | NSDictionary *sampleDict = @{
76 | @"one": @1,
77 | @"two": @2,
78 | @"null": [NSNull null]
79 | };
80 |
81 | it(@"checks that dictionary contains the specified key", ^{
82 | [[@([sampleDict hasKey:@"one"]) should] beTrue];
83 | [[@([sampleDict hasKey:@"imaginaryKey"]) should] beFalse];
84 | });
85 |
86 | it(@"tolerates null keys", ^{
87 | [[@([sampleDict hasKey:@"null"]) should] beTrue];
88 | });
89 |
90 | });
91 |
92 | describe(@"Pick", ^{
93 | NSDictionary *sampleDict = @{
94 | @"one": @1,
95 | @"two": @2,
96 | @"null": [NSNull null]
97 | };
98 |
99 | it(@"returns a new dictionary with only the whitelisted keys", ^{
100 | [[[sampleDict pick:@[@"one", @"two"]] should] equal:@{
101 | @"one": @1,
102 | @"two": @2
103 | }];
104 | });
105 | });
106 |
107 | describe(@"Omit", ^{
108 | NSDictionary *sampleDict = @{
109 | @"one": @1,
110 | @"two": @2,
111 | @"null": [NSNull null]
112 | };
113 |
114 | it(@"returns a new dictionary without the blacklisted keys", ^{
115 | [[[sampleDict omit:@[@"one", @"two"]] should] equal:@{@"null": [NSNull null]}];
116 | });
117 | });
118 |
119 | describe(@"Merge", ^{
120 | let(h1, ^{ return @{ @"a" : @100, @"b" : @200 }; });
121 | let(h2, ^{ return @{ @"b" : @254, @"c" : @300 }; });
122 |
123 | it(@"returns a new dictionary containing the contents of h1 and h2", ^{
124 | [[[h1 merge:h2] should] equal:@{ @"a" : @100, @"b" : @254, @"c" : @300 }];
125 | });
126 | });
127 |
128 | describe(@"Merge with block", ^{
129 | let(h1, ^{ return @{ @"a" : @100, @"b" : @200 }; });
130 | let(h2, ^{ return @{ @"b" : @254, @"c" : @300 }; });
131 |
132 | it(@"returns a new dictionary containing the contents of h1 and h2", ^{
133 | [[[h1 merge:h2 block:^id(id key, id oldVal, id newVal) {
134 | return @([newVal intValue] - [oldVal intValue]);
135 | }] should] equal:@{ @"a" : @100, @"b" : @54, @"c" : @300 }];
136 | });
137 | });
138 |
139 | describe(@"Invert", ^{
140 | let(sampleDict, ^{ return @{ @"one" : @1,
141 | @"two" : @2,
142 | @"three" : @3 }; });
143 |
144 | it(@"returns a new dictionary where keys are values and values are keys", ^{
145 | [[[sampleDict invert] should] equal:@{ @1 : @"one", @2 : @"two", @3 : @"three" }];
146 | NSLog(@"%@", [sampleDict invert]);
147 | });
148 | });
149 |
150 | SPEC_END
151 |
152 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSMutableArrayTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArrayTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "ObjectiveSugar.h"
10 | #import "Kiwi.h"
11 |
12 | SPEC_BEGIN(MutableArrayAdditions)
13 |
14 | describe(@"NSMutableArray categories", ^{
15 |
16 | let(mutableArray, ^{ return [NSMutableArray arrayWithObjects:@1, @2, @3, @4, @5, nil]; });
17 |
18 | it(@"-push aliases addObject", ^{
19 | [mutableArray push:@6];
20 | [[mutableArray should] equal:@[ @1, @2, @3, @4, @5, @6 ]];
21 | });
22 |
23 | it(@"-pop removes and returns the last element of the array", ^{
24 | [[[mutableArray pop] should] equal:@5];
25 | [[mutableArray should] equal:@[ @1, @2, @3, @4 ]];
26 | });
27 |
28 | it(@"-pop with parameter removes and returns the last n elements of the array", ^{
29 | [[[mutableArray pop:2] should] equal:@[ @4, @5 ]];
30 | [[mutableArray should] equal:@[ @1, @2, @3 ]];
31 | });
32 |
33 | it(@"-concat aliases addObjectsFromArray:", ^{
34 | [mutableArray concat:@[ @7, @8, @9 ]];
35 | [[mutableArray should] equal:@[ @1, @2, @3, @4, @5, @7, @8, @9 ]];
36 | });
37 |
38 | it(@"-shift removes and returns the first element of the array", ^{
39 | [[[mutableArray shift] should] equal:@1];
40 | [[mutableArray should] equal:@[ @2, @3, @4, @5 ]];
41 | });
42 |
43 | it(@"-shift with parameter removes and returns n elements of the array", ^{
44 | [[[mutableArray shift:2] should] equal:@[ @1, @2 ]];
45 | [[mutableArray should] equal:@[ @3, @4, @5 ]];
46 | });
47 |
48 | it(@"-shift with 0 returns an empty array and doesn't change original mutable array", ^{
49 | [[[mutableArray shift:0] should] equal:@[]];
50 | [[mutableArray should] equal:@[ @1, @2, @3, @4, @5 ]];
51 | });
52 |
53 | it(@"-keepIf keeps the objects passing the block", ^{
54 | NSMutableArray *array = @[@8, @5, @9, @1, @7, @14, @17, @87, @64].mutableCopy;
55 |
56 | [array keepIf:^BOOL(id object) {
57 | return [object intValue] % 2 == 0;
58 | }];
59 |
60 | [[array should] equal:@[ @8, @14, @64 ]];
61 | });
62 |
63 | });
64 |
65 | SPEC_END
66 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSNumberTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSNumberTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/21/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "ObjectiveSugar.h"
10 | #import "Kiwi.h"
11 |
12 | SPEC_BEGIN(NumberAdditions)
13 |
14 | describe(@"Iterators", ^{
15 |
16 | __block NSInteger counter;
17 |
18 | beforeEach(^{
19 | counter = 0;
20 | });
21 |
22 | it(@"-upto iterates inclusively", ^{
23 | __block NSInteger startingPoint = 5;
24 |
25 | [@(startingPoint) upto:8 do:^(NSInteger number) {
26 | [[@(number) should] equal:@(startingPoint + counter)];
27 | counter ++;
28 | }];
29 |
30 | [[@(counter) should] equal:@(4)];
31 | });
32 |
33 | it(@"-downto iterates inclusively", ^{
34 | __block NSInteger startingPoint = 8;
35 |
36 | [@(startingPoint) downto:4 do:^(NSInteger number) {
37 | [[@(number) should] equal:@(startingPoint - counter)];
38 | counter ++;
39 | }];
40 |
41 | [[@(counter) should] equal:@(5)];
42 | });
43 |
44 |
45 | it(@"times: iterates the exact number of times", ^{
46 | [@5 times:^{
47 | counter ++;
48 | }];
49 | [[@(counter) should] equal:@5];
50 | });
51 |
52 | it(@"timesWithIndex: iterates with the right index", ^{
53 | [@5 timesWithIndex:^(NSUInteger index) {
54 | [[@(index) should] equal:@(counter)];
55 | counter ++;
56 | }];
57 | [[@(counter) should] equal:@5];
58 | });
59 |
60 | it(@"tests singular date inflections", ^{
61 | [[[@1 second] should] equal:@1];
62 | [[[@1 minute] should] equal:@60];
63 | [[[@1 hour] should] equal:@3600];
64 | [[[@1 day] should] equal:@86400];
65 | [[[@1 week] should] equal:@604800];
66 | [[[@1 fortnight] should] equal:@1209600];
67 | [[[@1 month] should] equal:@2592000];
68 | [[[@1 year] should] equal:@31557600];
69 | });
70 |
71 | it(@"tests plural date inflections", ^{
72 | [[@(2).seconds should] equal:@2];
73 | [[@(2).minutes should] equal:@120];
74 | [[@(2).hours should] equal:@7200];
75 | [[@(2).days should] equal:@172800];
76 | [[@(2).weeks should] equal:@1209600];
77 | [[@(2).fortnights should] equal:@2419200];
78 | [[@(2).months should] equal:@5184000];
79 | [[@(2).years should] equal:@63115200];
80 | });
81 |
82 | it(@"tests ago inflection", ^{
83 | NSDate *testValue = @(30).seconds.ago;
84 | NSDate *compareValue = [NSDate dateWithTimeIntervalSinceNow:-30];
85 |
86 | [[@([testValue timeIntervalSince1970]) should] equal:@([compareValue timeIntervalSince1970]).doubleValue
87 | withDelta:0.0001];
88 | });
89 |
90 | it(@"tests since inflection", ^{
91 | NSDate *now = [NSDate date];
92 | NSDate *testValue = [@(10).minutes since:now];
93 | NSDate *compareValue = [NSDate dateWithTimeInterval:600 sinceDate:now];
94 |
95 | [[@([testValue timeIntervalSince1970]) should] equal:@([compareValue timeIntervalSince1970])];
96 | });
97 |
98 | it(@"tests until inflection", ^{
99 | NSDate *now = [NSDate date];
100 | NSDate *testValue = [@(10).minutes until:now];
101 | NSDate *compareValue = [NSDate dateWithTimeInterval:-600 sinceDate:now];
102 |
103 | [[@([testValue timeIntervalSince1970]) should] equal:@([compareValue timeIntervalSince1970])];
104 | });
105 |
106 | it(@"tests from_now inflection", ^{
107 | NSDate *testValue = @(30).minutes.fromNow;
108 | NSDate *compareValue = [NSDate dateWithTimeIntervalSinceNow:(30 * 60)];
109 |
110 | [[@([testValue timeIntervalSince1970]) should] equal:@([compareValue timeIntervalSince1970]).doubleValue
111 | withDelta:0.0001];
112 | });
113 |
114 | });
115 |
116 | SPEC_END
117 |
118 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSSetTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSSetTests.m
3 | // SampleProject
4 | //
5 | // Created by Marin Usalj on 11/23/12.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "Kiwi.h"
10 | #import "ObjectiveSugar.h"
11 |
12 | SPEC_BEGIN(SetAdditions)
13 |
14 | describe(@"Iterators", ^{
15 |
16 |
17 | NSSet *sampleSet = [NSSet setWithArray:@[@"first", @"second", @"third"]];
18 |
19 | context(@"Iterating using block", ^{
20 |
21 | it(@"iterates using -each:^", ^{
22 | NSMutableArray *duplicate = [sampleSet.allObjects mutableCopy];
23 |
24 | [sampleSet each:^(id object) {
25 | [[duplicate should] contain:object];
26 | [duplicate removeObject:object];
27 | }];
28 | [[duplicate should] beEmpty];
29 | });
30 |
31 | it(@"iterates using -eachWithIndex:^", ^{
32 | NSMutableArray *duplicate = [sampleSet.allObjects mutableCopy];
33 |
34 | [sampleSet eachWithIndex:^(id object, NSUInteger index) {
35 | [[object should] equal:sampleSet.allObjects[index]];
36 | [duplicate removeObject:object];
37 | }];
38 | [[duplicate should] beEmpty];
39 | });
40 |
41 | });
42 |
43 | context(@"first, last, sample", ^{
44 |
45 | it(@"-first returns object at index 0", ^{
46 | [[sampleSet.firstObject should] equal:sampleSet.allObjects[0]];
47 | });
48 |
49 | it(@"-first does not crash if there's no objects in set", ^{
50 | KWBlock *block = [[KWBlock alloc] initWithBlock:^{
51 | NSSet *empty = [NSSet set];
52 | [empty.firstObject description];
53 | }];
54 | [[block shouldNot] raise];
55 | });
56 |
57 | it(@"-last returns the last object", ^{
58 | [[sampleSet.lastObject should] equal:sampleSet.allObjects.lastObject];
59 | });
60 |
61 | it(@"-sample returns a random object", ^{
62 | [[sampleSet member:sampleSet.sample] shouldNotBeNil];
63 | });
64 |
65 | it(@"-sample of empty set returns nil", ^{
66 | NSSet *emptySet = [NSSet set];
67 | [emptySet.sample shouldBeNil];
68 | });
69 | });
70 |
71 | context(@"modifications", ^{
72 |
73 | NSSet *cars = [NSSet setWithArray:@[@"Testarossa", @"F50", @"F458 Italia"]];
74 | let(items, ^id{
75 | return @[@{ @"value": @4 }, @{ @"value": @5 }, @{ @"value": @9 }];
76 | });
77 |
78 | it(@"-map returns an array of objects returned by the block", ^{
79 | NSArray *mapped = [sampleSet map:^id(id object) {
80 | return @([object isEqualToString:@"third"]);
81 | }];
82 | [[mapped should] containObjects:@NO, @YES, @NO, nil];
83 | });
84 |
85 | it(@"-map treats nils the same way as -valueForKeyPath:", ^{
86 | NSSet *users = [NSSet setWithArray:@[@{@"name": @"Marin"}, @{@"fake": @"value"}, @{@"name": @"Neil"}]];
87 | NSArray *mappedUsers = [users map:^id(NSDictionary *user) { return user[@"name"]; }];
88 |
89 | [[mappedUsers.sort should] equal:[[users valueForKeyPath:@"name"] allObjects].sort];
90 | [[mappedUsers should] haveCountOf:2];
91 | [[mappedUsers should] containObjects:@"Marin", @"Neil", nil];
92 | });
93 |
94 | it(@"-select returns an array containing all the elements of NSArray for which block is not false", ^{
95 | [[[cars select:^BOOL(NSString *car) {
96 | return [car isEqualToString:@"F50"];
97 | }] should] equal:@[ @"F50" ]];
98 | });
99 |
100 | it(@"-reject returns an array containing all the elements of NSArray for which block is false", ^{
101 | [[[cars reject:^BOOL(NSString* car) {
102 | return [car isEqualToString:@"F50"];
103 | }] should] equal:@[ @"F458 Italia", @"Testarossa" ]];
104 | });
105 |
106 | it(@"-reduce returns a result of all the elements", ^{
107 | [[[items reduce:^id(NSDictionary *accumulator, NSDictionary *item) {
108 | return [accumulator[@"value"] intValue] > [item[@"value"] intValue]
109 | ? accumulator : item;
110 | }] should] equal:@{ @"value": @9 }];
111 | });
112 |
113 | it(@"-reduce:withBlock with accumulator behaves like -reduce and starts with user provided element", ^{
114 | [[[items reduce:@0 withBlock:^id(NSNumber *accumulator, NSDictionary *item) {
115 | return @(accumulator.intValue + [item[@"value"] intValue]);
116 | }] should] equal:@18];
117 | });
118 |
119 | });
120 |
121 | context(@"sorting", ^{
122 |
123 | it(@"-sort aliases -sortUsingComparator:", ^{
124 | NSSet *numbers = [NSSet setWithArray:@[ @4, @1, @3, @2 ]];
125 | [[[numbers sort] should] equal:@[ @1, @2, @3, @4 ]];
126 | });
127 |
128 | });
129 |
130 | });
131 |
132 | SPEC_END
133 |
134 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/NSStringTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSStringTests.m
3 | // SampleProject
4 | //
5 | // Created by Neil on 05/12/2012.
6 | // Copyright (c) 2012 @supermarin | supermar.in. All rights reserved.
7 | //
8 |
9 | #import "Kiwi.h"
10 | #import "ObjectiveSugar.h"
11 |
12 | SPEC_BEGIN(StringAdditions)
13 |
14 | describe(@"Foundation-style functions", ^{
15 |
16 | it(@"NSStringWithFormat makes NSString -stringWithFormat", ^{
17 |
18 | [[NSStringWithFormat(@"This is %@", @1) should] equal:@"This is 1"];
19 | });
20 |
21 | });
22 |
23 | describe(@"Additions", ^{
24 |
25 | NSString *sentence = @"Jane Doe's going in a shop,and,yeah;";
26 |
27 | it(@"-split splits by whitespace", ^{
28 | [[[@" the\r\nquick brown\t \tfox\n" split] should] equal:@[@"the", @"quick", @"brown", @"fox"]];
29 | });
30 |
31 | it(@"-split: splits with given delimiter", ^{
32 | [[[sentence split:@","] should] equal:@[@"Jane Doe's going in a shop", @"and", @"yeah;"]];
33 | });
34 |
35 | it(@"-split: splits with delimiter string, not just a char", ^{
36 | [[[@"one / two / three" split:@" / "] should] equal:@[@"one", @"two", @"three"]];
37 | });
38 |
39 | it(@"contains string", ^{
40 | [[@([sentence containsString:@"jane doe"]) should] beTrue];
41 | });
42 |
43 | context(@"CamelCase and snake_case", ^{
44 |
45 | it(@"converts snake_cased to CamelCased", ^{
46 | [[[@"snake_case" camelCase] should] equal:@"SnakeCase"];
47 | });
48 |
49 | it(@"handles correctly snake case on beginning and at the end", ^{
50 | [[[@"_snake_case" camelCase] should] equal:@"SnakeCase"];
51 | [[[@"snake_case_" camelCase] should] equal:@"SnakeCase"];
52 | });
53 |
54 | });
55 |
56 | context(@"lowerCamelCase", ^{
57 | it(@"converts snake_case to snakeCase", ^{
58 | [[[@"snake_case" lowerCamelCase] should] equal:@"snakeCase"];
59 | });
60 |
61 | it(@"handles extraneous underscores", ^{
62 | [[[@"_snake_case" lowerCamelCase] should] equal:@"snakeCase"];
63 | [[[@"snake_case_" lowerCamelCase] should] equal:@"snakeCase"];
64 | });
65 | });
66 |
67 | it(@"-strip strips whitespaces and newlines from both ends", ^{
68 | [[[@"\n Look mo, no empties!\n \n\n " strip] should] equal:@"Look mo, no empties!"];
69 | });
70 |
71 | });
72 |
73 | describe(@"match", ^{
74 | NSString *sentence = @"Find the thing in 'single quotes'!";
75 |
76 | it(@"Should find the thing in single quotes", ^{
77 | [[[sentence match:@"'[a-zA-Z ]+'"] should] equal:@"'single quotes'"];
78 | });
79 |
80 | it(@"Should return nil is no match is found", ^{
81 | [[[sentence match:@"<[a-z]>"] should] beNil];
82 | });
83 | });
84 |
85 |
86 |
87 | SPEC_END
88 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/ObjectiveSugarTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.mneorr.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/ObjectiveSugarTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, :deployment_target => "5.0"
2 |
3 | pod 'ObjectiveSugar', :path => '../'
4 |
5 | target :ObjectiveSugarTests, :exclusive => true do
6 | pod 'Kiwi', '~> 2.3.0', :inhibit_warnings => true
7 | end
8 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Kiwi (2.3.1)
3 | - ObjectiveSugar (1.1.1)
4 |
5 | DEPENDENCIES:
6 | - Kiwi (~> 2.3.0)
7 | - ObjectiveSugar (from `../`)
8 |
9 | EXTERNAL SOURCES:
10 | ObjectiveSugar:
11 | :path: "../"
12 |
13 | SPEC CHECKSUMS:
14 | Kiwi: f038a6c61f7a9e4d7766bff5717aa3b3fdb75f55
15 | ObjectiveSugar: 0729eb74a757ea48b109a8902178c9b89aa58a9f
16 |
17 | COCOAPODS: 0.36.4
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright © 2012 Marin Usalj, http://supermar.in
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/ObjectiveSugar.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'ObjectiveSugar'
3 | s.version = '1.1.1'
4 | s.summary = 'Objective C additions for humans. Write ObjC _like a boss_.'
5 | s.description = '-map, -each, -select, unless(true){}, -includes, -upto, -downto, and many more!'
6 | s.homepage = 'https://github.com/supermarin/ObjectiveSugar'
7 | s.license = { :type => 'MIT', :file => 'LICENSE' }
8 | s.authors = { 'Marin Usalj' => "marin2211@gmail.com",'Neil Cowburn' => 'git@neilcowburn.com'}
9 | s.source = { :git => 'https://github.com/supermarin/ObjectiveSugar.git', :tag => s.version.to_s }
10 | s.social_media_url = "https://twitter.com/_supermarin"
11 |
12 | s.ios.deployment_target = '4.0'
13 | s.osx.deployment_target = '10.6'
14 |
15 | s.requires_arc = true
16 |
17 | s.source_files = 'Classes', 'Classes/**/*.{h,m}'
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | > Write Objective C _like a boss_.
4 |
5 | A set of functional additions for Foundation you wish you'd had in the first place.
6 |
7 |
8 | [](https://travis-ci.org/supermarin/ObjectiveSugar)
9 |
10 |
11 | ## Usage
12 |
13 | 1. Install via [CocoaPods](http://cocoapods.org/)
14 |
15 | ```
16 | pod 'ObjectiveSugar'
17 | ```
18 | 2. Import the public header
19 |
20 | ```
21 | #import
22 | ```
23 |
24 |
25 | ## Documentation
26 |
27 |
28 | __NSNumber__ additions
29 | ``` objc
30 | [@3 times:^{
31 | NSLog(@"Hello!");
32 | }];
33 | // Hello!
34 | // Hello!
35 | // Hello!
36 |
37 | [@3 timesWithIndex:^(NSUInteger index) {
38 | NSLog(@"Another version with number: %d", index);
39 | }];
40 | // Another version with number: 0
41 | // Another version with number: 1
42 | // Another version with number: 2
43 |
44 |
45 | [@1 upto:4 do:^(NSInteger numbah) {
46 | NSLog(@"Current number.. %d", numbah);
47 | }];
48 | // Current number.. 1
49 | // Current number.. 2
50 | // Current number.. 3
51 | // Current number.. 4
52 |
53 | [@7 downto:4 do:^(NSInteger numbah) {
54 | NSLog(@"Current number.. %d", numbah);
55 | }];
56 | // Current number.. 7
57 | // Current number.. 6
58 | // Current number.. 5
59 | // Current number.. 4
60 |
61 | NSDate *firstOfDecember = [NSDate date]; // let's pretend it's 1st of December
62 |
63 | NSDate *firstOfNovember = [@30.days since:firstOfDecember];
64 | // 2012-11-01 00:00:00 +0000
65 |
66 | NSDate *christmas = [@7.days until:newYearsDay];
67 | // 2012-12-25 00:00:00 +0000
68 |
69 | NSDate *future = @24.days.fromNow;
70 | // 2012-12-25 20:49:05 +0000
71 |
72 | NSDate *past = @1.month.ago;
73 | // 2012-11-01 20:50:28 +00:00
74 | ```
75 | --
76 | __NSArray__ / __NSSet__ additions
77 | ``` objc
78 | // All of these methods return a modified copy of the array.
79 | // They're not modifying the source array.
80 |
81 | NSArray *cars = @[@"Testarossa", @"F50", @"F458 Italia"]; // or NSSet
82 |
83 | [cars each:^(id object) {
84 | NSLog(@"Car: %@", object);
85 | }];
86 | // Car: Testarossa
87 | // Car: F50
88 | // Car: F458 Italia
89 |
90 | [cars eachWithIndex:^(id object, NSUInteger index) {
91 | NSLog(@"Car: %@ index: %i", object, index);
92 | }];
93 | // Car: Testarossa index: 0
94 | // Car: F50 index: 1
95 | // Car: F458 Italia index: 2
96 |
97 | [cars each:^(id object) {
98 | NSLog(@"Car: %@", object);
99 | } options:NSEnumerationReverse];
100 | // Car: F458 Italia
101 | // Car: F50
102 | // Car: Testarossa
103 |
104 | [cars eachWithIndex:^(id object, NSUInteger index) {
105 | NSLog(@"Car: %@ index: %i", object, index);
106 | } options:NSEnumerationReverse];
107 | // Car: F458 Italia index: 2
108 | // Car: F50 index: 1
109 | // Car: Testarossa index: 0
110 |
111 | [cars map:^(NSString* car) {
112 | return car.lowercaseString;
113 | }];
114 | // testarossa, f50, f458 italia
115 |
116 | // Or, a more common example:
117 | [cars map:^(NSString* carName) {
118 | return [[Car alloc] initWithName:carName];
119 | }];
120 | // array of Car objects
121 |
122 | NSArray *mixedData = @[ @1, @"Objective Sugar!", @"Github", @4, @"5"];
123 |
124 | [mixedData select:^BOOL(id object) {
125 | return ([object class] == [NSString class]);
126 | }];
127 | // Objective Sugar, Github, 5
128 |
129 | [mixedData reject:^BOOL(id object) {
130 | return ([object class] == [NSString class]);
131 | }];
132 | // 1, 4
133 |
134 | NSArray *numbers = @[ @5, @2, @7, @1 ];
135 | [numbers sort];
136 | // 1, 2, 5, 7
137 |
138 | cars.sample
139 | // 458 Italia
140 | cars.sample
141 | // F50
142 |
143 | ```
144 | --
145 | __NSArray__ only
146 | ``` objc
147 |
148 | NSArray *numbers = @[@1, @2, @3, @4, @5, @6];
149 |
150 | // index from 2 to 4
151 | numbers[@"2..4"];
152 | // [@3, @4, @5]
153 |
154 | // index from 2 to 4 (excluded)
155 | numbers[@"2...4"];
156 | // [@3, @4]
157 |
158 | // With NSRange location: 2, length: 4
159 | numbers[@"2,4"];
160 | // [@3, @4, @5, @6]
161 |
162 | NSValue *range = [NSValue valueWithRange:NSMakeRange(2, 4)];
163 | numbers[range];
164 | // [@3, @4, @5, @6]
165 |
166 | [numbers reverse];
167 | // [@6, @5, @4, @3, @2, @1]
168 |
169 |
170 | NSArray *fruits = @[ @"banana", @"mango", @"apple", @"pear" ];
171 |
172 | [fruits includes:@"apple"];
173 | // YES
174 |
175 | [fruits take:3];
176 | // banana, mango, apple
177 |
178 | [fruits takeWhile:^BOOL(id fruit) {
179 | return ![fruit isEqualToString:@"apple"];
180 | }];
181 | // banana, mango
182 |
183 | NSArray *nestedArray = @[ @[ @1, @2, @3 ], @[ @4, @5, @6, @[ @7, @8 ] ], @9, @10 ];
184 | [nestedArray flatten];
185 | // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
186 |
187 | NSArray *abc = @[ @"a", @"b", @"c" ];
188 | [abc join];
189 | // abc
190 |
191 | [abc join:@"-"];
192 | // a-b-c
193 |
194 | NSArray *mixedData = @[ @1, @"Objective Sugar!", @"Github", @4, @"5"];
195 |
196 | [mixedData detect:^BOOL(id object) {
197 | return ([object class] == [NSString class]);
198 | }];
199 | // Objective Sugar
200 |
201 |
202 |
203 | // TODO: Make a better / simpler example of this
204 | NSArray *landlockedCountries = @[ @"Bolivia", @"Paraguay", @"Austria", @"Switzerland", @"Hungary" ];
205 | NSArray *europeanCountries = @[ @"France", @"Germany", @"Austria", @"Spain", @"Hungary", @"Poland", @"Switzerland" ];
206 |
207 |
208 | [landlockedCountries intersectionWithArray:europeanCountries];
209 | // landlockedEuropeanCountries = Austria, Switzerland, Hungary
210 |
211 | [landlockedCountries unionWithArray:europeanCountries];
212 | // landlockedOrEuropean = Bolivia, Paraguay, Austria, Switzerland, Hungary, France, Germany, Spain, Poland
213 |
214 | [landlockedCountries relativeComplement:europeanCountries];
215 | // nonEuropeanLandlockedCountries = Bolivia, Paraguay
216 |
217 | [europeanCountries relativeComplement:landlockedCountries];
218 | // notLandlockedEuropeanCountries = France, Germany, Spain, Poland
219 |
220 | [landlockedCountries symmetricDifference:europeanCountries];
221 | // uniqueCountries = Bolivia, Paraguay, France, Germany, Spain, Poland
222 | ```
223 | --
224 | __NSMutableArray__ additions
225 | ``` objc
226 | NSMutableArray *people = @[ @"Alice", @"Benjamin", @"Christopher" ];
227 |
228 | [people push:@"Daniel"]; // Alice, Benjamin, Christopher, Daniel
229 |
230 | [people pop]; // Daniel
231 | // people = Alice, Benjamin, Christopher
232 |
233 | [people pop:2]; // Benjamin, Christopher
234 | // people = Alice
235 |
236 | [people concat:@[ @"Evan", @"Frank", @"Gavin" ]];
237 | // people = Alice, Evan, Frank, Gavin
238 |
239 | [people keepIf:^BOOL(id object) {
240 | return [object characterAtIndex:0] == 'E';
241 | }];
242 | // people = Evan
243 |
244 | ```
245 | --
246 | __NSDictionary__ additions
247 | ``` objc
248 | NSDictionary *dict = @{ @"one" : @1, @"two" : @2, @"three" : @3 };
249 |
250 | [dict each:^(id key, id value){
251 | NSLog(@"Key: %@, Value: %@", key, value);
252 | }];
253 | // Key: one, Value: 1
254 | // Key: two, Value: 2
255 | // Key: three, Value: 3
256 |
257 | [dict eachKey:^(id key) {
258 | NSLog(@"Key: %@", key);
259 | }];
260 | // Key: one
261 | // Key: two
262 | // Key: three
263 |
264 | [dict eachValue:^(id value) {
265 | NSLog(@"Value: %@", value);
266 | }];
267 | // Value: 1
268 | // Value: 2
269 | // Value: 3
270 |
271 | [dict invert];
272 | // { 1 = one, 2 = two, 3 = three}
273 |
274 | NSDictionary *errors = @{
275 | @"username" : @[ @"already taken" ],
276 | @"password" : @[ @"is too short (minimum is 8 characters)", @"not complex enough" ],
277 | @"email" : @[ @"can't be blank" ];
278 | };
279 |
280 | [errors map:^(id attribute, id reasons) {
281 | return NSStringWithFormat(@"%@ %@", attribute, [reasons join:@", "]);
282 | }];
283 | // username already taken
284 | // password is too short (minimum is 8 characters), not complex enough
285 | // email can't be blank
286 |
287 | [errors hasKey:@"email"]
288 | // true
289 | [errors hasKey:@"Alcatraz"]
290 | // false
291 | ```
292 | --
293 | __NSString__ additions
294 | ``` objc
295 | NSString *sentence = NSStringWithFormat(@"This is a text-with-argument %@", @1234);
296 | // This is a text-with-argument 1234
297 |
298 | [sentence split];
299 | // array = this, is, a, text-with-argument, 1234
300 |
301 | [sentence split:@"-"]
302 | // array = this is a text, with, argument 1234
303 |
304 | [sentence containsString:@"this is a"];
305 | // YES
306 |
307 | [sentence match:@"-[a-z]+-"]
308 | // -with-
309 | ```
310 | --
311 | __C__ additions
312 | ``` objc
313 | unless(_messages) {
314 | // The body is only executed if the condition is false
315 | _messages = [self initializeMessages];
316 | }
317 |
318 | int iterations = 10;
319 | until(iterations == 0) {
320 | // The body is executed until the condition is false
321 | // 10 9 8 7 6 5 4 3 2 1
322 | printf("%d ", iterations);
323 | iterations--;
324 | }
325 | printf("\n");
326 |
327 | iterations = 10;
328 | do {
329 | // The body is executed at least once until the condition is false
330 | // Will print: Executed!
331 | printf("Executed!\n");
332 | } until(true);
333 | ```
334 |
335 | ## Contributing
336 |
337 | ObjectiveSugar is tested with [Kiwi](https://github.com/allending/Kiwi), and tests are located in Example.
338 | If you plan on contributing to the project, please:
339 |
340 | * Write tests
341 | * Write documentation
342 |
343 |
344 | ## Team
345 |
346 | - Marin Usalj [@supermarin](https://github.com/supermarin)
347 | - Neil Cowburn [@neilco](https://github.com/neilco)
348 |
349 |
--------------------------------------------------------------------------------