Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions lib/csv/row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ def ==(other)

# :call-seq:
# row.to_h -> hash
# row.to_h {|key, value| ... } -> hash
#
# Returns the new \Hash formed by adding each header-value pair in +self+
# as a key-value pair in the \Hash.
Expand All @@ -650,11 +651,34 @@ def ==(other)
# table = CSV.parse(source, headers: true)
# row = table[0]
# row.to_h # => {"Name"=>"Foo"}
#
# If a block is given, will call it with (key, value) arguments and use result as a hash entry:
# source = "Name,Value\nfoo,1\nbar,2\nbaz,3\n"
# table = CSV.parse(source, headers: true)
# row = table[0]
# row.to_h { |key, value| [key, "#{key}-#{value}"] } # => {"Name"=>"Name-foo", "Value"=>"Value-1"}
def to_h
hash = {}
each do |key, _value|
hash[key] = self[key] unless hash.key?(key)

if block_given?
each do |key, _value|
result = yield(key, self[key])
result_array = Array.try_convert(result)
raise TypeError, "wrong element type #{result.class} (expected array)" if result_array.nil?
raise ArgumentError, "wrong array length (expected 2, was #{result_array.size})" unless result_array.size == 2

key, value = result_array
next if hash.key?(key)

key.freeze if key.is_a?(String) && !key.frozen?
hash[key] = value
end
Comment on lines +663 to +675
Comment on lines +663 to +675
else
each do |key, _value|
hash[key] = self[key] unless hash.key?(key)
end
Comment on lines +677 to +679
end

hash
end
alias_method :to_hash, :to_h
Expand Down
23 changes: 23 additions & 0 deletions test/csv/test_row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,29 @@ def test_to_hash
end
end

def test_to_hash_with_block_transform_values
hash = @row.to_hash { |k, v| [k, v**2] }
assert_equal({"A" => 1, "B" => 4, "C" => 9}, hash)
hash.each_key do |string_key|
assert_predicate(string_key, :frozen?)
end
assert_raise TypeError do
@row.to_hash { "foo" }
end
assert_raise ArgumentError do
@row.to_hash { [1] }
end
end

def test_to_hash_with_block_transform_entries
new_keys_map = {"A" => "A", "B" => "B", "C" => "B"}
hash = @row.to_hash { |k, v| [new_keys_map[k], v**2] }
assert_equal({"A" => 1, "B" => 4}, hash)
hash.each_key do |string_key|
assert_predicate(string_key, :frozen?)
end
end

def test_to_csv
# normal conversion
assert_equal("1,2,3,4,\n", @row.to_csv)
Expand Down
Loading