Skip to content
Newer
Older
100644 428 lines (383 sloc) 10.8 KB
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
1 /*
2 * MacRuby extensions to NSString.
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored Apr 22, 2012
3 *
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored Apr 22, 2012
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
9595725 update copyrights to 2011
Laurent Sansonetti authored Jan 15, 2011
7 * Copyright (C) 2010-2011, Apple Inc. All rights reserved.
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
8 */
9
10 #import <Foundation/Foundation.h>
11
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored Jan 8, 2011
12 #include "macruby_internal.h"
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
13 #include "ruby/node.h"
14 #include "objc.h"
15 #include "vm.h"
16 #include "encoding.h"
17
18 VALUE rb_cString;
19 VALUE rb_cNSString;
20 VALUE rb_cNSMutableString;
21
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
22 // Some NSString instances actually do not even respond to mutable methods.
23 // So one way to know is to check if the setString: method exists.
24 #define CHECK_MUTABLE(obj) \
25 do { \
26 if (![obj respondsToSelector:@selector(setString:)]) { \
27 rb_raise(rb_eRuntimeError, \
28 "can't modify frozen/immutable string"); \
29 } \
30 } \
31 while (0)
32
33 // If a given mutable operation raises an NSException error,
34 // it is likely that the object is not mutable.
35 #define TRY_MOP(code) \
36 @try { \
37 code; \
38 } \
39 @catch(NSException *exc) { \
40 rb_raise(rb_eRuntimeError, "can't modify frozen/immutable string"); \
41 }
42
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
43 static inline VALUE
07bbd32 better to_str()
Laurent Sansonetti authored Apr 7, 2010
44 to_str(VALUE str)
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
45 {
07bbd32 better to_str()
Laurent Sansonetti authored Apr 7, 2010
46 switch (TYPE(str)) {
47 case T_STRING:
48 return str;
49 case T_SYMBOL:
50 return rb_sym_to_s(str);
51 }
52 return rb_convert_type(str, T_STRING, "String", "to_str");
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
53 }
54
55 static id
56 nsstr_dup(id rcv, SEL sel)
57 {
3146804 @Watson1978 Symbol#dup raises a TypeError
Watson1978 authored Jun 22, 2012
58 if (TYPE(rcv) == T_SYMBOL) {
59 rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname((VALUE)rcv));
60 }
61
3e200e8 make NSString#dup return a RubyString
Laurent Sansonetti authored Jun 6, 2011
62 id dup = (id)str_new_from_cfstring((CFStringRef)rcv);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
63 if (OBJ_TAINTED(rcv)) {
64 OBJ_TAINT(dup);
65 }
66 return dup;
67 }
68
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
69 static id
70 nsstr_to_s(id rcv, SEL sel)
71 {
72 return rcv;
73 }
74
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
75 static id
76 nsstr_replace(id rcv, SEL sel, VALUE other)
77 {
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
78 CHECK_MUTABLE(rcv);
79 TRY_MOP([rcv setString:(id)to_str(other)]);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
80 return rcv;
81 }
82
83 static id
84 nsstr_clear(id rcv, SEL sel)
85 {
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
86 CHECK_MUTABLE(rcv);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
87 const long len = [rcv length];
88 if (len > 0) {
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
89 TRY_MOP([rcv deleteCharactersInRange:NSMakeRange(0, len)]);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
90 }
91 return rcv;
92 }
93
94 static VALUE
95 nsstr_encoding(id rcv, SEL sel)
96 {
97 // All NSStrings are Unicode, so let's return UTF-8.
98 return (VALUE)rb_encodings[ENCODING_UTF8];
99 }
100
101 static VALUE
102 nsstr_length(id rcv, SEL sel)
103 {
104 return LONG2NUM([rcv length]);
105 }
106
107 static VALUE
108 nsstr_empty(id rcv, SEL sel)
109 {
110 return [rcv length] == 0 ? Qtrue : Qfalse;
111 }
112
113 static id
114 nsstr_concat(id rcv, SEL sel, VALUE other)
115 {
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
116 CHECK_MUTABLE(rcv);
117 TRY_MOP([rcv appendString:(id)to_str(other)]);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
118 return rcv;
119 }
120
121 static id
122 nsstr_plus(id rcv, SEL sel, VALUE other)
123 {
124 id newstr = [NSMutableString new];
125 [newstr appendString:rcv];
126 [newstr appendString:(id)to_str(other)];
127 return newstr;
128 }
129
130 static VALUE
131 nsstr_equal(id rcv, SEL sel, VALUE other)
132 {
68eebf6 fix a bug in NSString#== where an exception would occur if the operan…
Laurent Sansonetti authored May 6, 2010
133 if (rcv == (id)other) {
134 return Qtrue;
135 }
136 if (TYPE(other) != T_STRING) {
137 if (!rb_respond_to(other, rb_intern("to_str"))) {
138 return Qfalse;
139 }
140 return rb_equal(other, (VALUE)rcv);
141 }
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
142 return [rcv isEqualToString:(id)to_str(other)] ? Qtrue : Qfalse;
143 }
144
145 static VALUE
146 nsstr_cmp(id rcv, SEL sel, VALUE other)
147 {
148 int ret = [rcv compare:(id)to_str(other)];
149 if (ret > 0) {
150 ret = 1;
151 }
152 else if (ret < 0) {
153 ret = -1;
154 }
155 return INT2FIX(ret);
156 }
157
158 static VALUE
159 nsstr_casecmp(id rcv, SEL sel, VALUE other)
160 {
161 int ret = [rcv compare:(id)to_str(other) options:NSCaseInsensitiveSearch];
162 if (ret > 0) {
163 ret = 1;
164 }
165 else if (ret < 0) {
166 ret = -1;
167 }
168 return INT2FIX(ret);
169 }
170
171 static VALUE
172 nsstr_include(id rcv, SEL sel, VALUE other)
173 {
174 NSRange range = [rcv rangeOfString:(id)to_str(other)];
175 return range.location == NSNotFound ? Qfalse : Qtrue;
176 }
177
178 static VALUE
179 nsstr_to_rstr(id nsstr)
180 {
181 const long len = [nsstr length];
182 if (len == 0) {
183 return rb_str_new(NULL, 0);
184 }
185
186 unichar *buf = (unichar *)malloc(sizeof(unichar) * len);
187 [nsstr getCharacters:buf range:NSMakeRange(0, len)];
188 VALUE rstr = rb_unicode_str_new(buf, len);
189 free(buf);
190 return rstr;
191 }
192
193 static VALUE
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
194 nsstr_forward_m1(id rcv, SEL sel, int argc, VALUE *argv)
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
195 {
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored Jun 1, 2010
196 return rb_vm_call2(rb_vm_current_block(), nsstr_to_rstr(rcv), 0, sel, argc, argv);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
197 }
198
199 static VALUE
a2becd7 forgot the forwarder for arity 0
Laurent Sansonetti authored May 7, 2010
200 nsstr_forward_0(id rcv, SEL sel)
201 {
202 return nsstr_forward_m1(rcv, sel, 0, NULL);
203 }
204
205 static VALUE
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
206 nsstr_forward_1(id rcv, SEL sel, VALUE arg1)
207 {
208 return nsstr_forward_m1(rcv, sel, 1, &arg1);
209 }
210
211 static VALUE
212 nsstr_forward_2(id rcv, SEL sel, VALUE arg1, VALUE arg2)
213 {
214 VALUE args[2] = {arg1, arg2};
215 return nsstr_forward_m1(rcv, sel, 2, args);
216 }
217
218 static VALUE
219 nsstr_forward_3(id rcv, SEL sel, VALUE arg1, VALUE arg2, VALUE arg3)
220 {
221 VALUE args[3] = {arg1, arg2, arg3};
222 return nsstr_forward_m1(rcv, sel, 3, args);
223 }
224
225 static VALUE
226 nsstr_forward_bang_m1(id rcv, SEL sel, int argc, VALUE *argv)
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
227 {
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
228 CHECK_MUTABLE(rcv);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
229 VALUE rcv_rstr = nsstr_to_rstr(rcv);
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored Jun 1, 2010
230 VALUE ret = rb_vm_call2(rb_vm_current_block(), rcv_rstr, 0, sel, argc, argv);
7d2f92b raising RuntimeError as in 0.5 in case we try to mutate a non-mutable…
Laurent Sansonetti authored May 3, 2010
231 TRY_MOP([rcv setString:(id)rcv_rstr]);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
232 return ret;
233 }
234
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
235 static VALUE
a2becd7 forgot the forwarder for arity 0
Laurent Sansonetti authored May 7, 2010
236 nsstr_forward_bang_0(id rcv, SEL sel)
237 {
238 return nsstr_forward_bang_m1(rcv, sel, 0, NULL);
239 }
240
241 static VALUE
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
242 nsstr_forward_bang_1(id rcv, SEL sel, VALUE arg1)
243 {
244 return nsstr_forward_bang_m1(rcv, sel, 1, &arg1);
245 }
246
247 static VALUE
248 nsstr_forward_bang_2(id rcv, SEL sel, VALUE arg1, VALUE arg2)
249 {
250 VALUE args[2] = {arg1, arg2};
251 return nsstr_forward_bang_m1(rcv, sel, 2, args);
252 }
253
254 static VALUE
255 nsstr_forward_bang_3(id rcv, SEL sel, VALUE arg1, VALUE arg2, VALUE arg3)
256 {
257 VALUE args[3] = {arg1, arg2, arg3};
258 return nsstr_forward_bang_m1(rcv, sel, 3, args);
259 }
260
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
261 void
a8bd277 Make Symbol NSCoding compliant
Thibault Martin-Lagardette authored Mar 25, 2010
262 rb_str_NSCoder_encode(void *coder, VALUE str, const char *key)
263 {
264 NSString *nskey = [NSString stringWithUTF8String:key];
265 [(NSCoder *)coder encodeObject:(NSString *)str forKey:nskey];
266 }
267
268 VALUE
269 rb_str_NSCoder_decode(void *coder, const char *key)
270 {
271 NSString *nskey = [NSString stringWithUTF8String:key];
272 return OC2RB([(NSCoder *)coder decodeObjectForKey:nskey]);
273 }
274
275 void
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
276 Init_NSString(void)
277 {
278 rb_cString = rb_cNSString;
279 rb_include_module(rb_cString, rb_mComparable);
280 rb_cNSMutableString = (VALUE)objc_getClass("NSMutableString");
281 assert(rb_cNSMutableString != 0);
282
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
283 rb_objc_define_method(rb_cString, "dup", nsstr_dup, 0);
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
284 rb_objc_define_method(rb_cString, "to_s", nsstr_to_s, 0);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
285 rb_objc_define_method(rb_cString, "to_str", nsstr_to_s, 0);
286 rb_objc_define_method(rb_cString, "replace", nsstr_replace, 1);
287 rb_objc_define_method(rb_cString, "clear", nsstr_clear, 0);
288 rb_objc_define_method(rb_cString, "encoding", nsstr_encoding, 0);
289 rb_objc_define_method(rb_cString, "size", nsstr_length, 0);
290 rb_objc_define_method(rb_cString, "empty?", nsstr_empty, 0);
291 rb_objc_define_method(rb_cString, "<<", nsstr_concat, 1);
292 rb_objc_define_method(rb_cString, "concat", nsstr_concat, 1);
293 rb_objc_define_method(rb_cString, "+", nsstr_plus, 1);
294 rb_objc_define_method(rb_cString, "==", nsstr_equal, 1);
295 rb_objc_define_method(rb_cString, "eql?", nsstr_equal, 1);
296 rb_objc_define_method(rb_cString, "<=>", nsstr_cmp, 1);
297 rb_objc_define_method(rb_cString, "casecmp", nsstr_casecmp, 1);
298 rb_objc_define_method(rb_cString, "include?", nsstr_include, 1);
299
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
300 #define pick_forwarder(arity, bang) \
a9fbfdb fix some clang/clang++ compilation warnings
Laurent Sansonetti authored Jun 21, 2010
301 (arity == -1 \
302 ? (bang \
303 ? (void *)nsstr_forward_bang_m1 : (void *)nsstr_forward_m1) \
304 : (arity == 0) \
305 ? (bang \
306 ? (void *)nsstr_forward_bang_0 : (void *)nsstr_forward_0) \
307 : (arity == 1) \
308 ? (bang \
309 ? (void *)nsstr_forward_bang_1 : (void *)nsstr_forward_1) \
310 : (arity == 2) \
311 ? (bang \
312 ? (void *)nsstr_forward_bang_2 : (void *)nsstr_forward_2) \
313 : (arity == 3) \
314 ? (bang \
315 ? (void *)nsstr_forward_bang_3 : (void *)nsstr_forward_3) \
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
316 : (abort(),NULL))
317
318 #define forward(msg, arity) \
319 rb_objc_define_method(rb_cString, msg, pick_forwarder(arity, false), arity)
320
321 #define forward_bang(msg, arity) \
322 rb_objc_define_method(rb_cString, msg, pick_forwarder(arity, true), arity)
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
323
324 // These methods are implemented as forwarders.
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
325 forward("[]", -1);
326 forward_bang("[]=", -1);
327 forward("slice", -1);
328 forward_bang("slice!", -1);
5616c1f Fix the number or args for some NSString forwarding methods
Thibault Martin-Lagardette authored Jul 13, 2010
329 forward_bang("insert", 2);
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
330 forward("index", -1);
331 forward("rindex", -1);
332 forward("+", 1);
333 forward("*", 1);
334 forward("%", 1);
335 forward("start_with?", -1);
336 forward("end_with?", -1);
337 forward("to_sym", 0);
338 forward("intern", 0);
339 forward("inspect", 0);
340 forward("dump", 0);
341 forward("match", -1);
342 forward("=~", 1);
343 forward("scan", 1);
344 forward("split", -1);
345 forward("to_i", -1);
346 forward("hex", 0);
347 forward("oct", 0);
348 forward("ord", 0);
349 forward("chr", 0);
350 forward("to_f", 0);
351 forward("chomp", -1);
352 forward_bang("chomp!", -1);
353 forward("chop", -1);
354 forward_bang("chop!", -1);
355 forward("sub", -1);
356 forward_bang("sub!", -1);
357 forward("gsub", -1);
358 forward_bang("gsub!", -1);
359 forward("downcase", 0);
360 forward_bang("downcase!", 0);
361 forward("upcase", 0);
362 forward_bang("upcase!", 0);
363 forward("swapcase", 0);
364 forward_bang("swapcase!", 0);
365 forward("capitalize", 0);
366 forward_bang("capitalize!", 0);
367 forward("ljust", -1);
368 forward("rjust", -1);
369 forward("center", -1);
5616c1f Fix the number or args for some NSString forwarding methods
Thibault Martin-Lagardette authored Jul 13, 2010
370 forward("strip", 0);
371 forward("lstrip", 0);
372 forward("rstrip", 0);
2fb9930 register the forwarders with the correct arity to avoid recursive dis…
Laurent Sansonetti authored May 6, 2010
373 forward_bang("strip!", 0);
374 forward_bang("lstrip!", 0);
375 forward_bang("rstrip!", 0);
376 forward("lines", -1);
377 forward("each_line", -1);
378 forward("chars", 0);
379 forward("each_char", 0);
380 forward("succ", 0);
381 forward_bang("succ!", 0);
382 forward("next", 0);
383 forward_bang("next!", 0);
384 forward("upto", -1);
385 forward("reverse", 0);
386 forward_bang("reverse!", 0);
387 forward("count", -1);
388 forward("delete", -1);
389 forward_bang("delete!", -1);
390 forward("squeeze", -1);
391 forward_bang("squeeze!", -1);
392 forward("tr", 2);
393 forward_bang("tr!", 2);
394 forward("tr_s", 2);
395 forward_bang("tr_s!", 2);
396 forward("sum", -1);
397 forward("partition", 1);
398 forward("rpartition", 1);
399 forward("crypt", 1);
31471bb more work on the NSString extensions, should be completed
Laurent Sansonetti authored Mar 24, 2010
400
401 #undef forward
402 #undef forward_bang
403
404 // These methods will not work on NSStrings.
405 rb_objc_define_method(rb_cString, "bytesize", rstr_only, 0);
406 rb_objc_define_method(rb_cString, "getbyte", rstr_only, 1);
407 rb_objc_define_method(rb_cString, "setbyte", rstr_only, 2);
408 rb_objc_define_method(rb_cString, "force_encoding", rstr_only, 1);
409 rb_objc_define_method(rb_cString, "valid_encoding?", rstr_only, 0);
410 rb_objc_define_method(rb_cString, "ascii_only?", rstr_only, 0);
411 rb_objc_define_method(rb_cString, "bytes", rstr_only, 0);
412 rb_objc_define_method(rb_cString, "each_byte", rstr_only, 0);
1bf9a2e ruby strings now respond to #to_data which returns an NSData object w…
Laurent Sansonetti authored Jun 2, 2010
413 rb_objc_define_method(rb_cString, "to_data", rstr_only, 0);
6a51dbd make sure #pointer won't work on NSStrings
Laurent Sansonetti authored Oct 8, 2010
414 rb_objc_define_method(rb_cString, "pointer", rstr_only, 0);
a4c0bd2 started NSNumber / NSString extensions
Laurent Sansonetti authored Mar 23, 2010
415 }
5819dc0 better RSTRING_{PTR,LEN] for pure NSStrings
Laurent Sansonetti authored Feb 9, 2011
416
417 const char *
418 nsstr_cstr(VALUE str)
419 {
420 return [(NSString *)str UTF8String];
421 }
422
423 long
424 nsstr_clen(VALUE str)
425 {
426 return [(NSString *)str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
427 }
Something went wrong with that request. Please try again.