require "spec" require "csv" private def new_csv(headers = false, strip = false) CSV.new %(one, two\n1, 2\n3, 4\n5), headers: headers, strip: strip end describe CSV do it "gets headers" do csv = new_csv headers: true csv.headers.should eq(%w(one two)) end it "works without headers" do csv = CSV.new("", headers: true) csv.headers.should be_empty end it "raises if trying to access before first row" do csv = new_csv headers: true expect_raises(CSV::Error, "Before first row") do csv["one"] end end it "gets row values with string" do csv = new_csv headers: true csv.next.should be_true csv["one"].should eq("1") csv["two"].should eq(" 2") expect_raises(KeyError) { csv["three"] } csv["one"]?.should eq("1") csv["three"]?.should be_nil csv.next.should be_true csv["one"].should eq("3") csv.next.should be_true csv["one"].should eq("5") csv["two"].should eq("") csv.next.should be_false expect_raises(CSV::Error, "After last row") do csv["one"] end end it "gets row values with integer" do csv = new_csv headers: true csv.next.should be_true csv[0].should eq("1") csv[1].should eq(" 2") expect_raises(IndexError) do csv[2] end csv[-1].should eq(" 2") csv[-2].should eq("1") csv.next csv.next csv[0].should eq("5") csv[1].should eq("") csv[-2].should eq("5") csv[-1].should eq("") end it "gets row values with regex" do csv = new_csv headers: true csv.next.should be_true csv[/on/].should eq("1") csv[/tw/].should eq(" 2") expect_raises(KeyError) do csv[/foo/] end end it "gets current row" do csv = new_csv headers: true csv.next.should be_true row = csv.row row["one"].should eq("1") row[1].should eq(" 2") row[/on/].should eq("1") row.size.should eq(2) row.to_a.should eq(["1", " 2"]) row.to_h.should eq({"one" => "1", "two" => " 2"}) end it "strips" do csv = new_csv headers: true, strip: true csv.next.should be_true csv["one"].should eq("1") csv["two"].should eq("2") csv.row.to_a.should eq(%w(1 2)) csv.row.to_h.should eq({"one" => "1", "two" => "2"}) end it "works without headers" do csv = new_csv headers: false csv.next.should be_true csv[0].should eq("one") end it "can do each" do csv = new_csv headers: true csv.each do csv["one"].should eq("1") break end.should be_nil end it "can do new with block" do CSV.new(%(one, two\n1, 2\n3, 4\n5), headers: true, strip: true) do |csv| csv["one"].should eq("1") csv["two"].should eq("2") break end end it "returns a Tuple(String, String) for current row with indices" do CSV.new("John,20\nPeter,30") do |csv| csv.values_at(0, -1).should eq({"John", "20"}) break end end it "returns a Tuple(String, String) for current row with headers" do CSV.new("Name,Age\nJohn,20\nPeter,30", headers: true) do |csv| csv.values_at("Name", "Age").should eq({"John", "20"}) break end end it "returns a Tuple(String, String) for this row with indices" do CSV.new("John,20\nPeter,30") do |csv| csv.row.values_at(0, -1).should eq({"John", "20"}) break end end it "returns a Tuple(String, String) for this row with headers" do CSV.new("Name,Age\nJohn,20\nPeter,30", headers: true) do |csv| csv.row.values_at("Name", "Age").should eq({"John", "20"}) break end end describe "rewind" do describe "string based" do it "without headers" do csv = CSV.new("one,two\nthree,four", headers: false) csv.next csv.row.to_a.should eq(%w(one two)) csv.next csv.row.to_a.should eq(%w(three four)) csv.rewind csv.next csv.row.to_a.should eq(%w(one two)) end it "with headers" do csv = CSV.new("one,two\nthree,four\nfive,six", headers: true) csv.next csv.row.to_h.should eq({"one" => "three", "two" => "four"}) csv.next csv.row.to_h.should eq({"one" => "five", "two" => "six"}) csv.rewind csv.next csv.row.to_h.should eq({"one" => "three", "two" => "four"}) end end describe "IO based" do it "without headers" do csv = CSV.new(IO::Memory.new("one,two\nthree,four"), headers: false) csv.next csv.row.to_a.should eq(%w(one two)) csv.next csv.row.to_a.should eq(%w(three four)) csv.rewind csv.next csv.row.to_a.should eq(%w(one two)) end it "with headers" do csv = CSV.new(IO::Memory.new("one,two\nthree,four\nfive,six"), headers: true) csv.next csv.row.to_h.should eq({"one" => "three", "two" => "four"}) csv.next csv.row.to_h.should eq({"one" => "five", "two" => "six"}) csv.rewind csv.next csv.row.to_h.should eq({"one" => "three", "two" => "four"}) end end end end