Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 334 lines (236 sloc) 9.21 kB
11ff933 @kmalakoff Upgrading to new Cocoapods
authored
1 # SubjectiveScript.m
2
3 [![Version](http://cocoapod-badges.herokuapp.com/v/SubjectiveScript.m/badge.png)](http://cocoadocs.org/docsets/SubjectiveScript.m)
4 [![Platform](http://cocoapod-badges.herokuapp.com/p/SubjectiveScript.m/badge.png)](http://cocoadocs.org/docsets/SubjectiveScript.m)
5
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
6 Subjective-Script makes Objective-C more scripty!
7
3bb81b2 Reorganized into top-level Lib directory
Kevin Malakoff authored
8 **Note:** Subjective-Script requires ARC to be enabled on your Objective-C project.
9
0f45716 @kmalakoff Update README.md
authored
10 ### The Idea
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
11
12 My language of preference is CoffeeScript and whenever I develop in Objective-C, I find myself often having to look up [NSSomething reallyLongFunctionName:YES withAVerboseParameterName:YES and:[NSSomethingElse whichAddsMoreBrackets]] and it isn't very enjoyable or speedy!
13
14 While I was porting a test for [_.m](https://github.com/kmalakoff/_.m) from the original [Underscore.js](http://underscorejs.org/) that was easy to read:
15
16 ```JavaScript
17 var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
18 people = _.sortBy(people, function(person){ return person.age; });
19 equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
20 ```
21
22 It looked like this in Objective-C:
23
24 ```
25 NSArray *people = [NSArray arrayWithObjects:
26 [NSDictionary dictionaryWithObjectsAndKeys: @"moe", @"name", [NSNumber numberWithInt:30], @"age", nil],
27 [NSDictionary dictionaryWithObjectsAndKeys: @"curly", @"name", [NSNumber numberWithInt:50], @"age", nil],
28 nil];
29
30 STAssertEqualObjects([_.pluck(people, @"name") componentsJoinedByString:@", "],
31 @"moe, curly",
32 @"stooges sorted by age");
33 ```
34
35 The keys were in the wrong order, there was too much typing involved, and it became unreadable. So I wrote [Subjective-Script](https://github.com/kmalakoff/SubjectiveScript.m) and ported [QUnit.m](https://github.com/kmalakoff/QUnit.m) to end up with this:
36
37 ```
38 A* people = AO(OKV({@"name", @"curly"}, {@"age", N.I(50)}), OKV({@"name", @"moe"}, {@"age", N.I(30)}));
39 people = _.sortBy(people, ^(O* person){ return person.get(@"age"); });
40 equal(_.pluck(people, @"name").join(@", "), @"moe, curly", @"stooges sorted by age");
41 ```
42
43 Much better! And best of all, I can reuse my knowledge of JavaScript for function names so I can stop looking things up and get stuff done!
44
0f45716 @kmalakoff Update README.md
authored
45 ## The Syntax
46
47 ### Types
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
48
49 While JavaScript allows flexibility in variable types, Objective-C requires explicit variable types. To try to keep it brief, I tried to condense types down to the shortest name possible:
50
51 ```
52 typedef BOOL B;
53 typedef NSInteger I;
54 typedef NSUInteger UI;
55 typedef float F;
56 typedef double D;
57 typedef id KV[2]; // key-value pair
58
59 #define NSO NSObject
60 #define A NSMutableArray
61 #define NSA NSArray
62 #define O NSMutableDictionary
63 #define NSD NSDictionary
64 #define S NSMutableString
65 #define NSS NSString
66 #define Date NSDate
67 #define N NSNumber
68 #define E NSException
69 ```
70
71 and I tried to shorten NSNumbers, too, using the above abbreviations (B, I, UI, F, D):
72
73 ```
74 N* value = N.B(true);
75 equal(value.B, true, @"YES it is!")
76 ```
77
0f45716 @kmalakoff Update README.md
authored
78 ### Using Aggregate Types
79
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
80 I tried many different ways, but this seemed to be easy-to-read and brief (with key-value pair matching checked by the compiler):
81
82 ```
83 A* arrayOfInts = AI(1, 2, 3);
84 A* arrayOfObjects = AO(N.I(1), N.F(2.0), @"hello", nil, O.new);
85 I intValue = arrayOfInts.getAt(0).I; // or: intValue = arrayOfInts.get(@"1").I;
86 arrayOfInts.setAt(0, N.I(intValue+1)); // or: arrayOfInts.set(@"1", N.I(intValue+1));
87
88 O* obj = OKV({@"int", N.I(1)}, {@"float", N.F(2.0)}, {@"string", @"hello"}, {@"nil", nil}, {@"dictionary", O.new});
89 intValue = obj.get(@"int").I;
90 obj.set(@"int", N.I(intValue+1));
91 ```
92
93 would be equivalent to the following Javascript:
94
95 ```
96 var arrayOfInts = [1, 2, 3];
97 var arrayOfObjects = [1, 2.0, 'hello', null, {}];
98 var intValue = arrayOfInts[0];
99 arrayOfInts[0] = intValue+1;
100
101 var obj = {int: 1, float: 2.0, string: 'hello', nil: null, dictionary:{}};
102 intValue = obj.int; // or: intValue = obj['int'];
103 obj.int = intValue+1; // or: obj['int'] = intValue+1;
104 ```
105
106 and if you are interested, Objective-C may make the syntax even lighter using [Objective-C literals](http://clang.llvm.org/docs/ObjectiveCLiterals.html) in the future:
107
108 ```
109 NSA* arrayOfInts = @[@1, @2, @3];
110 NSA* arrayOfObjects = @[@1, @2.0, @"hello", NSNull.null, @{}];
111 NSD* obj = @{@int: @1, @float: @2.0, @string: @"hello", @nil: NSNull.null, @dictionary:@{}};
112 ```
113
114 The JavaScript-Inspired Library
115 ==========
116
117 To be able to reuse my JavaScript knowledge and not have to look through StackOverflow for really basic things that are hard to remember in Objective-C, I've ported some common JavaScript functions.
118
119
120 All Objects
121 -------
122
123 ```
124 N.I(1).instanceof(N.class);
125 // true
126
127 (A.new).instanceof(NSA.class);
128 // true
129
130 N.B(true).toString();
131 // @"true"
132
133 OKV({@"key1", @"value1"}).toString();
134 // @"[object Object]"
135
136 AO(AI(1,2,3),N.F(4.5),OKV({@"five", @"5"})).toString();
137 // @"[[1,2,3],4.5,[object Object]]
138 ```
139
140 Arrays
141 --------
142
143 ```
144 AI(1,2,3).length;
145 // 3
146
147 AI(1,2,3).hasOwnProperty(@"2");
148 // true
149
150 AI(1,2,3).get(@"2");
151 // N.I(3)
152
153 AI(1,2,3).concat(AI(1,2,4);
154 // [1,2,3,1,2,4]
155
156 AO(@"Banana", @"Orange", @"Lemon", @"Apple", @"Mango").slice(-3,-1);
157 // [Lemon,Apple]
158
159 AI(1,2,3).reverse();
160 // [3,2,1]
161
162 AO(N.I(1),AI(2,3)).flatten(true);
163 // [1,2,3]
164
165 AI(1,2,3).pop();
166 // N.I(3)
167
168 AI(1,2,3).push(N.I(4)).push(@"out the door");
169 // [1,2,3,4,out the door]
170
171 AI(3,2,1,2).sort(nil);
172 // [1,2,2,3]
173
174 AO(@"Banana", @"Orange", @"Apple", @"Lemon").splice(2,1, @"Kiwi", @"Mango", nil);
175 // [Banana,Orange,Kiwi,Mango,Lemon]
176
177 AI(3,4,5).unshift(N.I(1),N.I(2),nil);
178 // [1,2,3,4,5]
179
180 AI(1,2,3,4,5).shift();
181 // [2,3,4,5]
182 ```
183
184 Objects/Dictionaries
185 --------
186
187 ```
188 OKV({@"int", N.I(1)}, {@"float", N.F(2.0)}).hasOwnProperty(@"int");
189 // true
190
191 OKV({@"int", N.I(1)}, {@"float", N.F(2.0)}).delete_(@"int").hasOwnProperty(@"int");
192 // false
193
194 @"int".in(OKV({@"int", N.I(1)}, {@"float", N.F(2.0)}));
195 // true
196 ```
197
eca4267 Update
Kevin Malakoff authored
198 ```
199 delete obj.key or delete obj['key'] -> obj.delete_(@"key") -> what is the delete resevered word for..can it be used?
200 ```
201
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
202 Strings
203 --------
204
205 ```
206 @"hello world!".split(@" ")
207 // [@"hello", @"world!"]
208
209 @"hello world!".split(@"");
210 // [@"h", @"e", @"l", @"l", @"o", @"w", @"o", @"r", @"l", @"d", @"!"]
211
212 @"hello".add(@"world!");
213 // @"hello world!"
214
215 S* message = S.newS(@"hello"); message.append(@" world!");
216 // message == @"hello world!"
217 ```
218
219 Dates
220 --------
221
222 ```
223 SS.stringify(Date.newYMD_JS(2012, 7, 31));
224 // @"2012-08-30T15:00:00.000Z"
225 ```
226
227 Functions
228 --------
229
230 ```
231 O* obj = OKV({@"mirror", ^(NSS* string){return string.add(@" mirror"); }});
232 @"mirror".call(obj, @"hello", nil);
233 // @"hello mirror"
234
235 @"mirror".apply(obj, AO(@"hello"));
236 // @"hello mirror"
237 ```
238
239 Utilities
240 --------
241
242 There are a few utilities on the Subjective-Script base object rather than making them global as in JavaScript.
243
244 ```
245 SS.stringify(AO(N.I(1), N.F(2.0), N.F(3.1), @"hello", nil, O.new));
246 // @"[1,2,3.1,\"hello\",null,{}]"
247
248 SS.parseInt(@"123");
249 // N.I(123)
250
251 SS.typeof_(N.B(true));
252 // @"boolean"
253
254 SS.typeof_(@"string");
255 // @"string"
256
257 SS.typeof_(Date.new);
258 // @"object"
259
260 __block BOOL called1 = false;
261 SSTimeout* timeout1 = SS.setTimeout(^{ called1 = true; }, NSEC_PER_SEC*1);
262 SS.clearTimeout(timeout1);
263 // not called
264
265 __block BOOL called2 = false;
266 SS.setTimeout(^{ called2 = true; }, NSEC_PER_SEC*2);
267 // called
268 ```
269
076b88c Updated named properties.
Kevin Malakoff authored
270 Just One More Thing
271 ---------------
272
273 You can also easily add named properties on your own objects:
274
275 ```
276 @interface MyObject : O
277 @property (strong) NSS* name;
278 @end
279 @implementation MyObject : O
280 @dynamic name;
bdb504f Updated named properties to work with NSDictionary and NSMutableDicti…
Kevin Malakoff authored
281 IMPLEMENT_NAMED_PROPERTIES
076b88c Updated named properties.
Kevin Malakoff authored
282 @end
283
284 MyObject* obj = MyObject.new;
285 obj.name = @"Steve";
286 // they call me Steve
287 ```
288
bdb504f Updated named properties to work with NSDictionary and NSMutableDicti…
Kevin Malakoff authored
289 So you can write the initial example like:
290 ```
291 @interface Stooge : O
292 @property (strong) NSS* name;
293 @property (strong) N* age;
294 @end
295 @implementation Stooge
296 @dynamic name, age;
297 IMPLEMENT_NAMED_PROPERTIES
298 @end
299
300 A* people = AO(OTKV(Stooge, {@"name", @"curly"}, {@"age", N.I(50)}), OTKV(Stooge, {@"name", @"moe"}, {@"age", N.I(30)}));
301 people = _.sortBy(people, ^(Stooge* person){ return person.age; }); // no get(@"age") required
302 equal(_.pluck(people, @"name").join(@", "), @"moe, curly", @"stooges sorted by age");
303 ```
304
11ff933 @kmalakoff Upgrading to new Cocoapods
authored
305 ## Usage
306
307 To run the example project; clone the repo, and run `pod install` from the Project directory first.
308
309 ## Requirements
310
311 ## Installation
312
313 SubjectiveScript.m is available through [CocoaPods](http://cocoapods.org), to install
314 it simply add the following line to your Podfile:
315
316 pod "SubjectiveScript.m"
317
318 ## Author
319
320 Kevin Malakoff, kmalakoff@gmail.com
321
322 ## License
323
324 SubjectiveScript.m is available under the MIT license. See the LICENSE file for more info.
325
326
327 ## Please Contribute to SubjectiveScript.m
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
328
329 Currently, this is still early days and there is a lot to add and test. Please help out!
330
7086439 Update README.md
Kevin Malakoff authored
331 If there is anything else you would like added, just implement it in a good place, write the appropriate tests, and submit a pull request on [GitHub](https://github.com/kmalakoff/SubjectiveScript.m/pulls).
5d2a3cc Added JavaScript tests and worked on README
Kevin Malakoff authored
332
333 Also, feel free to submit your favorite features from other languages as long as they are easy to remember and help speed up development!
Something went wrong with that request. Please try again.