Skip to content
Newer
Older
100644 568 lines (494 sloc) 13.2 KB
9595725 update copyrights to 2011
Laurent Sansonetti authored
1 /*
2 * This file is covered by the Ruby license. See COPYING for more details.
3 *
4 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
5 * Copyright (C) 2001-2003 Akinori MUSHA
6 */
9c1d230 committing experimental branch content
Laurent Sansonetti authored
7
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
8 #include "macruby_internal.h"
301b43b ported to rb_objc_block_call() + misc cleanup
Laurent Sansonetti authored
9 #include "id.h"
81232c2 refactor duplicated code
Laurent Sansonetti authored
10 #include "ruby/node.h"
11 #include "vm.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
12
13 /*
76080c7 @Watson1978 update rdoc
Watson1978 authored
14 * Document-class: Enumerator
9c1d230 committing experimental branch content
Laurent Sansonetti authored
15 *
16 * A class which provides a method `each' to be used as an Enumerable
17 * object.
76080c7 @Watson1978 update rdoc
Watson1978 authored
18 *
19 * An enumerator can be created by following methods.
20 * - Kernel#to_enum
21 * - Kernel#enum_for
22 * - Enumerator.new
23 *
24 * Also, most iteration methods without a block returns an enumerator.
25 * For example, Array#map returns an enumerator if a block is not given.
26 * The enumerator has the with_index method.
27 * So ary.map.with_index works as follows.
28 *
29 * p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
30 * #=> ["0:foo", "1:bar", "2:baz"]
31 *
32 * An enumerator object can be used as an external iterator.
33 * I.e. Enumerator#next returns the next value of the iterator.
34 * Enumerator#next raises StopIteration at end.
35 *
36 * e = [1,2,3].each # returns an enumerator object.
37 * p e.next #=> 1
38 * p e.next #=> 2
39 * p e.next #=> 3
40 * p e.next #raises StopIteration
41 *
42 * An external iterator can be used to implement an internal iterator as follows.
43 *
44 * def ext_each(e)
45 * while true
46 * begin
47 * vs = e.next_values
48 * rescue StopIteration
49 * return $!.result
50 * end
51 * y = yield(*vs)
52 * e.feed y
53 * end
54 * end
55 *
56 * o = Object.new
57 * def o.each
58 * p yield
59 * p yield(1)
60 * p yield(1, 2)
61 * 3
62 * end
63 *
64 * # use o.each as an internal iterator directly.
65 * p o.each {|*x| p x; [:b, *x] }
66 * #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
67 *
68 * # convert o.each to an external iterator for
69 * # implementing an internal iterator.
70 * p ext_each(o.to_enum) {|*x| p x; [:b, *x] }
71 * #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
72 *
9c1d230 committing experimental branch content
Laurent Sansonetti authored
73 */
74 VALUE rb_cEnumerator;
75 static VALUE sym_each;
76
77 VALUE rb_eStopIteration;
78
79 struct enumerator {
80 VALUE obj;
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
81 SEL sel;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
82 VALUE args;
83 VALUE fib;
84 VALUE dst;
85 VALUE no_next;
86 };
87
88 static struct enumerator *
89 enumerator_ptr(VALUE obj)
90 {
91 struct enumerator *ptr;
92
93 Data_Get_Struct(obj, struct enumerator, ptr);
94 #if 0
95 if (RDATA(obj)->dmark != enumerator_mark) {
96 rb_raise(rb_eTypeError,
97 "wrong argument type %s (expected %s)",
98 rb_obj_classname(obj), rb_class2name(rb_cEnumerator));
99 }
100 #endif
de68086 @Watson1978 Properly detect if the object is initialized and raise error when app…
Watson1978 authored
101 if (!ptr || ptr->obj == Qundef) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
102 rb_raise(rb_eArgError, "uninitialized enumerator");
103 }
104 return ptr;
105 }
106
107 /*
108 * call-seq:
109 * obj.to_enum(method = :each, *args)
110 * obj.enum_for(method = :each, *args)
111 *
76080c7 @Watson1978 update rdoc
Watson1978 authored
112 * Returns Enumerator.new(self, method, *args).
9c1d230 committing experimental branch content
Laurent Sansonetti authored
113 *
114 * e.g.:
115 *
116 * str = "xyz"
117 *
118 * enum = str.enum_for(:each_byte)
119 * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
120 *
121 * # protects an array from being modified
122 * a = [1, 2, 3]
123 * some_method(a.to_enum)
124 *
125 */
126 static VALUE
127 obj_to_enum(VALUE obj, SEL sel, int argc, VALUE *argv)
128 {
129 VALUE meth = sym_each;
130
131 if (argc > 0) {
132 --argc;
133 meth = *argv++;
134 }
c6a0341 Kernel#to_enum: implemented
Laurent Sansonetti authored
135
e1960f6 Make sure #to_enum verify param is a symbol
Thibault Martin-Lagardette authored
136 ID meth_id = rb_to_id(meth);
81232c2 refactor duplicated code
Laurent Sansonetti authored
137 SEL enum_sel = rb_vm_id_to_sel(meth_id, argc);
c6a0341 Kernel#to_enum: implemented
Laurent Sansonetti authored
138 return rb_enumeratorize(obj, enum_sel, argc, argv);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
139 }
140
141 static VALUE
5b94e0e @Watson1978 enumerator_allocate() needs sel argument because "alloc" method is de…
Watson1978 authored
142 enumerator_allocate(VALUE klass, SEL sel)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
143 {
144 struct enumerator *ptr;
de68086 @Watson1978 Properly detect if the object is initialized and raise error when app…
Watson1978 authored
145 VALUE enum_obj;
146
147 enum_obj = Data_Make_Struct(klass, struct enumerator,
148 NULL, NULL, ptr);
149 ptr->obj = Qundef;
150
151 return enum_obj;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
152 }
153
154 static VALUE
155 enumerator_each_i(VALUE v, VALUE enum_obj, int argc, VALUE *argv)
156 {
157 return rb_yield_values2(argc, argv);
158 }
159
160 static VALUE
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
161 enumerator_init(VALUE enum_obj, VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
162 {
de68086 @Watson1978 Properly detect if the object is initialized and raise error when app…
Watson1978 authored
163 struct enumerator *ptr;
164
165 Data_Get_Struct(enum_obj, struct enumerator, ptr);
166
167 if (!ptr) {
168 rb_raise(rb_eArgError, "unallocated enumerator");
169 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
170
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
171 GC_WB(&ptr->obj, obj);
172 ptr->sel = sel;
173 if (argc > 0) {
174 GC_WB(&ptr->args, rb_ary_new4(argc, argv));
175 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
176 ptr->fib = 0;
177 ptr->dst = Qnil;
178 ptr->no_next = Qfalse;
179
180 return enum_obj;
181 }
182
183 /*
184 * call-seq:
76080c7 @Watson1978 update rdoc
Watson1978 authored
185 * Enumerator.new(obj, method = :each, *args)
186 * Enumerator.new { |y| ... }
187 *
188 * Creates a new Enumerator object, which is to be used as an
189 * Enumerable object iterating in a given way.
190 *
191 * In the first form, a generated Enumerator iterates over the given
192 * object using the given method with the given arguments passed.
193 * Use of this form is discouraged. Use Kernel#enum_for(), alias
194 * to_enum, instead.
195 *
196 * e = Enumerator.new(ObjectSpace, :each_object)
197 * #-> ObjectSpace.enum_for(:each_object)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
198 *
76080c7 @Watson1978 update rdoc
Watson1978 authored
199 * e.select { |obj| obj.is_a?(Class) } #=> array of all classes
9c1d230 committing experimental branch content
Laurent Sansonetti authored
200 *
76080c7 @Watson1978 update rdoc
Watson1978 authored
201 * In the second form, iteration is defined by the given block, in
202 * which a "yielder" object given as block parameter can be used to
203 * yield a value by calling the +yield+ method, alias +<<+.
204 *
205 * fib = Enumerator.new { |y|
206 * a = b = 1
207 * loop {
208 * y << a
209 * a, b = b, a + b
210 * }
211 * }
212 *
213 * p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
9c1d230 committing experimental branch content
Laurent Sansonetti authored
214 */
215 static VALUE
216 enumerator_initialize(VALUE obj, SEL sel, int argc, VALUE *argv)
217 {
218 VALUE recv, meth = sym_each;
219
220 if (argc == 0)
221 rb_raise(rb_eArgError, "wrong number of argument (0 for 1)");
222 recv = *argv++;
223 if (--argc) {
224 meth = *argv++;
225 --argc;
226 }
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
227 ID meth_id = rb_to_id(meth);
81232c2 refactor duplicated code
Laurent Sansonetti authored
228 SEL meth_sel = rb_vm_id_to_sel(meth_id, argc);
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
229 return enumerator_init(obj, recv, meth_sel, argc, argv);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
230 }
231
232 /* :nodoc: */
233 static VALUE
234 enumerator_init_copy(VALUE obj, SEL sel, VALUE orig)
235 {
236 struct enumerator *ptr0, *ptr1;
237
238 ptr0 = enumerator_ptr(orig);
239 if (ptr0->fib) {
240 /* Fibers cannot be copied */
241 rb_raise(rb_eTypeError, "can't copy execution context");
242 }
de68086 @Watson1978 Properly detect if the object is initialized and raise error when app…
Watson1978 authored
243
244 Data_Get_Struct(obj, struct enumerator, ptr1);
245
246 if (!ptr1) {
247 rb_raise(rb_eArgError, "unallocated enumerator");
248 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
249
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
250 GC_WB(&ptr1->obj, ptr0->obj);
251 ptr1->sel = ptr0->sel;
252 if (ptr0->args != 0) {
253 GC_WB(&ptr1->args, ptr0->args);
254 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
255 ptr1->fib = 0;
256
257 return obj;
258 }
259
260 VALUE
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
261 rb_enumeratorize(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
262 {
5b94e0e @Watson1978 enumerator_allocate() needs sel argument because "alloc" method is de…
Watson1978 authored
263 return enumerator_init(enumerator_allocate(rb_cEnumerator, 0), obj, sel,
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
264 argc, argv);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
265 }
266
267 static VALUE
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
268 enumerator_block_call(VALUE obj, VALUE (*func)(ANYARGS), VALUE arg)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
269 {
270 struct enumerator *e;
271 int argc = 0;
272 const VALUE *argv = 0;
273
274 e = enumerator_ptr(obj);
a6a914f implemented implicit enumeratorization
Laurent Sansonetti authored
275 if (e->args != 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
276 argc = RARRAY_LEN(e->args);
277 argv = RARRAY_PTR(e->args);
278 }
70ea0b5 per-vm method cache + misc fixes/improvements
Laurent Sansonetti authored
279 return rb_objc_block_call(e->obj, e->sel, argc, (VALUE *)argv,
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
280 func, arg);
281 }
282
283 /*
284 * call-seq:
285 * enum.each {...}
286 *
287 * Iterates the given block using the object and the method specified
288 * in the first place. If no block is given, returns self.
289 *
290 */
291 static VALUE
292 enumerator_each(VALUE obj, SEL sel)
293 {
294 if (!rb_block_given_p()) {
295 return obj;
296 }
297 return enumerator_block_call(obj, enumerator_each_i, obj);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
298 }
299
300 static VALUE
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
301 enumerator_with_index_i(VALUE val, VALUE m, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
302 {
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
303 VALUE idx;
304 VALUE *memo = (VALUE *)m;
305
306 idx = INT2FIX(*memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
307 ++*memo;
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
308
309 if (argc <= 1)
310 return rb_yield_values(2, val, idx);
311
312 return rb_yield_values(2, rb_ary_new4(argc, argv), idx);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
313 }
314
315 /*
316 * call-seq:
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
317 * e.with_index(offset = 0) {|(*args), idx| ... }
76080c7 @Watson1978 update rdoc
Watson1978 authored
318 * e.with_index(offset = 0)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
319 *
76080c7 @Watson1978 update rdoc
Watson1978 authored
320 * Iterates the given block for each element with an index, which
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
321 * starts from +offset+. If no block is given, returns an enumerator.
9c1d230 committing experimental branch content
Laurent Sansonetti authored
322 *
323 */
324 static VALUE
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
325 enumerator_with_index(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
326 {
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
327 VALUE memo;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
328
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
329 rb_scan_args(argc, argv, "01", &memo);
330 RETURN_ENUMERATOR(obj, argc, argv);
331 memo = NIL_P(memo) ? 0 : (VALUE)NUM2LONG(memo);
332 return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)&memo);
333 }
334
335 /*
336 * call-seq:
337 * e.each_with_index {|(*args), idx| ... }
338 * e.each_with_index
339 *
76080c7 @Watson1978 update rdoc
Watson1978 authored
340 * Same as Enumerator#with_index, except each_with_index does not
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
341 * receive an offset argument.
342 *
343 */
344 static VALUE
345 enumerator_each_with_index(VALUE obj, SEL sel)
346 {
347 return enumerator_with_index(obj, sel, 0, NULL);
348 }
349
350 static VALUE
351 enumerator_with_object_i(VALUE val, VALUE memo, int argc, VALUE *argv)
352 {
353 if (argc <= 1) {
354 return rb_yield_values(2, val, memo);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
355 }
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
356
357 return rb_yield_values(2, rb_ary_new4(argc, argv), memo);
358 }
359
360 /*
361 * call-seq:
362 * e.with_object(obj) {|(*args), memo_obj| ... }
363 * e.with_object(obj)
364 *
365 * Iterates the given block for each element with an arbitrary
366 * object given, and returns the initially given object.
367 *
368 * If no block is given, returns an enumerator.
369 *
370 */
371 static VALUE
372 enumerator_with_object(VALUE obj, SEL sel, VALUE memo)
373 {
374 RETURN_ENUMERATOR(obj, 1, &memo);
375 enumerator_block_call(obj, enumerator_with_object_i, memo);
376 return memo;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
377 }
378
379 #if 0
380 static VALUE
381 next_ii(VALUE i, VALUE obj, int argc, VALUE *argv)
382 {
383 rb_fiber_yield(argc, argv);
384 return Qnil;
385 }
386
387 static VALUE
388 next_i(VALUE curr, VALUE obj)
389 {
390 struct enumerator *e = enumerator_ptr(obj);
391 VALUE rnil = Qnil;
392
393 rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
394 e->no_next = Qtrue;
395 return rb_fiber_yield(1, &rnil);
396 }
397
398 static void
399 next_init(VALUE obj, struct enumerator *e)
400 {
401 VALUE curr = rb_fiber_current();
402 e->dst = curr;
403 e->fib = rb_fiber_new(next_i, obj);
404 }
405 #endif
406
407 /*
408 * call-seq:
76080c7 @Watson1978 update rdoc
Watson1978 authored
409 * e.next -> object
9c1d230 committing experimental branch content
Laurent Sansonetti authored
410 *
411 * Returns the next object in the enumerator, and move the internal
76080c7 @Watson1978 update rdoc
Watson1978 authored
412 * position forward. When the position reached at the end, StopIteration
413 * is raised.
414 *
415 * a = [1,2,3]
416 * e = a.to_enum
417 * p e.next #=> 1
418 * p e.next #=> 2
419 * p e.next #=> 3
420 * p e.next #raises StopIteration
9c1d230 committing experimental branch content
Laurent Sansonetti authored
421 *
422 * Note that enumeration sequence by next method does not affect other
423 * non-external enumeration methods, unless underlying iteration
424 * methods itself has side-effect, e.g. IO#each_line.
425 *
426 */
427
428 static VALUE
429 enumerator_next(VALUE obj, SEL sel)
430 {
431 // TODO
432 #if 0
433 struct enumerator *e = enumerator_ptr(obj);
434 VALUE curr, v;
435 curr = rb_fiber_current();
436
437 if (!e->fib || !rb_fiber_alive_p(e->fib)) {
438 next_init(obj, e);
439 }
440
441 v = rb_fiber_resume(e->fib, 1, &curr);
442 if (e->no_next) {
443 e->fib = 0;
444 e->dst = Qnil;
445 e->no_next = Qfalse;
446 rb_raise(rb_eStopIteration, "iteration reached at end");
447 }
448 return v;
449 #endif
450 return Qnil;
451 }
452
453 /*
454 * call-seq:
76080c7 @Watson1978 update rdoc
Watson1978 authored
455 * e.rewind -> e
9c1d230 committing experimental branch content
Laurent Sansonetti authored
456 *
457 * Rewinds the enumeration sequence by the next method.
76080c7 @Watson1978 update rdoc
Watson1978 authored
458 *
459 * If the enclosed object responds to a "rewind" method, it is called.
9c1d230 committing experimental branch content
Laurent Sansonetti authored
460 */
461
462 static VALUE
463 enumerator_rewind(VALUE obj, SEL sel)
464 {
465 struct enumerator *e = enumerator_ptr(obj);
466
467 e->fib = 0;
468 e->dst = Qnil;
469 e->no_next = Qfalse;
470 return obj;
471 }
472
1f07e4b @Watson1978 implement Enumerator#inspect
Watson1978 authored
473 static VALUE
474 inspect_enumerator(VALUE obj, VALUE dummy, int recur)
475 {
476 struct enumerator *e;
477 const char *cname;
478 VALUE eobj, str;
479 int tainted, untrusted;
480
481 Data_Get_Struct(obj, struct enumerator, e);
482
483 cname = rb_obj_classname(obj);
484
485 if (!e || e->obj == Qundef) {
486 return rb_sprintf("#<%s: uninitialized>", cname);
487 }
488
489 if (recur) {
490 str = rb_sprintf("#<%s: ...>", cname);
491 OBJ_TAINT(str);
492 return str;
493 }
494
495 eobj = e->obj;
496
497 tainted = OBJ_TAINTED(eobj);
498 untrusted = OBJ_UNTRUSTED(eobj);
499
500 /* (1..100).each_cons(2) => "#<Enumerator: 1..100:each_cons(2)>" */
501 str = rb_sprintf("#<%s: ", cname);
502 rb_str_concat(str, rb_inspect(eobj));
503 rb_str_buf_cat2(str, ":");
504 rb_str_buf_cat2(str, sel_getName(e->sel));
505
506 if (e->args) {
507 long argc = RARRAY_LEN(e->args);
508 VALUE *argv = (VALUE*)RARRAY_PTR(e->args);
509
510 rb_str_buf_cat2(str, "(");
511
512 while (argc--) {
513 VALUE arg = *argv++;
514
515 rb_str_concat(str, rb_inspect(arg));
516 rb_str_buf_cat2(str, argc > 0 ? ", " : ")");
517
518 if (OBJ_TAINTED(arg)) tainted = TRUE;
519 if (OBJ_UNTRUSTED(arg)) untrusted = TRUE;
520 }
521 }
522
523 rb_str_buf_cat2(str, ">");
524
525 if (tainted) OBJ_TAINT(str);
526 if (untrusted) OBJ_UNTRUST(str);
527 return str;
528 }
529
530 /*
531 * call-seq:
532 * e.inspect -> string
533 *
534 * Create a printable version of <i>e</i>.
535 */
536
537 static VALUE
538 enumerator_inspect(VALUE obj, SEL sel)
539 {
540 return rb_exec_recursive(inspect_enumerator, obj, 0);
541 }
542
9c1d230 committing experimental branch content
Laurent Sansonetti authored
543 void
544 Init_Enumerator(void)
545 {
546 rb_objc_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
547 rb_objc_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
548
fabdd03 Enumerator should be a top-level class
Laurent Sansonetti authored
549 rb_cEnumerator = rb_define_class("Enumerator", rb_cObject);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
550 rb_include_module(rb_cEnumerator, rb_mEnumerable);
551
552 rb_objc_define_method(*(VALUE *)rb_cEnumerator, "alloc", enumerator_allocate, 0);
553 rb_objc_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
554 rb_objc_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
555 rb_objc_define_method(rb_cEnumerator, "each", enumerator_each, 0);
6f5ed12 Improve core/enumerator pass rate
Thibault Martin-Lagardette authored
556 rb_objc_define_method(rb_cEnumerator, "each_with_index", enumerator_each_with_index, 0);
557 rb_objc_define_method(rb_cEnumerator, "each_with_object", enumerator_with_object, 1);
558 rb_objc_define_method(rb_cEnumerator, "with_index", enumerator_with_index, -1);
559 rb_objc_define_method(rb_cEnumerator, "with_object", enumerator_with_object, 1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
560 rb_objc_define_method(rb_cEnumerator, "next", enumerator_next, 0);
561 rb_objc_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
1f07e4b @Watson1978 implement Enumerator#inspect
Watson1978 authored
562 rb_objc_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
563
564 rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
565
566 sym_each = ID2SYM(rb_intern("each"));
567 }
Something went wrong with that request. Please try again.