2007/3/9 said:
Hello,
I am writing a class and I require it to open a file, and store the
contents in key, value pairs.
This is my first
def initialize()
@@store = Hash.new
end
def read_file
if File.exists?("LocationCopy.csv")
f = File.open("LocationCopy.csv","r")
f.each do |line|
temp = line.split(",")
@@store[temp[0]] = temp[1]
end
f.close
end
#puts @@store
end
Unfortunately thats what I call finger trouble, as I was saying this
is my first attempt at a Ruby application and was wondering if there
is a more efficient method for what I am trying to achieve. Would
using f.each_line and using a block be better?
Efficiency is ok. Using the block form of File.open is safer, i.e.
the file is always closed - even in case of error. But you should not
use a class variable, use @store instead.
And you can make your life easier by using CSV lib. Then it becomes a
one liner:
10:41:07 [~]: cat x
a,b
d,b;c
10:41:08 [~]: ruby -r csv -r enumerator -e 'p CSV.to_enum
open, "x",
"r", ";").inject({}) {|h,(k,v)| h[k]=v; h}'
{"a,b"=>nil, "d,b"=>"c"}
10:41:32 [~]: ruby -r csv -r enumerator -e 'p CSV.to_enum
open, "x",
"r", ",").inject({}) {|h,(k,v)| h[k]=v; h}'
{"a"=>"b", "d"=>"b;c"}
CSV.foreach uses "," as default separator:
10:41:49 [~]: ruby -r csv -r enumerator -e 'p CSV.to_enum
foreach,
"x").inject({}) {|h,(k,v)| h[k]=v; h}'
{"a"=>"b", "d"=>"b;c"}
Explanation: CSV.foreach yiels every record to the block. By using
to_enum (which is part of "enumerator") you can treat the CSV reader
like any Enumerable. With #inhect, a value is passed as first
parameter to the block and the block result is passed to the next
invocation to the block. In this case the hash which is stuffed into
#inject is simply passed on and on and is ultimately the result of
#inject. "p" then prints it.
Kind regards
robert