Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: JRuby 1.6.1, JRuby 1.6.2
-
Fix Version/s: JRuby 1.6.3
-
Component/s: Core Classes/Modules
-
Labels:None
-
Number of attachments :
Description
This only occurs in --1.9 mode.
Observed:
If #each is overridden on a Hash and yields the (key, value) tuple as expanded arguments, then Enumerable#map only yields the key to the block given to it. If #each yields (key, value) as an array, Enumerable#map yields the key and value.
Expected:
I would expect #map to be happy with either argument form, since MRI 1.9 allows either.
Steps to reproduce:
class BadHash < Hash
def each
super do |k, v|
yield(k,v)
end
end
end
class GoodHash < Hash
def each
super do |k, v|
yield([k,v])
end
end
end
[BadHash, GoodHash].each do |klass|
hash = klass.new
hash['a'] = 'b'
hash.map do |k,v|
puts "#{klass.name}: #{k} => #{v}"
end
end
Results with various jruby/ruby versions:
$ ruby -v jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use jruby-1.6.2 info: Using jruby 1.6.2 $ ruby -v jruby 1.6.2 (ruby-1.8.7-p330) (2011-05-23 e2ea975) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.9.1 info: Using ruby 1.9.1 p378 $ ruby -v ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.4.0] $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.8.7 info: Using ruby 1.8.7 p299 $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b
This currently affects rack v1.3.0 headers - it overrides #each in HeaderHash, then uses map to convert back to a hash, losing the header values:
(from https://github.com/rack/rack/blob/1.3.0/lib/rack/utils.rb#L336):
def each
super do |k, v|
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
end
end
def to_hash
Hash[*map do |k, v|
[k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v]
end.flatten]
end
Issue Links
- relates to
-
JRUBY-5878
Enumerator.map is not yielding all values
-
Activity
| Field | Original Value | New Value |
|---|---|---|
| Description |
This only occurs in --1.9 mode.
Observed: If #each is overridden on a Hash and yields the (key, value) tuple as expanded arguments, then Enumerable#map only yields the key to the block given to it. If #each yields (key, value) as an array, Enumerable#map yields the key and value. Expected: I would expect #map to be happy with either argument form, since MRI 1.9 allows either. Steps to reproduce: {preformat} class BadHash < Hash def each super do |k, v| yield(k,v) end end end class GoodHash < Hash def each super do |k, v| yield([k,v]) end end end [BadHash, GoodHash].each do |klass| hash = klass.new hash['a'] = 'b' hash.map do |k,v| puts "#{klass.name}: #{k} => #{v}" end end {preformat} Results with various jruby/ruby versions: {preformat} $ ruby -v jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use jruby-1.6.2 info: Using jruby 1.6.2 $ ruby -v jruby 1.6.2 (ruby-1.8.7-p330) (2011-05-23 e2ea975) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.9.1 info: Using ruby 1.9.1 p378 $ ruby -v ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.4.0] $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.8.7 info: Using ruby 1.8.7 p299 $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b {preformat} This currently affects rack v1.3.0 headers - it overrides #each in HeaderHash, then uses map to convert back to a hash, losing the header values: (from https://github.com/rack/rack/blob/1.3.0/lib/rack/utils.rb#L336): {preformat} def each super do |k, v| yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v) end end def to_hash Hash[*map do |k, v| [k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v] end.flatten] end {preformat} |
This only occurs in --1.9 mode.
Observed: If #each is overridden on a Hash and yields the (key, value) tuple as expanded arguments, then Enumerable#map only yields the key to the block given to it. If #each yields (key, value) as an array, Enumerable#map yields the key and value. Expected: I would expect #map to be happy with either argument form, since MRI 1.9 allows either. Steps to reproduce: {noformat} class BadHash < Hash def each super do |k, v| yield(k,v) end end end class GoodHash < Hash def each super do |k, v| yield([k,v]) end end end [BadHash, GoodHash].each do |klass| hash = klass.new hash['a'] = 'b' hash.map do |k,v| puts "#{klass.name}: #{k} => #{v}" end end {noformat} Results with various jruby/ruby versions: {noformat} $ ruby -v jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use jruby-1.6.2 info: Using jruby 1.6.2 $ ruby -v jruby 1.6.2 (ruby-1.8.7-p330) (2011-05-23 e2ea975) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_24) [darwin-x86_64-java] $ ruby --1.9 tmp/hash_each.rb BadHash: a => GoodHash: a => b $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.9.1 info: Using ruby 1.9.1 p378 $ ruby -v ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.4.0] $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b $ rvm use ruby-1.8.7 info: Using ruby 1.8.7 p299 $ ruby tmp/hash_each.rb BadHash: a => b GoodHash: a => b {noformat} This currently affects rack v1.3.0 headers - it overrides #each in HeaderHash, then uses map to convert back to a hash, losing the header values: (from https://github.com/rack/rack/blob/1.3.0/lib/rack/utils.rb#L336): {noformat} def each super do |k, v| yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v) end end def to_hash Hash[*map do |k, v| [k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v] end.flatten] end {noformat} |
| Assignee | Charles Oliver Nutter [ headius ] |
| Status | Open [ 1 ] | In Progress [ 3 ] |
| Status | In Progress [ 3 ] | Resolved [ 5 ] |
| Fix Version/s | JRuby 1.6.3 [ 17374 ] | |
| Resolution | Fixed [ 1 ] |
| Link |
This issue relates to |
| Status | Resolved [ 5 ] | Closed [ 6 ] |
The script to reproduce is also available at https://gist.github.com/1002147, since I screwed up the formatting of the description, and don't have rights to edit it.