I have made a CSV parser, and when I come to refactoring the rows method I am getting a closed stream error, can someone explain what I have done wrong please?
before the refactoring (this works):
class CSVParser
def initialize(csv_file)
@csv_file = csv_file
end
def rows
rows = []
CSV.foreach(@csv_file.path, headers: true) do |row|
rows << row.to_hash
end
rows
end
end
after re factoring(this is causing the error):
class CSVParser
def initialize(csv_file)
@csv_file = csv_file
end
def rows
CSV.foreach(@csv_file.path, headers: true).map{|row| row.to_hash}
end
end
Lets take a look at the source of #foreach - found here
def self.foreach(path, options = Hash.new, &block)
open(path, options) do |csv|
csv.each(&block)
end
end
The enumerator is unfortunately locked within the open method. The open method returns nil which why you cannot call enumerable methods like you would expect (#map for example ).
I’ve run into this before and was super frustrated as well. Fortunately Ruby 2.1.0 seems to have changed the implementation. It will return an enumerator unless a block is provided.
def self.foreach(path, options = Hash.new, &block)
return to_enum(__method__, path, options) unless block
open(path, options) do |csv|
csv.each(&block)
end
end