mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
98286e9850
This fixes various issues when a module is included in or prepended to a module or class, and then refined, or refined and then included or prepended to a module or class. Implement by renaming ensure_origin to rb_ensure_origin, making it non-static, and calling it when refining a module. Fix Module#initialize_copy to handle origins correctly. Previously, Module#initialize_copy did not handle origins correctly. For example, this code: ```ruby module B; end class A def b; 2 end prepend B end a = A.dup.new class A def b; 1 end end p a.b ``` Printed 1 instead of 2. This is because the super chain for a.singleton_class was: ``` a.singleton_class A.dup B(iclass) B(iclass origin) A(origin) # not A.dup(origin) ``` The B iclasses would not be modified, so the includer entry would be still be set to A and not A.dup. This modifies things so that if the class/module has an origin, all iclasses between the class/module and the origin are duplicated and have the correct includer entry set, and the correct origin is created. This requires other changes to make sure all tests still pass: * rb_undef_methods_from doesn't automatically handle classes with origins, so pass it the origin for Comparable when undefing methods in Complex. This fixed a failure in the Complex tests. * When adding a method, the method cache was not cleared correctly if klass has an origin. Clear the method cache for the klass before switching to the origin of klass. This fixed failures in the autoload tests related to overridding require, without breaking the optimization tests. Also clear the method cache for both the module and origin when removing a method. * Module#include? is fixed to skip origin iclasses. * Refinements are fixed to use the origin class of the module that has an origin. * RCLASS_REFINED_BY_ANY is removed as it was only used in a single place and is no longer needed. * Marshal#dump is fixed to skip iclass origins. * rb_method_entry_make is fixed to handled overridden optimized methods for modules that have origins. Fixes [Bug #16852]
1180 lines
34 KiB
Ruby
1180 lines
34 KiB
Ruby
# frozen_string_literal: false
|
|
require 'test/unit'
|
|
EnvUtil.suppress_warning {require 'continuation'}
|
|
require 'stringio'
|
|
|
|
class TestEnumerable < Test::Unit::TestCase
|
|
def setup
|
|
@obj = Object.new
|
|
class << @obj
|
|
include Enumerable
|
|
def each
|
|
yield 1
|
|
yield 2
|
|
yield 3
|
|
yield 1
|
|
yield 2
|
|
self
|
|
end
|
|
end
|
|
@empty = Object.new
|
|
class << @empty
|
|
attr_reader :block
|
|
include Enumerable
|
|
def each(&block)
|
|
@block = block
|
|
self
|
|
end
|
|
end
|
|
@verbose = $VERBOSE
|
|
$VERBOSE = nil
|
|
end
|
|
|
|
def teardown
|
|
$VERBOSE = @verbose
|
|
end
|
|
|
|
def test_grep_v
|
|
assert_equal([3], @obj.grep_v(1..2))
|
|
a = []
|
|
@obj.grep_v(2) {|x| a << x }
|
|
assert_equal([1, 3, 1], a)
|
|
|
|
a = []
|
|
lambda = ->(x, i) {a << [x, i]}
|
|
@obj.each_with_index.grep_v(proc{|x,i|x!=2}, &lambda)
|
|
assert_equal([[2, 1], [2, 4]], a)
|
|
end
|
|
|
|
def test_grep
|
|
assert_equal([1, 2, 1, 2], @obj.grep(1..2))
|
|
a = []
|
|
@obj.grep(2) {|x| a << x }
|
|
assert_equal([2, 2], a)
|
|
|
|
bug5801 = '[ruby-dev:45041]'
|
|
@empty.grep(//)
|
|
block = @empty.block
|
|
assert_nothing_raised(bug5801) {100.times {block.call}}
|
|
|
|
a = []
|
|
lambda = ->(x, i) {a << [x, i]}
|
|
@obj.each_with_index.grep(proc{|x,i|x==2}, &lambda)
|
|
assert_equal([[2, 1], [2, 4]], a)
|
|
end
|
|
|
|
def test_count
|
|
assert_equal(5, @obj.count)
|
|
assert_equal(2, @obj.count(1))
|
|
assert_equal(3, @obj.count {|x| x % 2 == 1 })
|
|
assert_equal(2, @obj.count(1) {|x| x % 2 == 1 })
|
|
assert_raise(ArgumentError) { @obj.count(0, 1) }
|
|
|
|
if RUBY_ENGINE == "ruby"
|
|
en = Class.new {
|
|
include Enumerable
|
|
alias :size :count
|
|
def each
|
|
yield 1
|
|
end
|
|
}
|
|
assert_equal(1, en.new.count, '[ruby-core:24794]')
|
|
end
|
|
end
|
|
|
|
def test_find
|
|
assert_equal(2, @obj.find {|x| x % 2 == 0 })
|
|
assert_equal(nil, @obj.find {|x| false })
|
|
assert_equal(:foo, @obj.find(proc { :foo }) {|x| false })
|
|
cond = ->(x, i) { x % 2 == 0 }
|
|
assert_equal([2, 1], @obj.each_with_index.find(&cond))
|
|
end
|
|
|
|
def test_find_index
|
|
assert_equal(1, @obj.find_index(2))
|
|
assert_equal(1, @obj.find_index {|x| x % 2 == 0 })
|
|
assert_equal(nil, @obj.find_index {|x| false })
|
|
assert_raise(ArgumentError) { @obj.find_index(0, 1) }
|
|
assert_equal(1, @obj.find_index(2) {|x| x == 1 })
|
|
end
|
|
|
|
def test_find_all
|
|
assert_equal([1, 3, 1], @obj.find_all {|x| x % 2 == 1 })
|
|
cond = ->(x, i) { x % 2 == 1 }
|
|
assert_equal([[1, 0], [3, 2], [1, 3]], @obj.each_with_index.find_all(&cond))
|
|
end
|
|
|
|
def test_reject
|
|
assert_equal([2, 3, 2], @obj.reject {|x| x < 2 })
|
|
cond = ->(x, i) {x < 2}
|
|
assert_equal([[2, 1], [3, 2], [2, 4]], @obj.each_with_index.reject(&cond))
|
|
end
|
|
|
|
def test_to_a
|
|
assert_equal([1, 2, 3, 1, 2], @obj.to_a)
|
|
end
|
|
|
|
def test_to_a_size_symbol
|
|
sym = Object.new
|
|
class << sym
|
|
include Enumerable
|
|
def each
|
|
self
|
|
end
|
|
|
|
def size
|
|
:size
|
|
end
|
|
end
|
|
assert_equal([], sym.to_a)
|
|
end
|
|
|
|
def test_to_a_size_infinity
|
|
inf = Object.new
|
|
class << inf
|
|
include Enumerable
|
|
def each
|
|
self
|
|
end
|
|
|
|
def size
|
|
Float::INFINITY
|
|
end
|
|
end
|
|
assert_equal([], inf.to_a)
|
|
end
|
|
|
|
StubToH = Object.new.tap do |obj|
|
|
def obj.each(*args)
|
|
yield(*args)
|
|
yield [:key, :value]
|
|
yield :other_key, :other_value
|
|
kvp = Object.new
|
|
def kvp.to_ary
|
|
[:obtained, :via_to_ary]
|
|
end
|
|
yield kvp
|
|
end
|
|
obj.extend Enumerable
|
|
obj.freeze
|
|
end
|
|
|
|
def test_to_h
|
|
obj = StubToH
|
|
|
|
assert_equal({
|
|
:hello => :world,
|
|
:key => :value,
|
|
:other_key => :other_value,
|
|
:obtained => :via_to_ary,
|
|
}, obj.to_h(:hello, :world))
|
|
|
|
e = assert_raise(TypeError) {
|
|
obj.to_h(:not_an_array)
|
|
}
|
|
assert_equal "wrong element type Symbol (expected array)", e.message
|
|
|
|
e = assert_raise(ArgumentError) {
|
|
obj.to_h([1])
|
|
}
|
|
assert_equal "element has wrong array length (expected 2, was 1)", e.message
|
|
end
|
|
|
|
def test_to_h_block
|
|
obj = StubToH
|
|
|
|
assert_equal({
|
|
"hello" => "world",
|
|
"key" => "value",
|
|
"other_key" => "other_value",
|
|
"obtained" => "via_to_ary",
|
|
}, obj.to_h(:hello, :world) {|k, v| [k.to_s, v.to_s]})
|
|
|
|
e = assert_raise(TypeError) {
|
|
obj.to_h {:not_an_array}
|
|
}
|
|
assert_equal "wrong element type Symbol (expected array)", e.message
|
|
|
|
e = assert_raise(ArgumentError) {
|
|
obj.to_h {[1]}
|
|
}
|
|
assert_equal "element has wrong array length (expected 2, was 1)", e.message
|
|
end
|
|
|
|
def test_inject
|
|
assert_equal(12, @obj.inject {|z, x| z * x })
|
|
assert_equal(48, @obj.inject {|z, x| z * 2 + x })
|
|
assert_equal(12, @obj.inject(:*))
|
|
assert_equal(24, @obj.inject(2) {|z, x| z * x })
|
|
assert_equal(24, @obj.inject(2, :*) {|z, x| z * x })
|
|
assert_equal(nil, @empty.inject() {9})
|
|
end
|
|
|
|
FIXNUM_MIN = RbConfig::LIMITS['FIXNUM_MIN']
|
|
FIXNUM_MAX = RbConfig::LIMITS['FIXNUM_MAX']
|
|
|
|
def test_inject_array_mul
|
|
assert_equal(nil, [].inject(:*))
|
|
assert_equal(5, [5].inject(:*))
|
|
assert_equal(35, [5, 7].inject(:*))
|
|
assert_equal(3, [].inject(3, :*))
|
|
assert_equal(15, [5].inject(3, :*))
|
|
assert_equal(105, [5, 7].inject(3, :*))
|
|
end
|
|
|
|
def test_inject_array_plus
|
|
assert_equal(3, [3].inject(:+))
|
|
assert_equal(8, [3, 5].inject(:+))
|
|
assert_equal(15, [3, 5, 7].inject(:+))
|
|
assert_float_equal(15.0, [3, 5, 7.0].inject(:+))
|
|
assert_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).inject(:+))
|
|
assert_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).inject(:+))
|
|
assert_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).inject(:+))
|
|
assert_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).inject(:+))
|
|
assert_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).inject(:+))
|
|
assert_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).inject(:+))
|
|
assert_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].inject(:+))
|
|
assert_float_equal(10.0, [3.0, 5].inject(2.0, :+))
|
|
assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].inject(:+))
|
|
assert_equal(2.0+3.0i, [2.0, 3.0i].inject(:+))
|
|
end
|
|
|
|
def test_inject_array_op_redefined
|
|
assert_separately([], "#{<<~"end;"}\n""end")
|
|
all_assertions_foreach("", *%i[+ * / - %]) do |op|
|
|
bug = '[ruby-dev:49510] [Bug#12178] should respect redefinition'
|
|
begin
|
|
Integer.class_eval do
|
|
alias_method :orig, op
|
|
define_method(op) do |x|
|
|
0
|
|
end
|
|
end
|
|
assert_equal(0, [1,2,3].inject(op), bug)
|
|
ensure
|
|
Integer.class_eval do
|
|
undef_method op
|
|
alias_method op, :orig
|
|
end
|
|
end
|
|
end;
|
|
end
|
|
|
|
def test_inject_array_op_private
|
|
assert_separately([], "#{<<~"end;"}\n""end")
|
|
all_assertions_foreach("", *%i[+ * / - %]) do |op|
|
|
bug = '[ruby-core:81349] [Bug #13592] should respect visibility'
|
|
assert_raise_with_message(NoMethodError, /private method/, bug) do
|
|
begin
|
|
Integer.class_eval do
|
|
private op
|
|
end
|
|
[1,2,3].inject(op)
|
|
ensure
|
|
Integer.class_eval do
|
|
public op
|
|
end
|
|
end
|
|
end
|
|
end;
|
|
end
|
|
|
|
def test_refine_Enumerable_then_include
|
|
assert_separately([], "#{<<~"end;"}\n")
|
|
module RefinementBug
|
|
refine Enumerable do
|
|
def refined_method
|
|
:rm
|
|
end
|
|
end
|
|
end
|
|
using RefinementBug
|
|
|
|
class A
|
|
include Enumerable
|
|
end
|
|
|
|
assert_equal(:rm, [].refined_method)
|
|
end;
|
|
end
|
|
|
|
def test_partition
|
|
assert_equal([[1, 3, 1], [2, 2]], @obj.partition {|x| x % 2 == 1 })
|
|
cond = ->(x, i) { x % 2 == 1 }
|
|
assert_equal([[[1, 0], [3, 2], [1, 3]], [[2, 1], [2, 4]]], @obj.each_with_index.partition(&cond))
|
|
end
|
|
|
|
def test_group_by
|
|
h = { 1 => [1, 1], 2 => [2, 2], 3 => [3] }
|
|
assert_equal(h, @obj.group_by {|x| x })
|
|
|
|
h = {1=>[[1, 0], [1, 3]], 2=>[[2, 1], [2, 4]], 3=>[[3, 2]]}
|
|
cond = ->(x, i) { x }
|
|
assert_equal(h, @obj.each_with_index.group_by(&cond))
|
|
end
|
|
|
|
def test_tally
|
|
h = {1 => 2, 2 => 2, 3 => 1}
|
|
assert_equal(h, @obj.tally)
|
|
end
|
|
|
|
def test_first
|
|
assert_equal(1, @obj.first)
|
|
assert_equal([1, 2, 3], @obj.first(3))
|
|
assert_nil(@empty.first)
|
|
assert_equal([], @empty.first(10))
|
|
|
|
bug5801 = '[ruby-dev:45041]'
|
|
assert_in_out_err([], <<-'end;', [], /unexpected break/, bug5801)
|
|
empty = Object.new
|
|
class << empty
|
|
attr_reader :block
|
|
include Enumerable
|
|
def each(&block)
|
|
@block = block
|
|
self
|
|
end
|
|
end
|
|
empty.first
|
|
empty.block.call
|
|
end;
|
|
end
|
|
|
|
def test_sort
|
|
assert_equal([1, 1, 2, 2, 3], @obj.sort)
|
|
assert_equal([3, 2, 2, 1, 1], @obj.sort {|x, y| y <=> x })
|
|
end
|
|
|
|
def test_sort_by
|
|
assert_equal([3, 2, 2, 1, 1], @obj.sort_by {|x| -x })
|
|
assert_equal((1..300).to_a.reverse, (1..300).sort_by {|x| -x })
|
|
|
|
cond = ->(x, i) { [-x, i] }
|
|
assert_equal([[3, 2], [2, 1], [2, 4], [1, 0], [1, 3]], @obj.each_with_index.sort_by(&cond))
|
|
end
|
|
|
|
def test_all
|
|
assert_equal(true, @obj.all? {|x| x <= 3 })
|
|
assert_equal(false, @obj.all? {|x| x < 3 })
|
|
assert_equal(true, @obj.all?)
|
|
assert_equal(false, [true, true, false].all?)
|
|
assert_equal(true, [].all?)
|
|
assert_equal(true, @empty.all?)
|
|
assert_equal(true, @obj.all?(Fixnum))
|
|
assert_equal(false, @obj.all?(1..2))
|
|
end
|
|
|
|
def test_all_with_unused_block
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
[1, 2].all?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
(1..2).all?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
3.times.all?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
{a: 1, b: 2}.all?([:b, 2]) {|x| x == 4 }
|
|
EOS
|
|
end
|
|
|
|
def test_any
|
|
assert_equal(true, @obj.any? {|x| x >= 3 })
|
|
assert_equal(false, @obj.any? {|x| x > 3 })
|
|
assert_equal(true, @obj.any?)
|
|
assert_equal(false, [false, false, false].any?)
|
|
assert_equal(false, [].any?)
|
|
assert_equal(false, @empty.any?)
|
|
assert_equal(true, @obj.any?(1..2))
|
|
assert_equal(false, @obj.any?(Float))
|
|
assert_equal(false, [1, 42].any?(Float))
|
|
assert_equal(true, [1, 4.2].any?(Float))
|
|
assert_equal(false, {a: 1, b: 2}.any?(->(kv) { kv == [:foo, 42] }))
|
|
assert_equal(true, {a: 1, b: 2}.any?(->(kv) { kv == [:b, 2] }))
|
|
end
|
|
|
|
def test_any_with_unused_block
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
[1, 23].any?(1) {|x| x == 1 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
(1..2).any?(34) {|x| x == 2 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
3.times.any?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
{a: 1, b: 2}.any?([:b, 2]) {|x| x == 4 }
|
|
EOS
|
|
end
|
|
|
|
def test_one
|
|
assert(@obj.one? {|x| x == 3 })
|
|
assert(!(@obj.one? {|x| x == 1 }))
|
|
assert(!(@obj.one? {|x| x == 4 }))
|
|
assert(@obj.one?(3..4))
|
|
assert(!(@obj.one?(1..2)))
|
|
assert(!(@obj.one?(4..5)))
|
|
assert(%w{ant bear cat}.one? {|word| word.length == 4})
|
|
assert(!(%w{ant bear cat}.one? {|word| word.length > 4}))
|
|
assert(!(%w{ant bear cat}.one? {|word| word.length < 4}))
|
|
assert(%w{ant bear cat}.one?(/b/))
|
|
assert(!(%w{ant bear cat}.one?(/t/)))
|
|
assert(!([ nil, true, 99 ].one?))
|
|
assert([ nil, true, false ].one?)
|
|
assert(![].one?)
|
|
assert(!@empty.one?)
|
|
assert([ nil, true, 99 ].one?(Integer))
|
|
end
|
|
|
|
def test_one_with_unused_block
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
[1, 2].one?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
(1..2).one?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
3.times.one?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
{a: 1, b: 2}.one?([:b, 2]) {|x| x == 4 }
|
|
EOS
|
|
end
|
|
|
|
def test_none
|
|
assert(@obj.none? {|x| x == 4 })
|
|
assert(!(@obj.none? {|x| x == 1 }))
|
|
assert(!(@obj.none? {|x| x == 3 }))
|
|
assert(@obj.none?(4..5))
|
|
assert(!(@obj.none?(1..3)))
|
|
assert(%w{ant bear cat}.none? {|word| word.length == 5})
|
|
assert(!(%w{ant bear cat}.none? {|word| word.length >= 4}))
|
|
assert(%w{ant bear cat}.none?(/d/))
|
|
assert(!(%w{ant bear cat}.none?(/b/)))
|
|
assert([].none?)
|
|
assert([nil].none?)
|
|
assert([nil,false].none?)
|
|
assert(![nil,false,true].none?)
|
|
assert(@empty.none?)
|
|
end
|
|
|
|
def test_none_with_unused_block
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
[1, 2].none?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
(1..2).none?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
3.times.none?(1) {|x| x == 3 }
|
|
EOS
|
|
assert_in_out_err [], <<-EOS, [], ["-:1: warning: given block not used"]
|
|
{a: 1, b: 2}.none?([:b, 2]) {|x| x == 4 }
|
|
EOS
|
|
end
|
|
|
|
def test_min
|
|
assert_equal(1, @obj.min)
|
|
assert_equal(3, @obj.min {|a,b| b <=> a })
|
|
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
|
assert_equal([3, 2], @obj.each_with_index.min(&cond))
|
|
enum = %w(albatross dog horse).to_enum
|
|
assert_equal("albatross", enum.min)
|
|
assert_equal("dog", enum.min {|a,b| a.length <=> b.length })
|
|
assert_equal(1, [3,2,1].to_enum.min)
|
|
assert_equal(%w[albatross dog], enum.min(2))
|
|
assert_equal(%w[dog horse],
|
|
enum.min(2) {|a,b| a.length <=> b.length })
|
|
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].to_enum.min(2))
|
|
assert_equal([2, 4, 6, 7], [2, 4, 8, 6, 7].to_enum.min(4))
|
|
end
|
|
|
|
def test_max
|
|
assert_equal(3, @obj.max)
|
|
assert_equal(1, @obj.max {|a,b| b <=> a })
|
|
cond = ->((a, ia), (b, ib)) { (b <=> a).nonzero? or ia <=> ib }
|
|
assert_equal([1, 3], @obj.each_with_index.max(&cond))
|
|
enum = %w(albatross dog horse).to_enum
|
|
assert_equal("horse", enum.max)
|
|
assert_equal("albatross", enum.max {|a,b| a.length <=> b.length })
|
|
assert_equal(1, [3,2,1].to_enum.max{|a,b| b <=> a })
|
|
assert_equal(%w[horse dog], enum.max(2))
|
|
assert_equal(%w[albatross horse],
|
|
enum.max(2) {|a,b| a.length <=> b.length })
|
|
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].to_enum.max(2))
|
|
end
|
|
|
|
def test_minmax
|
|
assert_equal([1, 3], @obj.minmax)
|
|
assert_equal([3, 1], @obj.minmax {|a,b| b <=> a })
|
|
ary = %w(albatross dog horse)
|
|
assert_equal(["albatross", "horse"], ary.minmax)
|
|
assert_equal(["dog", "albatross"], ary.minmax {|a,b| a.length <=> b.length })
|
|
assert_equal([1, 3], [2,3,1].minmax)
|
|
assert_equal([3, 1], [2,3,1].minmax {|a,b| b <=> a })
|
|
assert_equal([1, 3], [2,2,3,3,1,1].minmax)
|
|
assert_equal([nil, nil], [].minmax)
|
|
end
|
|
|
|
def test_min_by
|
|
assert_equal(3, @obj.min_by {|x| -x })
|
|
cond = ->(x, i) { -x }
|
|
assert_equal([3, 2], @obj.each_with_index.min_by(&cond))
|
|
a = %w(albatross dog horse)
|
|
assert_equal("dog", a.min_by {|x| x.length })
|
|
assert_equal(3, [2,3,1].min_by {|x| -x })
|
|
assert_equal(%w[dog horse], a.min_by(2) {|x| x.length })
|
|
assert_equal([13, 14], [20, 32, 32, 21, 30, 25, 29, 13, 14].min_by(2) {|x| x})
|
|
end
|
|
|
|
def test_max_by
|
|
assert_equal(1, @obj.max_by {|x| -x })
|
|
cond = ->(x, i) { -x }
|
|
assert_equal([1, 0], @obj.each_with_index.max_by(&cond))
|
|
a = %w(albatross dog horse)
|
|
assert_equal("albatross", a.max_by {|x| x.length })
|
|
assert_equal(1, [2,3,1].max_by {|x| -x })
|
|
assert_equal(%w[albatross horse], a.max_by(2) {|x| x.length })
|
|
assert_equal([3, 2], [0, 0, 0, 0, 0, 0, 1, 3, 2].max_by(2) {|x| x})
|
|
end
|
|
|
|
def test_minmax_by
|
|
assert_equal([3, 1], @obj.minmax_by {|x| -x })
|
|
cond = ->(x, i) { -x }
|
|
assert_equal([[3, 2], [1, 0]], @obj.each_with_index.minmax_by(&cond))
|
|
a = %w(albatross dog horse)
|
|
assert_equal(["dog", "albatross"], a.minmax_by {|x| x.length })
|
|
assert_equal([3, 1], [2,3,1].minmax_by {|x| -x })
|
|
end
|
|
|
|
def test_member
|
|
assert(@obj.member?(1))
|
|
assert(!(@obj.member?(4)))
|
|
assert([1,2,3].member?(1))
|
|
assert(!([1,2,3].member?(4)))
|
|
end
|
|
|
|
class Foo
|
|
include Enumerable
|
|
def each
|
|
yield 1
|
|
yield 1,2
|
|
end
|
|
end
|
|
|
|
def test_each_with_index
|
|
a = []
|
|
@obj.each_with_index {|x, i| a << [x, i] }
|
|
assert_equal([[1,0],[2,1],[3,2],[1,3],[2,4]], a)
|
|
|
|
hash = Hash.new
|
|
%w(cat dog wombat).each_with_index do |item, index|
|
|
hash[item] = index
|
|
end
|
|
assert_equal({"cat"=>0, "wombat"=>2, "dog"=>1}, hash)
|
|
assert_equal([[1, 0], [[1, 2], 1]], Foo.new.each_with_index.to_a)
|
|
end
|
|
|
|
def test_each_with_object
|
|
obj = [0, 1]
|
|
ret = (1..10).each_with_object(obj) {|i, memo|
|
|
memo[0] += i
|
|
memo[1] *= i
|
|
}
|
|
assert_same(obj, ret)
|
|
assert_equal([55, 3628800], ret)
|
|
assert_equal([[1, nil], [[1, 2], nil]], Foo.new.each_with_object(nil).to_a)
|
|
end
|
|
|
|
def test_each_entry
|
|
assert_equal([1, 2, 3], [1, 2, 3].each_entry.to_a)
|
|
assert_equal([1, [1, 2]], Foo.new.each_entry.to_a)
|
|
a = []
|
|
cond = ->(x, i) { a << x }
|
|
@obj.each_with_index.each_entry(&cond)
|
|
assert_equal([1, 2, 3, 1, 2], a)
|
|
end
|
|
|
|
def test_each_slice
|
|
ary = []
|
|
(1..10).each_slice(3) {|a| ary << a}
|
|
assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary)
|
|
|
|
bug9749 = '[ruby-core:62060] [Bug #9749]'
|
|
ary.clear
|
|
(1..10).each_slice(3, &lambda {|a, *| ary << a})
|
|
assert_equal([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]], ary, bug9749)
|
|
|
|
ary.clear
|
|
(1..10).each_slice(10) {|a| ary << a}
|
|
assert_equal([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], ary)
|
|
|
|
ary.clear
|
|
(1..10).each_slice(11) {|a| ary << a}
|
|
assert_equal([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], ary)
|
|
end
|
|
|
|
def test_each_cons
|
|
ary = []
|
|
(1..5).each_cons(3) {|a| ary << a}
|
|
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary)
|
|
|
|
bug9749 = '[ruby-core:62060] [Bug #9749]'
|
|
ary.clear
|
|
(1..5).each_cons(3, &lambda {|a, *| ary << a})
|
|
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], ary, bug9749)
|
|
|
|
ary.clear
|
|
(1..5).each_cons(5) {|a| ary << a}
|
|
assert_equal([[1, 2, 3, 4, 5]], ary)
|
|
|
|
ary.clear
|
|
(1..5).each_cons(6) {|a| ary << a}
|
|
assert_empty(ary)
|
|
end
|
|
|
|
def test_zip
|
|
assert_equal([[1,1],[2,2],[3,3],[1,1],[2,2]], @obj.zip(@obj))
|
|
assert_equal([["a",1],["b",2],["c",3]], ["a", "b", "c"].zip(@obj))
|
|
|
|
a = []
|
|
result = @obj.zip([:a, :b, :c]) {|x,y| a << [x, y] }
|
|
assert_nil result
|
|
assert_equal([[1,:a],[2,:b],[3,:c],[1,nil],[2,nil]], a)
|
|
|
|
a = []
|
|
cond = ->((x, i), y) { a << [x, y, i] }
|
|
@obj.each_with_index.zip([:a, :b, :c], &cond)
|
|
assert_equal([[1,:a,0],[2,:b,1],[3,:c,2],[1,nil,3],[2,nil,4]], a)
|
|
|
|
a = []
|
|
@obj.zip({a: "A", b: "B", c: "C"}) {|x,y| a << [x, y] }
|
|
assert_equal([[1,[:a,"A"]],[2,[:b,"B"]],[3,[:c,"C"]],[1,nil],[2,nil]], a)
|
|
|
|
ary = Object.new
|
|
def ary.to_a; [1, 2]; end
|
|
assert_raise(TypeError) {%w(a b).zip(ary)}
|
|
def ary.each; [3, 4].each{|e|yield e}; end
|
|
assert_equal([[1, 3], [2, 4], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
|
|
def ary.to_ary; [5, 6]; end
|
|
assert_equal([[1, 5], [2, 6], [3, nil], [1, nil], [2, nil]], @obj.zip(ary))
|
|
obj = eval("class C\u{1f5ff}; self; end").new
|
|
assert_raise_with_message(TypeError, /C\u{1f5ff}/) {(1..1).zip(obj)}
|
|
end
|
|
|
|
def test_take
|
|
assert_equal([1,2,3], @obj.take(3))
|
|
end
|
|
|
|
def test_take_while
|
|
assert_equal([1,2], @obj.take_while {|x| x <= 2})
|
|
cond = ->(x, i) {x <= 2}
|
|
assert_equal([[1, 0], [2, 1]], @obj.each_with_index.take_while(&cond))
|
|
|
|
bug5801 = '[ruby-dev:45040]'
|
|
@empty.take_while {true}
|
|
block = @empty.block
|
|
assert_nothing_raised(bug5801) {100.times {block.call}}
|
|
end
|
|
|
|
def test_drop
|
|
assert_equal([3,1,2], @obj.drop(2))
|
|
end
|
|
|
|
def test_drop_while
|
|
assert_equal([3,1,2], @obj.drop_while {|x| x <= 2})
|
|
cond = ->(x, i) {x <= 2}
|
|
assert_equal([[3, 2], [1, 3], [2, 4]], @obj.each_with_index.drop_while(&cond))
|
|
end
|
|
|
|
def test_cycle
|
|
assert_equal([1,2,3,1,2,1,2,3,1,2], @obj.cycle.take(10))
|
|
a = []
|
|
@obj.cycle(2) {|x| a << x}
|
|
assert_equal([1,2,3,1,2,1,2,3,1,2], a)
|
|
a = []
|
|
cond = ->(x, i) {a << x}
|
|
@obj.each_with_index.cycle(2, &cond)
|
|
assert_equal([1,2,3,1,2,1,2,3,1,2], a)
|
|
end
|
|
|
|
def test_callcc
|
|
assert_raise(RuntimeError) do
|
|
c = nil
|
|
@obj.sort_by {|x| callcc {|c2| c ||= c2 }; x }
|
|
c.call
|
|
end
|
|
|
|
assert_raise(RuntimeError) do
|
|
c = nil
|
|
o = Object.new
|
|
class << o; self; end.class_eval do
|
|
define_method(:<=>) do |x|
|
|
callcc {|c2| c ||= c2 }
|
|
0
|
|
end
|
|
end
|
|
[o, o].sort_by {|x| x }
|
|
c.call
|
|
end
|
|
|
|
assert_raise(RuntimeError) do
|
|
c = nil
|
|
o = Object.new
|
|
class << o; self; end.class_eval do
|
|
define_method(:<=>) do |x|
|
|
callcc {|c2| c ||= c2 }
|
|
0
|
|
end
|
|
end
|
|
[o, o, o].sort_by {|x| x }
|
|
c.call
|
|
end
|
|
|
|
assert_raise_with_message(RuntimeError, /reentered/) do
|
|
i = 0
|
|
c = nil
|
|
o = Object.new
|
|
class << o; self; end.class_eval do
|
|
define_method(:<=>) do |x|
|
|
callcc {|c2| c ||= c2 }
|
|
i += 1
|
|
0
|
|
end
|
|
end
|
|
[o, o].min(1)
|
|
assert_operator(i, :<=, 5, "infinite loop")
|
|
c.call
|
|
end
|
|
end
|
|
|
|
def test_reverse_each
|
|
assert_equal([2,1,3,2,1], @obj.reverse_each.to_a)
|
|
end
|
|
|
|
def test_reverse_each_memory_corruption
|
|
bug16354 = '[ruby-dev:50867]'
|
|
assert_normal_exit %q{
|
|
size = 1000
|
|
(0...size).reverse_each do |i|
|
|
i.inspect
|
|
ObjectSpace.each_object(Array) do |a|
|
|
a.clear if a.length == size
|
|
end
|
|
end
|
|
}, bug16354
|
|
end
|
|
|
|
def test_chunk
|
|
e = [].chunk {|elt| true }
|
|
assert_equal([], e.to_a)
|
|
|
|
e = @obj.chunk {|elt| elt & 2 == 0 ? false : true }
|
|
assert_equal([[false, [1]], [true, [2, 3]], [false, [1]], [true, [2]]], e.to_a)
|
|
|
|
e = @obj.chunk {|elt| elt < 3 ? :_alone : true }
|
|
assert_equal([[:_alone, [1]],
|
|
[:_alone, [2]],
|
|
[true, [3]],
|
|
[:_alone, [1]],
|
|
[:_alone, [2]]], e.to_a)
|
|
|
|
e = @obj.chunk {|elt| elt == 3 ? :_separator : true }
|
|
assert_equal([[true, [1, 2]],
|
|
[true, [1, 2]]], e.to_a)
|
|
|
|
e = @obj.chunk {|elt| elt == 3 ? nil : true }
|
|
assert_equal([[true, [1, 2]],
|
|
[true, [1, 2]]], e.to_a)
|
|
|
|
e = @obj.chunk {|elt| :_foo }
|
|
assert_raise(RuntimeError) { e.to_a }
|
|
|
|
e = @obj.chunk.with_index {|elt, i| elt - i }
|
|
assert_equal([[1, [1, 2, 3]],
|
|
[-2, [1, 2]]], e.to_a)
|
|
|
|
assert_equal(4, (0..3).chunk.size)
|
|
end
|
|
|
|
def test_slice_before
|
|
e = [].slice_before {|elt| true }
|
|
assert_equal([], e.to_a)
|
|
|
|
e = @obj.slice_before {|elt| elt.even? }
|
|
assert_equal([[1], [2,3,1], [2]], e.to_a)
|
|
|
|
e = @obj.slice_before {|elt| elt.odd? }
|
|
assert_equal([[1,2], [3], [1,2]], e.to_a)
|
|
|
|
ss = %w[abc defg h ijk l mno pqr st u vw xy z]
|
|
assert_equal([%w[abc defg h], %w[ijk l], %w[mno], %w[pqr st u vw xy z]],
|
|
ss.slice_before(/\A...\z/).to_a)
|
|
assert_warning("") {ss.slice_before(/\A...\z/).to_a}
|
|
end
|
|
|
|
def test_slice_after0
|
|
assert_raise(ArgumentError) { [].slice_after }
|
|
end
|
|
|
|
def test_slice_after1
|
|
e = [].slice_after {|a| flunk "should not be called" }
|
|
assert_equal([], e.to_a)
|
|
|
|
e = [1,2].slice_after(1)
|
|
assert_equal([[1], [2]], e.to_a)
|
|
|
|
e = [1,2].slice_after(3)
|
|
assert_equal([[1, 2]], e.to_a)
|
|
|
|
[true, false].each {|b|
|
|
block_results = [true, b]
|
|
e = [1,2].slice_after {|a| block_results.shift }
|
|
assert_equal([[1], [2]], e.to_a)
|
|
assert_equal([], block_results)
|
|
|
|
block_results = [false, b]
|
|
e = [1,2].slice_after {|a| block_results.shift }
|
|
assert_equal([[1, 2]], e.to_a)
|
|
assert_equal([], block_results)
|
|
}
|
|
end
|
|
|
|
def test_slice_after_both_pattern_and_block
|
|
assert_raise(ArgumentError) { [].slice_after(1) {|a| true } }
|
|
end
|
|
|
|
def test_slice_after_continuation_lines
|
|
lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
|
|
e = lines.slice_after(/[^\\]\n\z/)
|
|
assert_equal([["foo\n"], ["bar\\\n", "baz\n"], ["\n", "qux\n"]], e.to_a)
|
|
end
|
|
|
|
def test_slice_before_empty_line
|
|
lines = ["foo", "", "bar"]
|
|
e = lines.slice_after(/\A\s*\z/)
|
|
assert_equal([["foo", ""], ["bar"]], e.to_a)
|
|
end
|
|
|
|
def test_slice_when_0
|
|
e = [].slice_when {|a, b| flunk "should not be called" }
|
|
assert_equal([], e.to_a)
|
|
end
|
|
|
|
def test_slice_when_1
|
|
e = [1].slice_when {|a, b| flunk "should not be called" }
|
|
assert_equal([[1]], e.to_a)
|
|
end
|
|
|
|
def test_slice_when_2
|
|
e = [1,2].slice_when {|a,b|
|
|
assert_equal(1, a)
|
|
assert_equal(2, b)
|
|
true
|
|
}
|
|
assert_equal([[1], [2]], e.to_a)
|
|
|
|
e = [1,2].slice_when {|a,b|
|
|
assert_equal(1, a)
|
|
assert_equal(2, b)
|
|
false
|
|
}
|
|
assert_equal([[1, 2]], e.to_a)
|
|
end
|
|
|
|
def test_slice_when_3
|
|
block_invocations = [
|
|
lambda {|a, b|
|
|
assert_equal(1, a)
|
|
assert_equal(2, b)
|
|
true
|
|
},
|
|
lambda {|a, b|
|
|
assert_equal(2, a)
|
|
assert_equal(3, b)
|
|
false
|
|
}
|
|
]
|
|
e = [1,2,3].slice_when {|a,b|
|
|
block_invocations.shift.call(a, b)
|
|
}
|
|
assert_equal([[1], [2, 3]], e.to_a)
|
|
assert_equal([], block_invocations)
|
|
end
|
|
|
|
def test_slice_when_noblock
|
|
assert_raise(ArgumentError) { [].slice_when }
|
|
end
|
|
|
|
def test_slice_when_contiguously_increasing_integers
|
|
e = [1,4,9,10,11,12,15,16,19,20,21].slice_when {|i, j| i+1 != j }
|
|
assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a)
|
|
end
|
|
|
|
def test_chunk_while_contiguously_increasing_integers
|
|
e = [1,4,9,10,11,12,15,16,19,20,21].chunk_while {|i, j| i+1 == j }
|
|
assert_equal([[1], [4], [9,10,11,12], [15,16], [19,20,21]], e.to_a)
|
|
end
|
|
|
|
def test_detect
|
|
@obj = ('a'..'z')
|
|
assert_equal('c', @obj.detect {|x| x == 'c' })
|
|
|
|
proc = Proc.new {|x| x == 'c' }
|
|
assert_equal('c', @obj.detect(&proc))
|
|
|
|
lambda = ->(x) { x == 'c' }
|
|
assert_equal('c', @obj.detect(&lambda))
|
|
|
|
assert_equal(['c',2], @obj.each_with_index.detect {|x, i| x == 'c' })
|
|
|
|
proc2 = Proc.new {|x, i| x == 'c' }
|
|
assert_equal(['c',2], @obj.each_with_index.detect(&proc2))
|
|
|
|
bug9605 = '[ruby-core:61340]'
|
|
lambda2 = ->(x, i) { x == 'c' }
|
|
assert_equal(['c',2], @obj.each_with_index.detect(&lambda2), bug9605)
|
|
end
|
|
|
|
def test_select
|
|
@obj = ('a'..'z')
|
|
assert_equal(['c'], @obj.select {|x| x == 'c' })
|
|
|
|
proc = Proc.new {|x| x == 'c' }
|
|
assert_equal(['c'], @obj.select(&proc))
|
|
|
|
lambda = ->(x) { x == 'c' }
|
|
assert_equal(['c'], @obj.select(&lambda))
|
|
|
|
assert_equal([['c',2]], @obj.each_with_index.select {|x, i| x == 'c' })
|
|
|
|
proc2 = Proc.new {|x, i| x == 'c' }
|
|
assert_equal([['c',2]], @obj.each_with_index.select(&proc2))
|
|
|
|
bug9605 = '[ruby-core:61340]'
|
|
lambda2 = ->(x, i) { x == 'c' }
|
|
assert_equal([['c',2]], @obj.each_with_index.select(&lambda2), bug9605)
|
|
end
|
|
|
|
def test_map
|
|
@obj = ('a'..'e')
|
|
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map {|x| x.upcase })
|
|
|
|
proc = Proc.new {|x| x.upcase }
|
|
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&proc))
|
|
|
|
lambda = ->(x) { x.upcase }
|
|
assert_equal(['A', 'B', 'C', 'D', 'E'], @obj.map(&lambda))
|
|
|
|
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
|
|
@obj.each_with_index.map {|x, i| [x.upcase, i] })
|
|
|
|
proc2 = Proc.new {|x, i| [x.upcase, i] }
|
|
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
|
|
@obj.each_with_index.map(&proc2))
|
|
|
|
lambda2 = ->(x, i) { [x.upcase, i] }
|
|
assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
|
|
@obj.each_with_index.map(&lambda2))
|
|
|
|
hash = { a: 'hoge', b: 'fuga' }
|
|
lambda = -> (k, v) { "#{k}:#{v}" }
|
|
assert_equal ["a:hoge", "b:fuga"], hash.map(&lambda)
|
|
end
|
|
|
|
def test_flat_map
|
|
@obj = [[1,2], [3,4]]
|
|
assert_equal([2,4,6,8], @obj.flat_map {|i| i.map{|j| j*2} })
|
|
|
|
proc = Proc.new {|i| i.map{|j| j*2} }
|
|
assert_equal([2,4,6,8], @obj.flat_map(&proc))
|
|
|
|
lambda = ->(i) { i.map{|j| j*2} }
|
|
assert_equal([2,4,6,8], @obj.flat_map(&lambda))
|
|
|
|
assert_equal([[1,2],0,[3,4],1],
|
|
@obj.each_with_index.flat_map {|x, i| [x,i] })
|
|
|
|
proc2 = Proc.new {|x, i| [x,i] }
|
|
assert_equal([[1,2],0,[3,4],1],
|
|
@obj.each_with_index.flat_map(&proc2))
|
|
|
|
lambda2 = ->(x, i) { [x,i] }
|
|
assert_equal([[1,2],0,[3,4],1],
|
|
@obj.each_with_index.flat_map(&lambda2))
|
|
end
|
|
|
|
def assert_typed_equal(e, v, cls, msg=nil)
|
|
assert_kind_of(cls, v, msg)
|
|
assert_equal(e, v, msg)
|
|
end
|
|
|
|
def assert_int_equal(e, v, msg=nil)
|
|
assert_typed_equal(e, v, Integer, msg)
|
|
end
|
|
|
|
def assert_rational_equal(e, v, msg=nil)
|
|
assert_typed_equal(e, v, Rational, msg)
|
|
end
|
|
|
|
def assert_float_equal(e, v, msg=nil)
|
|
assert_typed_equal(e, v, Float, msg)
|
|
end
|
|
|
|
def assert_complex_equal(e, v, msg=nil)
|
|
assert_typed_equal(e, v, Complex, msg)
|
|
end
|
|
|
|
def test_sum
|
|
class << (enum = Object.new)
|
|
include Enumerable
|
|
def each
|
|
yield 3
|
|
yield 5
|
|
yield 7
|
|
end
|
|
end
|
|
assert_int_equal(15, enum.sum)
|
|
|
|
assert_int_equal(0, [].each.sum)
|
|
assert_int_equal(3, [3].each.sum)
|
|
assert_int_equal(8, [3, 5].each.sum)
|
|
assert_int_equal(15, [3, 5, 7].each.sum)
|
|
assert_rational_equal(8r, [3, 5r].each.sum)
|
|
assert_float_equal(15.0, [3, 5, 7.0].each.sum)
|
|
assert_float_equal(15.0, [3, 5r, 7.0].each.sum)
|
|
assert_complex_equal(8r + 1i, [3, 5r, 1i].each.sum)
|
|
assert_complex_equal(15.0 + 1i, [3, 5r, 7.0, 1i].each.sum)
|
|
|
|
assert_int_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).each.sum)
|
|
assert_int_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).each.sum)
|
|
assert_int_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).each.sum)
|
|
assert_int_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).each.sum)
|
|
assert_int_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).each.sum)
|
|
assert_int_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).each.sum)
|
|
|
|
assert_float_equal(0.0, [].each.sum(0.0))
|
|
assert_float_equal(3.0, [3].each.sum(0.0))
|
|
assert_float_equal(3.5, [3].each.sum(0.5))
|
|
assert_float_equal(8.5, [3.5, 5].each.sum)
|
|
assert_float_equal(10.5, [2, 8.5].each.sum)
|
|
assert_float_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].each.sum)
|
|
assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].each.sum)
|
|
|
|
assert_rational_equal(3/2r, [1/2r, 1].each.sum)
|
|
assert_rational_equal(5/6r, [1/2r, 1/3r].each.sum)
|
|
|
|
assert_equal(2.0+3.0i, [2.0, 3.0i].each.sum)
|
|
|
|
assert_int_equal(13, [1, 2].each.sum(10))
|
|
assert_int_equal(16, [1, 2].each.sum(10) {|v| v * 2 })
|
|
|
|
yielded = []
|
|
three = SimpleDelegator.new(3)
|
|
ary = [1, 2.0, three]
|
|
assert_float_equal(12.0, ary.each.sum {|x| yielded << x; x * 2 })
|
|
assert_equal(ary, yielded)
|
|
|
|
assert_raise(TypeError) { [Object.new].each.sum }
|
|
|
|
large_number = 100000000
|
|
small_number = 1e-9
|
|
until (large_number + small_number) == large_number
|
|
small_number /= 10
|
|
end
|
|
assert_float_equal(large_number+(small_number*10), [large_number, *[small_number]*10].each.sum)
|
|
assert_float_equal(large_number+(small_number*10), [large_number/1r, *[small_number]*10].each.sum)
|
|
assert_float_equal(large_number+(small_number*11), [small_number, large_number/1r, *[small_number]*10].each.sum)
|
|
assert_float_equal(small_number, [large_number, small_number, -large_number].each.sum)
|
|
|
|
k = Class.new do
|
|
include Enumerable
|
|
def initialize(*values)
|
|
@values = values
|
|
end
|
|
def each(&block)
|
|
@values.each(&block)
|
|
end
|
|
end
|
|
assert_equal(+Float::INFINITY, k.new(0.0, +Float::INFINITY).sum)
|
|
assert_equal(+Float::INFINITY, k.new(+Float::INFINITY, 0.0).sum)
|
|
assert_equal(-Float::INFINITY, k.new(0.0, -Float::INFINITY).sum)
|
|
assert_equal(-Float::INFINITY, k.new(-Float::INFINITY, 0.0).sum)
|
|
assert_predicate(k.new(-Float::INFINITY, Float::INFINITY).sum, :nan?)
|
|
|
|
assert_equal("abc", ["a", "b", "c"].each.sum(""))
|
|
assert_equal([1, [2], 3], [[1], [[2]], [3]].each.sum([]))
|
|
end
|
|
|
|
def test_hash_sum
|
|
histogram = { 1 => 6, 2 => 4, 3 => 3, 4 => 7, 5 => 5, 6 => 4 }
|
|
assert_equal(100, histogram.sum {|v, n| v * n })
|
|
end
|
|
|
|
def test_range_sum
|
|
assert_int_equal(55, (1..10).sum)
|
|
assert_float_equal(55.0, (1..10).sum(0.0))
|
|
assert_int_equal(90, (5..10).sum {|v| v * 2 })
|
|
assert_float_equal(90.0, (5..10).sum(0.0) {|v| v * 2 })
|
|
assert_int_equal(0, (2..0).sum)
|
|
assert_int_equal(5, (2..0).sum(5))
|
|
assert_int_equal(2, (2..2).sum)
|
|
assert_int_equal(42, (2...2).sum(42))
|
|
|
|
not_a_range = Class.new do
|
|
include Enumerable # Defines the `#sum` method
|
|
def each
|
|
yield 2
|
|
yield 4
|
|
yield 6
|
|
end
|
|
|
|
def begin; end
|
|
def end; end
|
|
end
|
|
assert_equal(12, not_a_range.new.sum)
|
|
end
|
|
|
|
def test_uniq
|
|
src = [1, 1, 1, 1, 2, 2, 3, 4, 5, 6]
|
|
assert_equal([1, 2, 3, 4, 5, 6], src.uniq.to_a)
|
|
olympics = {
|
|
1896 => 'Athens',
|
|
1900 => 'Paris',
|
|
1904 => 'Chicago',
|
|
1906 => 'Athens',
|
|
1908 => 'Rome',
|
|
}
|
|
assert_equal([[1896, "Athens"], [1900, "Paris"], [1904, "Chicago"], [1908, "Rome"]],
|
|
olympics.uniq{|k,v| v})
|
|
assert_equal([1, 2, 3, 4, 5, 10], (1..100).uniq{|x| (x**2) % 10 }.first(6))
|
|
assert_equal([1, [1, 2]], Foo.new.to_enum.uniq)
|
|
end
|
|
|
|
def test_transient_heap_sort_by
|
|
klass = Class.new do
|
|
include Comparable
|
|
attr_reader :i
|
|
def initialize e
|
|
@i = e
|
|
end
|
|
def <=> other
|
|
GC.start
|
|
i <=> other.i
|
|
end
|
|
end
|
|
assert_equal [1, 2, 3, 4, 5], (1..5).sort_by{|e| klass.new e}
|
|
end
|
|
|
|
def test_filter_map
|
|
@obj = (1..8).to_a
|
|
assert_equal([4, 8, 12, 16], @obj.filter_map { |i| i * 2 if i.even? })
|
|
assert_equal([2, 4, 6, 8, 10, 12, 14, 16], @obj.filter_map { |i| i * 2 })
|
|
assert_equal([0, 0, 0, 0, 0, 0, 0, 0], @obj.filter_map { 0 })
|
|
assert_equal([], @obj.filter_map { false })
|
|
assert_equal([], @obj.filter_map { nil })
|
|
assert_instance_of(Enumerator, @obj.filter_map)
|
|
end
|
|
end
|