summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-array-ext
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-array-ext')
-rw-r--r--mrbgems/mruby-array-ext/mrbgem.rake1
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb201
-rw-r--r--mrbgems/mruby-array-ext/test/array.rb137
3 files changed, 297 insertions, 42 deletions
diff --git a/mrbgems/mruby-array-ext/mrbgem.rake b/mrbgems/mruby-array-ext/mrbgem.rake
index 18f92ad65..e4b5938c7 100644
--- a/mrbgems/mruby-array-ext/mrbgem.rake
+++ b/mrbgems/mruby-array-ext/mrbgem.rake
@@ -1,4 +1,5 @@
MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
+ spec.summary = 'extensional Array class'
end
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index 337cef632..7f48811f1 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -201,4 +201,205 @@ class Array
self.replace(result)
end
end
+
+ # for efficiency
+ def reverse_each(&block)
+ return to_enum :reverse_each unless block_given?
+
+ i = self.size - 1
+ while i>=0
+ block.call(self[i])
+ i -= 1
+ end
+ self
+ end
+
+ NONE=Object.new
+ ##
+ # call-seq:
+ # ary.fetch(index) -> obj
+ # ary.fetch(index, default) -> obj
+ # ary.fetch(index) { |index| block } -> obj
+ #
+ # Tries to return the element at position +index+, but throws an IndexError
+ # exception if the referenced +index+ lies outside of the array bounds. This
+ # error can be prevented by supplying a second argument, which will act as a
+ # +default+ value.
+ #
+ # Alternatively, if a block is given it will only be executed when an
+ # invalid +index+ is referenced. Negative values of +index+ count from the
+ # end of the array.
+ #
+ # a = [ 11, 22, 33, 44 ]
+ # a.fetch(1) #=> 22
+ # a.fetch(-1) #=> 44
+ # a.fetch(4, 'cat') #=> "cat"
+ # a.fetch(100) { |i| puts "#{i} is out of bounds" }
+ # #=> "100 is out of bounds"
+ #
+
+ def fetch(n=nil, ifnone=NONE, &block)
+ warn "block supersedes default value argument" if n != nil && ifnone != NONE && block
+
+ idx = n
+ if idx < 0
+ idx += size
+ end
+ if idx < 0 || size <= idx
+ return block.call(n) if block
+ if ifnone == NONE
+ raise IndexError, "index #{n} outside of array bounds: #{-size}...#{size}"
+ end
+ return ifnone
+ end
+ self[idx]
+ end
+
+ ##
+ # call-seq:
+ # ary.fill(obj) -> ary
+ # ary.fill(obj, start [, length]) -> ary
+ # ary.fill(obj, range ) -> ary
+ # ary.fill { |index| block } -> ary
+ # ary.fill(start [, length] ) { |index| block } -> ary
+ # ary.fill(range) { |index| block } -> ary
+ #
+ # The first three forms set the selected elements of +self+ (which
+ # may be the entire array) to +obj+.
+ #
+ # A +start+ of +nil+ is equivalent to zero.
+ #
+ # A +length+ of +nil+ is equivalent to the length of the array.
+ #
+ # The last three forms fill the array with the value of the given block,
+ # which is passed the absolute index of each element to be filled.
+ #
+ # Negative values of +start+ count from the end of the array, where +-1+ is
+ # the last element.
+ #
+ # a = [ "a", "b", "c", "d" ]
+ # a.fill("x") #=> ["x", "x", "x", "x"]
+ # a.fill("w", -1) #=> ["x", "x", "x", "w"]
+ # a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
+ # a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
+ # a.fill { |i| i*i } #=> [0, 1, 4, 9]
+ # a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]
+ # a.fill(1, 2) { |i| i+1 } #=> [0, 2, 3, 27]
+ # a.fill(0..1) { |i| i+1 } #=> [1, 2, 3, 27]
+ #
+
+ 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)"
+ end
+
+ beg = len = 0
+ ary = []
+ if block
+ if arg0 == nil && arg1 == nil && arg2 == nil
+ # ary.fill { |index| block } -> ary
+ beg = 0
+ len = self.size
+ elsif arg0 != nil && arg0.respond_to?(:begin) && arg0.respond_to?(:end)
+ # ary.fill(range) { |index| block } -> ary
+ beg = arg0.begin
+ beg += self.size if beg < 0
+ len = arg0.end - beg + 1
+ elsif arg0 != nil
+ # ary.fill(start [, length] ) { |index| block } -> ary
+ beg = arg0
+ beg += self.size if beg < 0
+ if arg1 == nil
+ len = self.size
+ else
+ len = arg0 + arg1
+ end
+ end
+ else
+ 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
+ beg = arg1.begin
+ len = arg1.end - beg + 1
+ elsif arg0 != nil && arg1 != nil
+ # ary.fill(obj, start [, length]) -> ary
+ beg = arg1
+ beg += self.size if beg < 0
+ if arg2 == nil
+ len = self.size
+ else
+ len = arg1 + arg2
+ end
+ end
+ end
+
+ i = beg
+ if block
+ while i < len
+ self[i] = block.call(i)
+ i += 1
+ end
+ else
+ while i < len
+ self[i] = arg0
+ i += 1
+ end
+ end
+ self
+ end
+
+ ##
+ # call-seq:
+ # ary.rotate(count=1) -> new_ary
+ #
+ # Returns a new array by rotating +self+ so that the element at +count+ is
+ # the first element of the new array.
+ #
+ # If +count+ is negative then it rotates in the opposite direction, starting
+ # from the end of +self+ where +-1+ is the last element.
+ #
+ # 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"]
+
+ def rotate(count=1)
+ ary = []
+ len = self.length
+
+ if len > 0
+ idx = (count < 0) ? (len - (~count % len) - 1) : (count % len) # rotate count
+ len.times do
+ ary << self[idx]
+ idx += 1
+ idx = 0 if idx > len-1
+ end
+ end
+ ary
+ end
+
+ ##
+ # call-seq:
+ # ary.rotate!(count=1) -> ary
+ #
+ # Rotates +self+ in place so that the element at +count+ comes first, and
+ # returns +self+.
+ #
+ # If +count+ is negative then it rotates in the opposite direction, starting
+ # from the end of the array where +-1+ is the last element.
+ #
+ # 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"]
+
+ def rotate!(count=1)
+ self.replace(self.rotate(count))
+ end
end
diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb
index 1c441cec4..9a0f25f9a 100644
--- a/mrbgems/mruby-array-ext/test/array.rb
+++ b/mrbgems/mruby-array-ext/test/array.rb
@@ -2,8 +2,8 @@
# Array(Ext) Test
assert("Array::try_convert") do
- Array.try_convert([1]) == [1] and
- Array.try_convert("1").nil?
+ assert_equal [1], Array.try_convert([1])
+ assert_nil Array.try_convert("1")
end
assert("Array#assoc") do
@@ -12,98 +12,151 @@ assert("Array#assoc") do
s3 = "foo"
a = [ s1, s2, s3 ]
- a.assoc("letters") == [ "letters", "a", "b", "c" ] and
- a.assoc("foo").nil?
+ assert_equal [ "letters", "a", "b", "c" ], a.assoc("letters")
+ assert_nil a.assoc("foo")
end
assert("Array#at") do
a = [ "a", "b", "c", "d", "e" ]
- a.at(0) == "a" and a.at(-1) == "e"
+ assert_equal "a", a.at(0)
+ assert_equal "e", a.at(-1)
end
assert("Array#rassoc") do
a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
- a.rassoc("two") == [2, "two"] and
- a.rassoc("four").nil?
+ assert_equal [2, "two"], a.rassoc("two")
+ assert_nil a.rassoc("four")
end
assert("Array#uniq!") do
a = [1, 2, 3, 1]
a.uniq!
- a == [1, 2, 3]
+ assert_equal [1, 2, 3], a
+
+ b = [ "a", "b", "c" ]
+ assert_nil b.uniq!
end
assert("Array#uniq") do
a = [1, 2, 3, 1]
- a.uniq == [1, 2, 3] && a == [1, 2, 3, 1]
+ assert_equal [1, 2, 3], a.uniq
+ assert_equal [1, 2, 3, 1], a
end
assert("Array#-") do
a = [1, 2, 3, 1]
b = [1]
c = 1
- e1 = nil
-
- begin
- a - c
- rescue => e1
- end
- (a - b) == [2, 3] and e1.class == TypeError and a == [1, 2, 3, 1]
+ assert_raise(TypeError) { a - c }
+ assert_equal [2, 3], (a - b)
+ assert_equal [1, 2, 3, 1], a
end
assert("Array#|") do
a = [1, 2, 3, 1]
b = [1, 4]
c = 1
- e1 = nil
-
- begin
- a | c
- rescue => e1
- end
- (a | b) == [1, 2, 3, 4] and e1.class == TypeError and a == [1, 2, 3, 1]
+ assert_raise(TypeError) { a | c }
+ assert_equal [1, 2, 3, 4], (a | b)
+ assert_equal [1, 2, 3, 1], a
end
assert("Array#&") do
a = [1, 2, 3, 1]
b = [1, 4]
c = 1
- e1 = nil
- begin
- a & c
- rescue => e1
- end
-
- (a & b) == [1] and e1.class == TypeError and a == [1, 2, 3, 1]
+ assert_raise(TypeError) { a & c }
+ assert_equal [1], (a & b)
+ assert_equal [1, 2, 3, 1], a
end
assert("Array#flatten") do
- [1, 2, "3", {4=>5}, :'6'] == [1, 2, "3", {4=>5}, :'6'].flatten and
- [1, 2, 3, 4, 5, 6] == [1, 2, [3, 4, 5], 6].flatten and
- [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten and
- [1, [2, [3, [4, [5, [6]]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(0) and
- [1, 2, [3, [4, [5, [6]]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(1) and
- [1, 2, 3, [4, [5, [6]]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(2) and
- [1, 2, 3, 4, [5, [6]]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(3) and
- [1, 2, 3, 4, 5, [6]] == [1, [2, [3, [4, [5, [6]]]]]].flatten(4) and
- [1, 2, 3, 4, 5, 6] == [1, [2, [3, [4, [5, [6]]]]]].flatten(5)
+ assert_equal [1, 2, "3", {4=>5}, :'6'], [1, 2, "3", {4=>5}, :'6'].flatten
+ assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, 4, 5], 6].flatten
+ assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, [4, 5], 6]].flatten
+ assert_equal [1, [2, [3, [4, [5, [6]]]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(0)
+ assert_equal [1, 2, [3, [4, [5, [6]]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(1)
+ assert_equal [1, 2, 3, [4, [5, [6]]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(2)
+ assert_equal [1, 2, 3, 4, [5, [6]]], [1, [2, [3, [4, [5, [6]]]]]].flatten(3)
+ assert_equal [1, 2, 3, 4, 5, [6]], [1, [2, [3, [4, [5, [6]]]]]].flatten(4)
+ assert_equal [1, 2, 3, 4, 5, 6], [1, [2, [3, [4, [5, [6]]]]]].flatten(5)
end
assert("Array#flatten!") do
- [1, 2, 3, 4, 5, 6] == [1, 2, [3, [4, 5], 6]].flatten!
+ assert_equal [1, 2, 3, 4, 5, 6], [1, 2, [3, [4, 5], 6]].flatten!
end
assert("Array#compact") do
a = [1, nil, "2", nil, :t, false, nil]
- a.compact == [1, "2", :t, false] && a == [1, nil, "2", nil, :t, false, nil]
+ assert_equal [1, "2", :t, false], a.compact
+ assert_equal [1, nil, "2", nil, :t, false, nil], a
end
assert("Array#compact!") do
a = [1, nil, "2", nil, :t, false, nil]
a.compact!
- a == [1, "2", :t, false]
+ assert_equal [1, "2", :t, false], a
+end
+
+assert("Array#fetch") do
+ a = [ 11, 22, 33, 44 ]
+ assert_equal 22, a.fetch(1)
+ assert_equal 44, a.fetch(-1)
+ assert_equal 'cat', a.fetch(4, 'cat')
+ ret = 0
+ a.fetch(100) { |i| ret = i }
+ assert_equal 100, ret
+ assert_raise(IndexError) { a.fetch(100) }
+end
+
+assert("Array#fill") do
+ a = [ "a", "b", "c", "d" ]
+ assert_equal ["x", "x", "x", "x"], a.fill("x")
+ assert_equal ["x", "x", "x", "w"], a.fill("w", -1)
+ assert_equal ["x", "x", "z", "z"], a.fill("z", 2, 2)
+ assert_equal ["y", "y", "z", "z"], a.fill("y", 0..1)
+ assert_equal [0, 1, 4, 9], a.fill { |i| i*i }
+ assert_equal [0, 1, 8, 27], a.fill(-2) { |i| i*i*i }
+ assert_equal [0, 2, 3, 27], a.fill(1, 2) { |i| i+1 }
+ assert_equal [1, 2, 3, 27], a.fill(0..1) { |i| i+1 }
+ assert_raise(ArgumentError) { a.fill }
+end
+
+assert("Array#reverse_each") do
+ a = [ "a", "b", "c", "d" ]
+ b = []
+ a.reverse_each do |i|
+ b << i
+ end
+ assert_equal [ "d", "c", "b", "a" ], b
+
+ if Object.const_defined?(:Enumerator)
+ assert_equal [ "d", "c", "b", "a" ], a.reverse_each.to_a
+ else
+ true
+ end
+end
+
+assert("Array#rotate") do
+ a = ["a", "b", "c", "d"]
+ assert_equal ["b", "c", "d", "a"], a.rotate
+ assert_equal ["a", "b", "c", "d"], a
+ assert_equal ["c", "d", "a", "b"], a.rotate(2)
+ assert_equal ["b", "c", "d", "a"], a.rotate(-3)
+ assert_equal ["c", "d", "a", "b"], a.rotate(10)
+ assert_equal [], [].rotate
+end
+
+assert("Array#rotate!") do
+ a = ["a", "b", "c", "d"]
+ assert_equal ["b", "c", "d", "a"], a.rotate!
+ assert_equal ["b", "c", "d", "a"], a
+ assert_equal ["d", "a", "b", "c"], a.rotate!(2)
+ assert_equal ["a", "b", "c", "d"], a.rotate!(-3)
+ assert_equal ["c", "d", "a", "b"], a.rotate(10)
+ assert_equal [], [].rotate!
end