[macruby-changes] [4066] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon May 10 19:28:32 PDT 2010


Revision: 4066
          http://trac.macosforge.org/projects/ruby/changeset/4066
Author:   martinlagardette at apple.com
Date:     2010-05-10 19:28:27 -0700 (Mon, 10 May 2010)
Log Message:
-----------
Improve core/array pass rate

 - Implement #rotate, #rotate!, #select!, #keep_if, #sort_by!
 - Fix various bugs to comply with the specs
 - Delete now-working specs

Modified Paths:
--------------
    MacRuby/trunk/NSArray.m
    MacRuby/trunk/array.c
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/join_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/multiply_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/sort_by_tags.txt

Removed Paths:
-------------
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/flatten_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/keep_if_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/rotate_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/select_tags.txt

Modified: MacRuby/trunk/NSArray.m
===================================================================
--- MacRuby/trunk/NSArray.m	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/NSArray.m	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1141,7 +1141,7 @@
 {
     VALUE *arg = (VALUE *)argp;
     if (recur) {
-	return rb_usascii_str_new2("[...]");
+	rb_raise(rb_eArgError, "recursive array join");
     }
     return rb_ary_join(arg[0], arg[1]);
 }

Modified: MacRuby/trunk/array.c
===================================================================
--- MacRuby/trunk/array.c	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/array.c	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1340,6 +1340,111 @@
     return rary_reverse_bang(rary_dup(ary, 0), 0);
 }
 
+static inline long
+rotate_count(long cnt, long len)
+{
+    return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len);
+}
+
+static void
+ary_reverse(VALUE ary, long pos1, long pos2)
+{
+    while (pos1 < pos2) {
+	VALUE elem = rary_elt(ary, pos1);
+	rary_elt_set(ary, pos1, rary_elt(ary, pos2));
+	rary_elt_set(ary, pos2, elem);
+	pos1++;
+	pos2--;
+    }
+}
+
+VALUE
+ary_rotate(VALUE ary, long cnt)
+{
+    rb_ary_modify(ary);
+    if (cnt != 0) {
+	long len = RARY(ary)->len;
+	if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) {
+	    --len;
+	    if (cnt < len) {
+		ary_reverse(ary, cnt, len);
+	    }
+	    if (--cnt > 0) {
+		ary_reverse(ary, 0, cnt);
+	    }
+	    if (len > 0) {
+		ary_reverse(ary, 0, len);
+	    }
+	    return ary;
+	}
+    }
+
+    return Qnil;
+}
+    
+/*
+ *  call-seq:
+ *     array.rotate!([cnt = 1]) -> array
+ *
+ *  Rotates _self_ in place so that the element at +cnt+ comes first,
+ *  and returns _self_.  If +cnt+ is negative then it rotates in
+ *  counter direction.
+ *
+ *     a = [ "a", "b", "c", "d" ]
+ *     a.rotate!        #=> ["b", "c", "d", "a"]
+ *     a                #=> ["b", "c", "d", "a"]
+ *     a.rotate!(2)     #=> ["d", "a", "b", "c"]
+ *     a.rotate!(-3)    #=> ["a", "b", "c", "d"]
+ */
+
+static VALUE
+rary_rotate_bang(VALUE ary, SEL sel, int argc, VALUE *argv)
+{
+    VALUE n;
+    long cnt = 1;
+
+    rb_scan_args(argc, argv, "01", &n);
+    if (!NIL_P(n)) {
+	cnt = NUM2LONG(n);
+    }
+    ary_rotate(ary, cnt);
+    return ary;
+}
+
+/*
+ *  call-seq:
+ *     array.rotate([n = 1]) -> an_array
+ *
+ *  Returns new array by rotating _self_, whose first element is the
+ *  element at +cnt+ in _self_.  If +cnt+ is negative then it rotates
+ *  in counter direction.
+ *
+ *     a = [ "a", "b", "c", "d" ]
+ *     a.rotate         #=> ["b", "c", "d", "a"]
+ *     a                #=> ["a", "b", "c", "d"]
+ *     a.rotate(2)      #=> ["c", "d", "a", "b"]
+ *     a.rotate(-3)     #=> ["b", "c", "d", "a"]
+ */
+
+static VALUE
+rary_rotate(VALUE ary, SEL sel, int argc, VALUE *argv)
+{
+    VALUE rotated;
+    VALUE n;
+    long cnt = 1;
+
+    rb_scan_args(argc, argv, "01", &n);
+    if (!NIL_P(n)) {
+	cnt = NUM2LONG(n);
+    }
+
+    rotated = rary_dup(ary, 0);
+    if (RARY(ary)->len > 0) {
+	ary_rotate(rotated, cnt);
+    }
+    return rotated;
+}
+
 static int
 sort_1(void *dummy, const void *ap, const void *bp)
 {
@@ -1474,6 +1579,33 @@
     return sort_bang(ary, true);
 }
 
+static VALUE
+sort_by_i(VALUE i)
+{
+    return rb_yield(i);
+}
+
+/*
+ *  call-seq:
+ *     array.sort_by! {| obj | block }    -> array
+ *
+ *  Sorts <i>array</i> in place using a set of keys generated by mapping the
+ *  values in <i>array</i> through the given block.
+ */
+
+static VALUE
+rary_sort_by_bang(VALUE ary, SEL sel)
+{
+    VALUE sorted;
+
+    RETURN_ENUMERATOR(ary, 0, 0);
+    rb_ary_modify(ary);
+    sorted = rb_objc_block_call(ary, sel_registerName("sort_by"), NULL, 0, 0,
+	sort_by_i, 0);
+    rb_ary_replace(ary, sorted);
+    return ary;
+}
+
 /* 
  *  call-seq:
  *     array.collect! {|item| block }   ->   array
@@ -1613,6 +1745,64 @@
 
 /*
  *  call-seq:
+ *     array.select! {|item| block } -> an_array
+ *
+ *  Invokes the block passing in successive elements from
+ *  <i>array</i>, deleting elements for which the block returns a
+ *  false value.  but returns <code>nil</code> if no changes were
+ *  made.  Also see <code>Array#keep_if</code>
+ */
+
+static VALUE
+rary_select_bang(VALUE ary, SEL sel)
+{
+    long i1, i2;
+
+    RETURN_ENUMERATOR(ary, 0, 0);
+    rb_ary_modify(ary);
+    for (i1 = i2 = 0; i1 < RARY(ary)->len; i1++) {
+	VALUE v = rary_elt(ary, i1);
+	VALUE test = RTEST(rb_yield(v));
+	RETURN_IF_BROKEN();
+	if (!RTEST(test)) {
+	    continue;
+	}
+	if (i1 != i2) {
+	    rb_ary_store(ary, i2, v);
+	}
+	i2++;
+    }
+
+    if (RARY(ary)->len == i2) {
+	return Qnil;
+    }
+    if (i2 < RARY(ary)->len) {
+	RARY(ary)->len = i2;
+    }
+    return ary;
+}
+
+/*
+ *  call-seq:
+ *     array.keep_if {|item| block } -> an_array
+ *
+ *  Deletes every element of <i>self</i> for which <i>block</i> evaluates
+ *  to <code>false</code>.
+ *
+ *     a = %w{ a b c d e f }
+ *     a.keep_if {|v| v =~ /[aeiou]/}   #=> ["a", "e"]
+ */
+
+static VALUE
+rary_keep_if(VALUE ary, SEL sel)
+{
+    RETURN_ENUMERATOR(ary, 0, 0);
+    rary_select_bang(ary, 0);
+    return ary;
+}
+
+/*
+ *  call-seq:
  *     array.delete(obj)            -> obj or nil 
  *     array.delete(obj) { block }  -> obj or nil
  *  
@@ -1746,15 +1936,24 @@
 	pos = NUM2LONG(arg1);
 	len = NUM2LONG(arg2);
 delete_pos_len:
+	if (len < 0) {
+	    return Qnil;
+	}
 	if (pos < 0) {
 	    pos = alen + pos;
 	    if (pos < 0) {
 		return Qnil;
 	    }
 	}
+	else if (alen < pos) {
+	    return Qnil;
+	}
 	if (alen < len || alen < pos + len) {
 	    len = alen - pos;
 	}
+	if (len == 0) {
+	    return rb_ary_new2(0);
+	}
 	arg2 = rary_subseq(ary, pos, len);
 	rary_splice(ary, pos, len, Qundef);
 	return arg2;
@@ -2783,7 +2982,7 @@
 	level = NUM2INT(lv);
     }
     if (level == 0) {
-	return ary;
+	return Qnil;
     }
 
     result = flatten(ary, level, &mod);
@@ -2825,7 +3024,7 @@
 	level = NUM2INT(lv);
     }
     if (level == 0) {
-	return ary;
+	return rary_dup(ary, 0);
     }
 
     result = flatten(ary, level, &mod);
@@ -3525,13 +3724,18 @@
     rb_objc_define_method(rb_cRubyArray, "rindex", rary_rindex, -1);
     rb_objc_define_method(rb_cRubyArray, "reverse", rary_reverse, 0);
     rb_objc_define_method(rb_cRubyArray, "reverse!", rary_reverse_bang, 0);
+    rb_objc_define_method(rb_cRubyArray, "rotate", rary_rotate, -1);
+    rb_objc_define_method(rb_cRubyArray, "rotate!", rary_rotate_bang, -1);
     rb_objc_define_method(rb_cRubyArray, "sort", rary_sort, 0);
     rb_objc_define_method(rb_cRubyArray, "sort!", rary_sort_bang, 0);
+    rb_objc_define_method(rb_cRubyArray, "sort_by!", rary_sort_by_bang, 0);
     rb_objc_define_method(rb_cRubyArray, "collect", rary_collect, 0);
     rb_objc_define_method(rb_cRubyArray, "collect!", rary_collect_bang, 0);
     rb_objc_define_method(rb_cRubyArray, "map", rary_collect, 0);
     rb_objc_define_method(rb_cRubyArray, "map!", rary_collect_bang, 0);
     rb_objc_define_method(rb_cRubyArray, "select", rary_select, 0);
+    rb_objc_define_method(rb_cRubyArray, "select!", rary_select_bang, 0);
+    rb_objc_define_method(rb_cRubyArray, "keep_if", rary_keep_if, 0);
     rb_objc_define_method(rb_cRubyArray, "values_at", rary_values_at, -1);
     rb_objc_define_method(rb_cRubyArray, "delete", rary_delete, 1);
     rb_objc_define_method(rb_cRubyArray, "delete_at", rary_delete_at, 1);

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/array/flatten_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/flatten_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/flatten_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,2 +0,0 @@
-fails:Array#flatten! returns nil when the level of recursion is 0
-fails:Array#flatten returns dup when the level of recursion is 0

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/array/join_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/join_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/join_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,2 +1 @@
-fails:Array#join raises an ArgumentError when the Array is recursive
 fails:Array#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/array/keep_if_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/keep_if_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/keep_if_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,3 +0,0 @@
-fails:Array#keep_if returns the same array if no changes were made
-fails:Array#keep_if deletes elements for which the block returns a false value
-fails:Array#keep_if returns an enumerator if no block is given

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/array/multiply_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/multiply_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/multiply_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,2 +1 @@
-fails:Array#* with a string raises an ArgumentError when the Array is recursive
 fails:Array#* with a string returns a string formed by concatenating each element.to_str separated by separator without trailing separator

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/array/rotate_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/rotate_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/rotate_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,9 +0,0 @@
-fails:Array#rotate returns a copy of the array whose first n elements is moved to the last
-fails:Array#rotate returns a copy of the array when the length is one
-fails:Array#rotate returns an empty array when self is empty
-fails:Array#rotate does not return self
-fails:Array#rotate returns subclass instance for Array subclasses
-fails:Array#rotate! moves the first n elements to the last and returns self
-fails:Array#rotate! does nothing and returns self when the length is zero or one
-fails:Array#rotate! returns self
-fails:Array#rotate! raises a RuntimeError on a frozen array

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/array/select_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/select_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/select_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,3 +0,0 @@
-fails:Array#select! returns nil if no changes were made in the array
-fails:Array#select! deletes elements for which the block returns a false value
-fails:Array#select! returns an enumerator if no block is given

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/array/sort_by_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/sort_by_tags.txt	2010-05-11 02:06:36 UTC (rev 4065)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/sort_by_tags.txt	2010-05-11 02:28:27 UTC (rev 4066)
@@ -1,6 +1,2 @@
 fails:Array#sort_by! sorts array in place by passing each element to the given block
-fails:Array#sort_by! returns an Enumerator if not given a block
-fails:Array#sort_by! completes when supplied a block that always returns the same result
-fails:Array#sort_by! raises a RuntimeError on a frozen array
 fails:Array#sort_by! returns the specified value when it would break in the given block
-fails:Array#sort_by! makes some modification even if finished sorting when it would break in the given block
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100510/38c889b4/attachment-0001.html>


More information about the macruby-changes mailing list