Index: array.c =================================================================== --- array.c (revision 54477) +++ array.c (working copy) @@ -2948,10 +2948,51 @@ ary_resize_smaller(VALUE ary, long len) } } +static VALUE +rb_ary_delete_internal(VALUE ary, VALUE item, int *deleted) +{ + VALUE v = item; + long i1, i2; + + for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { + VALUE e = RARRAY_AREF(ary, i1); + + if (rb_equal(e, item)) { + v = e; + continue; + } + if (i1 != i2) { + rb_ary_store(ary, i2, e); + } + i2++; + } + + if (RARRAY_LEN(ary) == i2) { + if (deleted) *deleted = 0; + if (rb_block_given_p()) { + return rb_yield(item); + } + return Qnil; + } + + if (deleted) *deleted = 1; + ary_resize_smaller(ary, i2); + + return v; +} + +VALUE +rb_ary_delete(VALUE ary, VALUE item) +{ + return rb_ary_delete_internal(ary, item, NULL); +} + /* * call-seq: * ary.delete(obj) -> item or nil * ary.delete(obj) { block } -> item or result of block + * ary.delete(...) -> [items] + * ary.delete(...) { block } -> [items] or [results of block] * * Deletes all items from +self+ that are equal to +obj+. * @@ -2961,43 +3002,46 @@ ary_resize_smaller(VALUE ary, long len) * the item is not found. (To remove +nil+ elements and get an informative * return value, use Array#compact!) * + * If passed multiple arguments, delete them from +self+ and returns the + * deleted items as an Array. In this case, if no item is deleted, returns + * empty Array. + * * a = [ "a", "b", "b", "b", "c" ] * a.delete("b") #=> "b" * a #=> ["a", "c"] * a.delete("z") #=> nil * a.delete("z") { "not found" } #=> "not found" + * a.delete("a", "c") #=> ["a", "c"] + * a #=> [] + * a.delete("a", "c") #=> [] */ -VALUE -rb_ary_delete(VALUE ary, VALUE item) +static VALUE +rb_ary_delete_m(int argc, VALUE *argv, VALUE ary) { - VALUE v = item; - long i1, i2; + switch (argc) { + case 0: + return Qnil; + case 1: + return rb_ary_delete_internal(ary, argv[0], NULL); + default: + { + VALUE r = rb_ary_new(); + VALUE e; + int i; - for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { - VALUE e = RARRAY_AREF(ary, i1); - - if (rb_equal(e, item)) { - v = e; - continue; + for (i = 0; i < argc; i++) { + int deleted; + e = rb_ary_delete_internal(ary, argv[i], &deleted); + if (deleted || rb_block_given_p()) { + rb_ary_push(r, e); } - if (i1 != i2) { - rb_ary_store(ary, i2, e); } - i2++; + return r; } - if (RARRAY_LEN(ary) == i2) { - if (rb_block_given_p()) { - return rb_yield(item); } - return Qnil; } - ary_resize_smaller(ary, i2); - - return v; -} - void rb_ary_delete_same(VALUE ary, VALUE item) { @@ -5951,7 +5995,7 @@ Init_Array(void) rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0); rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); - rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); + rb_define_method(rb_cArray, "delete", rb_ary_delete_m, -1); rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1); rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0); rb_define_method(rb_cArray, "reject", rb_ary_reject, 0); Index: test/ruby/test_array.rb =================================================================== --- test/ruby/test_array.rb (revision 54477) +++ test/ruby/test_array.rb (working copy) @@ -626,6 +626,26 @@ class TestArray < Test::Unit::TestCase a = @cls[1, o, o2, 2] assert_equal(o2, a.delete(42)) assert_equal([1, 2], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(['cab', 'car'], a.delete('cab', 'car')) + assert_equal(@cls[*('cac'..'caq').to_a] + @cls[*('cas'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(['cap'], a.delete('cap', 'caz')) + assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(nil, a.delete()) + assert_equal(@cls[*('cab'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(['cap', 99], a.delete('cap', 'caz') { 99 }) + assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a) + + a = @cls[*('cab'..'cat').to_a] + assert_equal(['cap', nil], a.delete('cap', 'caz') { nil }) + assert_equal(@cls[*('cab'..'cao').to_a] + @cls[*('caq'..'cat').to_a], a) end def test_delete_at