зеркало из https://github.com/github/ruby.git
Make product consistently yield an array of N elements instead of N arguments
Inconsistency pointed out by @mame: ``` >> Enumerator.product([1], [2], [3]).to_a => [[1, 2, 3]] >> Enumerator.product([1], [2]).to_a => [[1, 2]] >> Enumerator.product([1]).to_a => [1] >> Enumerator.product().to_a => [nil] ``` Got fixed as follows: ``` >> Enumerator.product([1], [2], [3]).to_a => [[1, 2, 3]] >> Enumerator.product([1], [2]).to_a => [[1, 2]] >> Enumerator.product([1]).to_a => [[1]] >> Enumerator.product().to_a => [[]] ``` This was due to the nature of the N-argument funcall in Ruby.
This commit is contained in:
Родитель
684fa46ee6
Коммит
308ccbaeb2
|
@ -3434,7 +3434,7 @@ enumerator_plus(VALUE obj, VALUE eobj)
|
|||
*
|
||||
* The method used against each enumerable object is `each_entry`
|
||||
* instead of `each` so that the product of N enumerable objects
|
||||
* yields exactly N arguments in each iteration.
|
||||
* yields an array of exactly N elements in each iteration.
|
||||
*
|
||||
* When no enumerator is given, it calls a given block once yielding
|
||||
* an empty argument list.
|
||||
|
@ -3627,7 +3627,7 @@ product_each(VALUE obj, struct product_state *pstate)
|
|||
rb_block_call(eobj, id_each_entry, 0, NULL, product_each_i, (VALUE)pstate);
|
||||
}
|
||||
else {
|
||||
rb_funcallv(pstate->block, id_call, pstate->argc, pstate->argv);
|
||||
rb_funcall(pstate->block, id_call, 1, rb_ary_new_from_values(pstate->argc, pstate->argv));
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
|
|
@ -908,46 +908,82 @@ class TestEnumerator < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_product
|
||||
##
|
||||
## Enumerator::Product
|
||||
##
|
||||
|
||||
# 0-dimensional
|
||||
e = Enumerator::Product.new
|
||||
assert_instance_of(Enumerator::Product, e)
|
||||
assert_kind_of(Enumerator, e)
|
||||
assert_equal(1, e.size)
|
||||
elts = []
|
||||
e.each { |*x| elts << x }
|
||||
e.each { |x| elts << x }
|
||||
assert_equal [[]], elts
|
||||
assert_equal elts, e.to_a
|
||||
heads = []
|
||||
e.each { |x,| heads << x }
|
||||
assert_equal [nil], heads
|
||||
|
||||
# 1-dimensional
|
||||
e = Enumerator::Product.new(1..3)
|
||||
assert_instance_of(Enumerator::Product, e)
|
||||
assert_kind_of(Enumerator, e)
|
||||
assert_equal(3, e.size)
|
||||
elts = []
|
||||
e.each { |x| elts << x }
|
||||
assert_equal [[1], [2], [3]], elts
|
||||
assert_equal elts, e.to_a
|
||||
|
||||
# 2-dimensional
|
||||
e = Enumerator::Product.new(1..3, %w[a b])
|
||||
assert_instance_of(Enumerator::Product, e)
|
||||
assert_kind_of(Enumerator, e)
|
||||
assert_equal(3 * 2, e.size)
|
||||
elts = []
|
||||
e.each { |*x| elts << x }
|
||||
e.each { |x| elts << x }
|
||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]], elts
|
||||
assert_equal elts, e.to_a
|
||||
heads = []
|
||||
e.each { |x,| heads << x }
|
||||
assert_equal [1, 1, 2, 2, 3, 3], heads
|
||||
|
||||
# Reject keyword arguments
|
||||
assert_raise(ArgumentError) {
|
||||
Enumerator::Product.new(1..3, foo: 1, bar: 2)
|
||||
}
|
||||
|
||||
##
|
||||
## Enumerator.product
|
||||
##
|
||||
|
||||
# without a block
|
||||
e = Enumerator.product(1..3, %w[a b])
|
||||
assert_instance_of(Enumerator::Product, e)
|
||||
|
||||
# with a block
|
||||
elts = []
|
||||
ret = Enumerator.product(1..3, %w[a b]) { |*x| elts << x }
|
||||
ret = Enumerator.product(1..3) { |x| elts << x }
|
||||
assert_instance_of(Enumerator::Product, ret)
|
||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]], elts
|
||||
assert_equal [[1], [2], [3]], elts
|
||||
assert_equal elts, Enumerator.product(1..3).to_a
|
||||
|
||||
# an infinite enumerator and a finite enumerable
|
||||
e = Enumerator.product(1.., 'a'..'c')
|
||||
assert_equal(Float::INFINITY, e.size)
|
||||
assert_equal [[1, "a"], [1, "b"], [1, "c"], [2, "a"]], e.take(4)
|
||||
|
||||
# an infinite enumerator and an unknown enumerator
|
||||
e = Enumerator.product(1.., Enumerator.new { |y| y << 'a' << 'b' })
|
||||
assert_equal(Float::INFINITY, e.size)
|
||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4)
|
||||
|
||||
# an infinite enumerator and an unknown enumerator
|
||||
e = Enumerator.product(1..3, Enumerator.new { |y| y << 'a' << 'b' })
|
||||
assert_equal(nil, e.size)
|
||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4)
|
||||
|
||||
# Reject keyword arguments
|
||||
assert_raise(ArgumentError) {
|
||||
Enumerator.product(1..3, foo: 1, bar: 2)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче