Merge pull request #2142 from cremno/rename-mrb_str_buf_append
[mruby.git] / mrbgems / mruby-array-ext / mrblib / array.rb
index 411c4e8..bddcd8a 100644 (file)
@@ -313,7 +313,7 @@ class Array
 
   def fill(arg0=nil, arg1=nil, arg2=nil, &block)
     if arg0 == nil && arg1 == nil && arg2 == nil && !block
-      raise ArgumentError, "wrong number of arguments (0 for 1..3)" 
+      raise ArgumentError, "wrong number of arguments (0 for 1..3)"
     end
 
     beg = len = 0
@@ -323,11 +323,13 @@ class Array
         # ary.fill { |index| block }                    -> ary
         beg = 0
         len = self.size
-      elsif arg0 != nil && arg0.respond_to?(:begin) && arg0.respond_to?(:end)
+      elsif arg0 != nil && arg0.kind_of?(Range)
         # ary.fill(range) { |index| block }             -> ary
         beg = arg0.begin
         beg += self.size if beg < 0
-        len = arg0.end - beg + 1
+        len = arg0.end
+        len += self.size if len < 0
+        len += 1 unless arg0.exclude_end?
       elsif arg0 != nil
         # ary.fill(start [, length] ) { |index| block } -> ary
         beg = arg0
@@ -342,20 +344,22 @@ class Array
       if arg0 != nil && arg1 == nil && arg2 == nil
         # ary.fill(obj)                                 -> ary
         beg = 0
-        len = self.size      
-      elsif arg0 != nil && arg1 != nil && arg1.respond_to?(:begin) && arg1.respond_to?(:end)
-        # ary.fill(obj, range )                         -> ary
         len = self.size
+      elsif arg0 != nil && arg1 != nil && arg1.kind_of?(Range)
+        # ary.fill(obj, range )                         -> ary
         beg = arg1.begin
-        len = arg1.end - beg + 1
+        beg += self.size if beg < 0
+        len = arg1.end
+        len += self.size if len < 0
+        len += 1 unless arg1.exclude_end?
       elsif arg0 != nil && arg1 != nil
         # ary.fill(obj, start [, length])               -> ary
         beg = arg1
         beg += self.size if beg < 0
-       if arg2 == nil
+        if arg2 == nil
           len = self.size
         else
-          len = arg1 + arg2
+          len = beg + arg2
         end
       end
     end
@@ -591,4 +595,96 @@ class Array
     return nil unless satisfied
     self[low]
   end
+
+  ##
+  #  call-seq:
+  #     ary.delete_if { |item| block }  -> ary
+  #     ary.delete_if                   -> Enumerator
+  #
+  #  Deletes every element of +self+ for which block evaluates to +true+.
+  #
+  #  The array is changed instantly every time the block is called, not after
+  #  the iteration is over.
+  #
+  #  See also Array#reject!
+  #
+  #  If no block is given, an Enumerator is returned instead.
+  #
+  #     scores = [ 97, 42, 75 ]
+  #     scores.delete_if {|score| score < 80 }   #=> [97]
+
+  def delete_if(&block)
+    return to_enum :delete_if unless block_given?
+
+    idx = 0
+    len = self.size
+    while idx < self.size do
+      if block.call(self[idx])
+        self.delete_at(idx)
+      else
+        idx += 1
+      end
+    end
+    self
+  end
+
+  ##
+  #  call-seq:
+  #     ary.keep_if { |item| block } -> ary
+  #     ary.keep_if                  -> Enumerator
+  #
+  #  Deletes every element of +self+ for which the given block evaluates to
+  #  +false+.
+  #
+  #  See also Array#select!
+  #
+  #  If no block is given, an Enumerator is returned instead.
+  #
+  #     a = [1, 2, 3, 4, 5]
+  #     a.keep_if { |val| val > 3 } #=> [4, 5]
+
+  def keep_if(&block)
+    return to_enum :keep_if unless block_given?
+
+    idx = 0
+    len = self.size
+    while idx < self.size do
+      if block.call(self[idx])
+        idx += 1
+      else
+        self.delete_at(idx)
+      end
+    end
+    self
+  end
+
+  ##
+  #  call-seq:
+  #     ary.select!  {|item| block } -> ary or nil
+  #     ary.select!                  -> Enumerator
+  #
+  #  Invokes the given block passing in successive elements from +self+,
+  #  deleting elements for which the block returns a +false+ value.
+  #
+  #  If changes were made, it will return +self+, otherwise it returns +nil+.
+  #
+  #  See also Array#keep_if
+  #
+  #  If no block is given, an Enumerator is returned instead.
+
+  def select!(&block)
+    return to_enum :select! unless block_given?
+
+    idx = 0
+    len = self.size
+    while idx < self.size do
+      if block.call(self[idx])
+        idx += 1
+      else
+        self.delete_at(idx)
+      end
+    end
+    return nil if self.size == len
+    self
+  end
 end