[macruby-changes] [4075] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Tue May 11 17:05:42 PDT 2010
Revision: 4075
http://trac.macosforge.org/projects/ruby/changeset/4075
Author: martinlagardette at apple.com
Date: 2010-05-11 17:05:41 -0700 (Tue, 11 May 2010)
Log Message:
-----------
Improve core/enumerable pass rate
- Implement `#flat_map`, `#collect_concat`, `#each_entry`, `#each_slice`, `#each_cons`, `#each_with_object`
- Fix various enumerable methods
- Some syntax fixes
Modified Paths:
--------------
MacRuby/trunk/enum.c
Removed Paths:
-------------
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_concat_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_entry_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_with_object_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/flat_map_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/join_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/map_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/max_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/min_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/minmax_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/sort_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/take_tags.txt
MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/zip_tags.txt
Modified: MacRuby/trunk/enum.c
===================================================================
--- MacRuby/trunk/enum.c 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/enum.c 2010-05-12 00:05:41 UTC (rev 4075)
@@ -14,6 +14,7 @@
#include "ruby/util.h"
#include "vm.h"
#include "id.h"
+#include "array.h"
VALUE rb_mEnumerable;
static ID id_each, id_eqq, id_next, id_size;
@@ -395,8 +396,50 @@
return ary;
}
+static VALUE
+flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv)
+{
+ VALUE tmp;
+
+ i = enum_yield(argc, argv);
+ tmp = rb_check_array_type(i);
+
+ if (NIL_P(tmp)) {
+ rb_ary_push(ary, i);
+ }
+ else {
+ rb_ary_concat(ary, tmp);
+ }
+ return Qnil;
+}
+
/*
* call-seq:
+ * enum.flat_map {| obj | block } => array
+ * enum.collect_concat {| obj | block } => array
+ *
+ * Returns a new array with the concatenated results of running
+ * <em>block</em> once for every element in <i>enum</i>.
+ *
+ * [[1,2],[3,4]].flat_map {|i| i } #=> [1, 2, 3, 4]
+ *
+ */
+
+static VALUE
+enum_flat_map(VALUE obj, SEL sel)
+{
+ VALUE ary;
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ ary = rb_ary_new();
+ rb_objc_block_call(obj, selEach, cacheEach, 0, 0, flat_map_i, ary);
+
+ return ary;
+}
+
+/*
+ * call-seq:
* enum.to_a => array
* enum.entries => array
*
@@ -1445,8 +1488,193 @@
return obj;
}
+static VALUE
+each_val_i(VALUE i, VALUE p, int argc, VALUE *argv)
+{
+ ENUM_WANT_SVALUE();
+ rb_yield(i);
+ return Qnil;
+}
+/*
+ * call-seq:
+ * enum.each_entry {|obj| block} => enum
+ *
+ * Calls <i>block</i> once for each element in <i>self</i>, passing that
+ * element as a parameter, converting multiple values from yield to an
+ * array.
+ *
+ * class Foo
+ * include Enumerable
+ * def each
+ * yield 1
+ * yield 1,2
+ * end
+ * end
+ * Foo.new.each_entry{|o| print o, " -- "}
+ *
+ * produces:
+ *
+ * 1 -- [1, 2] --
+ */
+
static VALUE
+enum_each_entry(VALUE obj, SEL sel, int argc, VALUE *argv)
+{
+ RETURN_ENUMERATOR(obj, argc, argv);
+ rb_objc_block_call(obj, selEach, cacheEach, argc, argv, each_val_i, 0);
+ return obj;
+}
+
+static VALUE
+each_slice_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
+{
+ VALUE ary = memo[0];
+ VALUE v = Qnil;
+ long size = (long)memo[1];
+ ENUM_WANT_SVALUE();
+
+ rb_ary_push(ary, i);
+
+ if (RARRAY_LEN(ary) == size) {
+ v = rb_yield(ary);
+ memo[0] = rb_ary_new2(size);
+ }
+
+ return v;
+}
+
+/*
+ * call-seq:
+ * e.each_slice(n) {...}
+ * e.each_slice(n)
+ *
+ * Iterates the given block for each slice of <n> elements. If no
+ * block is given, returns an enumerator.
+ *
+ * e.g.:
+ * (1..10).each_slice(3) {|a| p a}
+ * # outputs below
+ * [1, 2, 3]
+ * [4, 5, 6]
+ * [7, 8, 9]
+ * [10]
+ *
+ */
+static VALUE
+enum_each_slice(VALUE obj, SEL sel, VALUE n)
+{
+ long size = NUM2LONG(n);
+ VALUE args[2], ary;
+
+ if (size <= 0) {
+ rb_raise(rb_eArgError, "invalid slice size");
+ }
+ RETURN_ENUMERATOR(obj, 1, &n);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
+
+ rb_objc_block_call(obj, selEach, cacheEach, 0, 0, each_slice_i, (VALUE)args);
+
+ ary = args[0];
+ if (RARRAY_LEN(ary) > 0) {
+ rb_yield(ary);
+ }
+
+ return Qnil;
+}
+
+static VALUE
+each_cons_i(VALUE i, VALUE *memo, int argc, VALUE *argv)
+{
+ VALUE ary = memo[0];
+ VALUE v = Qnil;
+ long size = (long)memo[1];
+ ENUM_WANT_SVALUE();
+
+ if (RARRAY_LEN(ary) == size) {
+ rb_ary_shift(ary);
+ }
+ rb_ary_push(ary, i);
+ if (RARRAY_LEN(ary) == size) {
+ v = rb_yield(rb_ary_dup(ary));
+ }
+ return v;
+}
+
+/*
+ * call-seq:
+ * each_cons(n) {...}
+ * each_cons(n)
+ *
+ * Iterates the given block for each array of consecutive <n>
+ * elements. If no block is given, returns an enumerator.
+ *
+ * e.g.:
+ * (1..10).each_cons(3) {|a| p a}
+ * # outputs below
+ * [1, 2, 3]
+ * [2, 3, 4]
+ * [3, 4, 5]
+ * [4, 5, 6]
+ * [5, 6, 7]
+ * [6, 7, 8]
+ * [7, 8, 9]
+ * [8, 9, 10]
+ *
+ */
+static VALUE
+enum_each_cons(VALUE obj, SEL sel, VALUE n)
+{
+ long size = NUM2LONG(n);
+ VALUE args[2];
+
+ if (size <= 0) {
+ rb_raise(rb_eArgError, "invalid size");
+ }
+ RETURN_ENUMERATOR(obj, 1, &n);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
+
+ rb_objc_block_call(obj, selEach, cacheEach, 0, 0, each_cons_i, (VALUE)args);
+
+ return Qnil;
+}
+
+static VALUE
+each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv)
+{
+ ENUM_WANT_SVALUE();
+ return rb_yield_values(2, i, memo);
+}
+
+/*
+ * call-seq:
+ * each_with_object(obj) {|(*args), memo_obj| ... }
+ * each_with_object(obj)
+ *
+ * Iterates the given block for each element with an arbitrary
+ * object given, and returns the initially given object.
+ *
+ * If no block is given, returns an enumerator.
+ *
+ * e.g.:
+ * evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
+ * # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+ *
+ */
+static VALUE
+enum_each_with_object(VALUE obj, SEL sel, VALUE memo)
+{
+ RETURN_ENUMERATOR(obj, 1, &memo);
+
+ rb_objc_block_call(obj, selEach, cacheEach, 0, 0,
+ each_with_object_i, (VALUE)memo);
+
+ return memo;
+}
+
+static VALUE
zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
{
volatile VALUE result = memo->u1.value;
@@ -1553,24 +1781,28 @@
ID conv;
NODE *memo;
VALUE result = Qnil;
+ VALUE args = rb_ary_new4(argc, argv);
int allary = Qtrue;
- for (i=0; i<argc; i++) {
- if (TYPE(argv[i]) != T_ARRAY) {
+ for (i = 0; i < argc; i++) {
+ VALUE ary = rb_check_array_type(argv[i]);
+ if (NIL_P(ary)) {
allary = Qfalse;
break;
}
+ rary_store(args, i, ary);
}
if (!allary) {
conv = rb_intern("to_enum");
- for (i=0; i<argc; i++) {
- argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
+ for (i = 0; i < argc; i++) {
+ VALUE res = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
+ rary_store(args, i, res);
}
}
if (!rb_block_given_p()) {
result = rb_ary_new();
}
- memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), 0);
+ memo = rb_node_newnode(NODE_MEMO, result, args, 0);
rb_objc_block_call(obj, selEach, cacheEach, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
@@ -1579,8 +1811,10 @@
static VALUE
take_i(VALUE i, VALUE *arg, int argc, VALUE *argv)
{
- if (arg[1]-- == 0) rb_iter_break();
rb_ary_push(arg[0], enum_values_pack(argc, argv));
+ if (--arg[1] == 0) {
+ rb_iter_break();
+ }
return Qnil;
}
@@ -1605,8 +1839,11 @@
rb_raise(rb_eArgError, "attempt to take negative size");
}
+ if (len == 0) {
+ return rb_ary_new2(0);
+ }
+ args[0] = rb_ary_new();
args[1] = len;
- args[0] = rb_ary_new();
rb_objc_block_call(obj, selEach, cacheEach, 0, 0, take_i, (VALUE)args);
return args[0];
}
@@ -1615,7 +1852,9 @@
static VALUE
take_while_i(VALUE i, VALUE *ary, int argc, VALUE *argv)
{
- if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
+ if (!RTEST(enum_yield(argc, argv))) {
+ rb_iter_break();
+ }
rb_ary_push(*ary, enum_values_pack(argc, argv));
return Qnil;
}
@@ -1823,6 +2062,8 @@
rb_objc_define_method(rb_mEnumerable, "reject", enum_reject, 0);
rb_objc_define_method(rb_mEnumerable, "collect", enum_collect, 0);
rb_objc_define_method(rb_mEnumerable, "map", enum_collect, 0);
+ rb_objc_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0);
+ rb_objc_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0);
rb_objc_define_method(rb_mEnumerable, "inject", enum_inject, -1);
rb_objc_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
rb_objc_define_method(rb_mEnumerable, "partition", enum_partition, 0);
@@ -1842,6 +2083,10 @@
rb_objc_define_method(rb_mEnumerable, "include?", enum_member, 1);
rb_objc_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1);
rb_objc_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
+ rb_objc_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1);
+ rb_objc_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
+ rb_objc_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
+ rb_objc_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
rb_objc_define_method(rb_mEnumerable, "zip", enum_zip, -1);
rb_objc_define_method(rb_mEnumerable, "take", enum_take, 1);
rb_objc_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_concat_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_concat_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_concat_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,4 +0,0 @@
-fails:Enumerable#collect_concat returns a new array with the results of passing each element to block, flattened one level
-fails:Enumerable#collect_concat skips elements that are empty Arrays
-fails:Enumerable#collect_concat calls to_ary but not to_a
-fails:Enumerable#collect_concat returns an enumerator when no block given
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/collect_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,2 +0,0 @@
-fails:Enumerable#collect with implicit to_proc [each(&obj) form] does not call obj.to_proc if obj is a lambda
-fails:Enumerable#collect with implicit to_proc [each(&obj) form] does not call obj.to_proc if obj is a Proc
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_entry_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_entry_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_entry_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,4 +0,0 @@
-fails:Enumerable#each_entry yields multiple arguments as an array
-fails:Enumerable#each_entry returns an enumerator if no block
-fails:Enumerable#each_entry raises an Argument error when extra arguments
-fails:Enumerable#each_entry passes extra arguments to #each
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_with_object_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_with_object_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/each_with_object_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,2 +0,0 @@
-fails:Enumerable#each_with_object passes each element and its argument to the block
-fails:Enumerable#each_with_object returns an enumerator if no block
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/flat_map_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/flat_map_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/flat_map_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,4 +0,0 @@
-fails:Enumerable#flat_map returns a new array with the results of passing each element to block, flattened one level
-fails:Enumerable#flat_map skips elements that are empty Arrays
-fails:Enumerable#flat_map calls to_ary but not to_a
-fails:Enumerable#flat_map returns an enumerator when no block given
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/join_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/join_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/join_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,10 +0,0 @@
-critical:Enumerable#join raises an ArgumentError when the Array is recursive
-fails:Enumerable#join returns an empty string if the Array is empty
-fails:Enumerable#join returns a string formed by concatenating each element.to_s separated by separator without trailing separator
-fails:Enumerable#join uses the same separator with nested arrays
-fails:Enumerable#join tries to convert the passed separator to a String using #to_str
-fails:Enumerable#join does not consider taint of either the array or the separator when the array is empty
-fails:Enumerable#join returns a string which would be infected with taint of the array, its elements or the separator when the array is not empty
-fails:Enumerable#join does not consider untrustworthiness of either the array or the separator when the array is empty
-fails:Enumerable#join returns a string which would be infected with untrustworthiness of the array, its elements or the separator when the array is not empty
-fails:Enumerable#join returns a string formed by concatenating each element.to_str separated by separator without trailing separator
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/map_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/map_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/map_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,2 +0,0 @@
-fails:Enumerable#map with implicit to_proc [each(&obj) form] does not call obj.to_proc if obj is a lambda
-fails:Enumerable#map with implicit to_proc [each(&obj) form] does not call obj.to_proc if obj is a Proc
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/max_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/max_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/max_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1 +0,0 @@
-critical:Enumerable#max raises a NoMethodError for elements without #<=>
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/min_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/min_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/min_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1 +0,0 @@
-critical:Enumerable#min raises a NoMethodError for elements without #<=>
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/minmax_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/minmax_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/minmax_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1 +0,0 @@
-critical:Enumerable#minmax raises a NoMethodError for elements without #<=>
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/sort_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/sort_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/sort_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1 +0,0 @@
-critical:Enumerable#sort raises a NoMethodError if elements do not define <=>
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/take_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/take_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/take_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1,5 +0,0 @@
-fails:Enumerable#take when passed an argument returns the first count elements if given a count
-fails:Enumerable#take when passed an argument returns an empty array when passed count == 0
-fails:Enumerable#take when passed an argument returns an array containing the first element when passed count == 1
-fails:Enumerable#take when passed an argument tries to convert the passed argument to an Integer using #to_int
-fails:Enumerable#take when passed an argument consumes only what is needed
Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/zip_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/zip_tags.txt 2010-05-11 23:56:20 UTC (rev 4074)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/enumerable/zip_tags.txt 2010-05-12 00:05:41 UTC (rev 4075)
@@ -1 +0,0 @@
-fails:Enumerable#zip converts arguments to arrays using #to_ary
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100511/b13c6bf7/attachment-0001.html>
More information about the macruby-changes
mailing list