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:
parent
684fa46ee6
commit
308ccbaeb2
@ -3434,7 +3434,7 @@ enumerator_plus(VALUE obj, VALUE eobj)
|
|||||||
*
|
*
|
||||||
* The method used against each enumerable object is `each_entry`
|
* The method used against each enumerable object is `each_entry`
|
||||||
* instead of `each` so that the product of N enumerable objects
|
* 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
|
* When no enumerator is given, it calls a given block once yielding
|
||||||
* an empty argument list.
|
* 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);
|
rb_block_call(eobj, id_each_entry, 0, NULL, product_each_i, (VALUE)pstate);
|
||||||
}
|
}
|
||||||
else {
|
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;
|
return obj;
|
||||||
|
@ -908,46 +908,82 @@ class TestEnumerator < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_product
|
def test_product
|
||||||
|
##
|
||||||
|
## Enumerator::Product
|
||||||
|
##
|
||||||
|
|
||||||
|
# 0-dimensional
|
||||||
e = Enumerator::Product.new
|
e = Enumerator::Product.new
|
||||||
assert_instance_of(Enumerator::Product, e)
|
assert_instance_of(Enumerator::Product, e)
|
||||||
assert_kind_of(Enumerator, e)
|
assert_kind_of(Enumerator, e)
|
||||||
assert_equal(1, e.size)
|
assert_equal(1, e.size)
|
||||||
elts = []
|
elts = []
|
||||||
e.each { |*x| elts << x }
|
e.each { |x| elts << x }
|
||||||
assert_equal [[]], elts
|
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])
|
e = Enumerator::Product.new(1..3, %w[a b])
|
||||||
assert_instance_of(Enumerator::Product, e)
|
assert_instance_of(Enumerator::Product, e)
|
||||||
assert_kind_of(Enumerator, e)
|
assert_kind_of(Enumerator, e)
|
||||||
assert_equal(3 * 2, e.size)
|
assert_equal(3 * 2, e.size)
|
||||||
elts = []
|
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 [[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) {
|
assert_raise(ArgumentError) {
|
||||||
Enumerator::Product.new(1..3, foo: 1, bar: 2)
|
Enumerator::Product.new(1..3, foo: 1, bar: 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
## Enumerator.product
|
||||||
|
##
|
||||||
|
|
||||||
|
# without a block
|
||||||
e = Enumerator.product(1..3, %w[a b])
|
e = Enumerator.product(1..3, %w[a b])
|
||||||
assert_instance_of(Enumerator::Product, e)
|
assert_instance_of(Enumerator::Product, e)
|
||||||
|
|
||||||
|
# with a block
|
||||||
elts = []
|
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_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')
|
e = Enumerator.product(1.., 'a'..'c')
|
||||||
assert_equal(Float::INFINITY, e.size)
|
assert_equal(Float::INFINITY, e.size)
|
||||||
assert_equal [[1, "a"], [1, "b"], [1, "c"], [2, "a"]], e.take(4)
|
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' })
|
e = Enumerator.product(1.., Enumerator.new { |y| y << 'a' << 'b' })
|
||||||
assert_equal(Float::INFINITY, e.size)
|
assert_equal(Float::INFINITY, e.size)
|
||||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4)
|
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' })
|
e = Enumerator.product(1..3, Enumerator.new { |y| y << 'a' << 'b' })
|
||||||
assert_equal(nil, e.size)
|
assert_equal(nil, e.size)
|
||||||
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4)
|
assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4)
|
||||||
|
|
||||||
|
# Reject keyword arguments
|
||||||
assert_raise(ArgumentError) {
|
assert_raise(ArgumentError) {
|
||||||
Enumerator.product(1..3, foo: 1, bar: 2)
|
Enumerator.product(1..3, foo: 1, bar: 2)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user