Skip to content

Commit 4a5c504

Browse files
tsymbalenkovladkou
andauthored
Support block in CSV::Row#to_h (#356)
It will be consistent with Ruby's method, otherwise it has to be like `row.entries.to_h { ... }` --------- Co-authored-by: Sutou Kouhei <kou@cozmixng.org>
1 parent bc69827 commit 4a5c504

2 files changed

Lines changed: 49 additions & 2 deletions

File tree

lib/csv/row.rb

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ def ==(other)
637637

638638
# :call-seq:
639639
# row.to_h -> hash
640+
# row.to_h {|key, value| ... } -> hash
640641
#
641642
# Returns the new \Hash formed by adding each header-value pair in +self+
642643
# as a key-value pair in the \Hash.
@@ -650,11 +651,34 @@ def ==(other)
650651
# table = CSV.parse(source, headers: true)
651652
# row = table[0]
652653
# row.to_h # => {"Name"=>"Foo"}
654+
#
655+
# If a block is given, will call it with (key, value) arguments and use result as a hash entry:
656+
# source = "Name,Value\nfoo,1\nbar,2\nbaz,3\n"
657+
# table = CSV.parse(source, headers: true)
658+
# row = table[0]
659+
# row.to_h { |key, value| [key, "#{key}-#{value}"] } # => {"Name"=>"Name-foo", "Value"=>"Value-1"}
653660
def to_h
654661
hash = {}
655-
each do |key, _value|
656-
hash[key] = self[key] unless hash.key?(key)
662+
663+
if block_given?
664+
each do |key, _value|
665+
result = yield(key, self[key])
666+
result_array = Array.try_convert(result)
667+
raise TypeError, "wrong element type #{result.class} (expected array)" if result_array.nil?
668+
raise ArgumentError, "wrong array length (expected 2, was #{result_array.size})" unless result_array.size == 2
669+
670+
key, value = result_array
671+
next if hash.key?(key)
672+
673+
key.freeze if key.is_a?(String) && !key.frozen?
674+
hash[key] = value
675+
end
676+
else
677+
each do |key, _value|
678+
hash[key] = self[key] unless hash.key?(key)
679+
end
657680
end
681+
658682
hash
659683
end
660684
alias_method :to_hash, :to_h

test/csv/test_row.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,29 @@ def test_to_hash
341341
end
342342
end
343343

344+
def test_to_hash_with_block_transform_values
345+
hash = @row.to_hash { |k, v| [k, v**2] }
346+
assert_equal({"A" => 1, "B" => 4, "C" => 9}, hash)
347+
hash.each_key do |string_key|
348+
assert_predicate(string_key, :frozen?)
349+
end
350+
assert_raise TypeError do
351+
@row.to_hash { "foo" }
352+
end
353+
assert_raise ArgumentError do
354+
@row.to_hash { [1] }
355+
end
356+
end
357+
358+
def test_to_hash_with_block_transform_entries
359+
new_keys_map = {"A" => "A", "B" => "B", "C" => "B"}
360+
hash = @row.to_hash { |k, v| [new_keys_map[k], v**2] }
361+
assert_equal({"A" => 1, "B" => 4}, hash)
362+
hash.each_key do |string_key|
363+
assert_predicate(string_key, :frozen?)
364+
end
365+
end
366+
344367
def test_to_csv
345368
# normal conversion
346369
assert_equal("1,2,3,4,\n", @row.to_csv)

0 commit comments

Comments
 (0)