0

What does header:true do |row|, @book<<BookInSTOCK.new, row ["ISBN"] mean in the following code?

class CsvReader
  def initialize
    @book_in_stock = []
  end
  def read_in_csv_data(csv_file_name)
    # enter code here
    CSV.foreach(csv_file_name, header: true) do |row|
      @books_in_stock << BoookInStock.new (row["ISBN"], row ["Amount"])
    end
   end
 end
sawa
  • 165,429
  • 45
  • 277
  • 381
boniface316
  • 489
  • 3
  • 17

3 Answers3

1

@book << BookInSTOCK.new

Adds a new BookInSTOCK object into the @book variable docs

CSV.foreach(csv_file_name, header: true) do |row|

header:true is a named parameter In this case it says there is a header in the csv_file_name, and here you are looping over each row in the csv file and I'm guessing you will want to get data from each row.

That's where:

row ["ISBN"]

Is a way to see what the ISBN is in the specific row. Based on the CSV there is most likely other information you can look up in that row.

EDIT

Based on the comments below I will add some more context

Let's assume a csv that looks like this

ISBN, AMOUNT
1, $30
2, $50
3, $60

then let's assume we have this code(It's very close to yours.

CSV.foreach(csv_file_name, header: true) do |row|
  puts row["ISBN"]
end

Then the output will be:

1
2
3

As you can see we are looping over each row and printing out the information. I hope this helps.

Community
  • 1
  • 1
dbarnes
  • 1,803
  • 3
  • 17
  • 31
  • Can I do header:true do |column|? row["ISBN"] why I need to use row? cant I use column here too? – boniface316 May 20 '15 at 21:13
  • Well you can row is just a variable name, but row is just a representation of each row in the CSV file. If you want to loop over the columns you'll probably have to use a different function. – dbarnes May 20 '15 at 21:14
  • Maybe this will help http://www.tutorialspoint.com/ruby/ruby_iterators.htm. That is just a foreach loop, I'm guessing you're new to programming. – dbarnes May 20 '15 at 21:18
  • Updated the answer to hopefully help. – dbarnes May 20 '15 at 21:22
  • Here is where I got got confused? isnt all the information are on column? can we use |var| instead of |row|? – boniface316 May 20 '15 at 21:25
  • `row` is just a variable name. It could be `mydata` it doesn't really matter, it is just a way to make your code clear as to what you are trying to do. – dbarnes May 20 '15 at 21:26
  • You took time to explain. I really appreciate it. – boniface316 May 20 '15 at 21:29
  • One last question. The reason why its saving "ISBN" is because of the header or its saving cause its the key? – boniface316 May 20 '15 at 21:30
  • I'm assuming all header information in CSV's are keys for the row object. If you were to have a different CSV with no ISBN in it this code will not work. – dbarnes May 20 '15 at 21:31
  • Interesting. Life is easy and you make it easier my friend! – boniface316 May 20 '15 at 21:35
1

Reading the comments, I think you should first make yourself familiar with the basic building blocks and the syntax of Ruby.

I know, in the beginning I had tons of similar questions. I found a very basic and playful approach to learn the basics of the Ruby programming language in this book.

To answer your question:

CSV.foreach(csv_file_name, header: true) is a method call to CSV. The method foreach in this case receives two arguments.

  1. csv_file_name is a variable that is being defined as the first argument of the outer method read_in_csv_data.

    So if you call CsvReader.new.read_in_csv_data("file.csv") it will pass the string "file.csv" down to CSV.foreach("file.csv", ....

  2. header: true is basically a Hash, but this style is commonly known as named arguments. Very useful and readable if you want to pass down options to a method that are very specific.

    How does CSV.foreach receive header: true?
    That is easy to find out, open up a $ irb session on your local machine, and define the following method:

    def foo(arg1, arg2)
      p arg1
      p arg2
      nil
    end
    

    Now play around by calling foo with different arguments.

    > foo("string", 123)
    "string"
    123
    => nil
    > foo("string", named: "argument")
    "string"
    {:named=>"argument}
    => nil
    > foo("string", { named: "argument" })
    "string"
    {:named=>"argument}
    => nil
    

    Doing this you might grasp how Ruby handles named arguments or hash arguments. As you see, the latter examples above show that you can specify a Hash without {} as the last argument on any method in Ruby.
    header: true represents a Hash, ie {:header => true}.

    What does header: true trigger?
    This has to be read up in the documentation for CSV::foreach. You you do a Google search for "ruby csv foreach" you will quickly find a documentation. Here is a direct link to CSV::foreach. There you can read "The options parameter can be anything ::new understands.". So you gotta look for the documentation of CSV::new. This leads you to a nice description of each option you can pass to CSV::new or CSV::foreach.

    What does the documentation say?

    :headers If set to :first_row or true, the initial row of the CSV file will be treated as a row of headers. If set to an Array, the contents will be used as the headers. If set to a String, the String is run through a call of ::parse_line with the same :col_sep, :row_sep, and :quote_char as this instance to produce an Array of headers. This setting causes #shift to return rows as CSV::Row objects instead of Arrays and #read to return CSV::Table objects instead of an Array of Arrays.

Your other questions:

You are welcome to ask questions, but I also think it would be very good for you to get someone to help you directly. Maybe find yourself a local Ruby user group. People there are usually very friendly and helpful.

Having said that, I will now explain what row["ISBN"] means:

CSV::foreach is a method that yields a block. This block is somewhat similar to a function, and per definition of CSV::foreach it lets you do something with each row of the csv file.

row itself is just a variable name defined in the block arguments (ie |row|).

Maybe its time for you to open up another $ irb and play around with blocks yourself:

def foo
  yield 123
end

Try calling foo the same way as you do CSV::foreach, just that you print the output.

> foo do |row| puts row end
123
=> nil
> foo { |arg1| puts arg1 }
123
=> nil

As you see yield 123 is passing 123 as the first argument of the block. You take the first argument in a variable (eg row or arg1) and you can do something with it in the block. Also note that you can create these blocks with do |arg1| ... end but also { |arg1| ... }.

So what is it with this ["ISBN"]??

row itself is just a variable, but is also an object so you can call methods on it. In Ruby you might have already encountered a hash. The contents of a hash in Ruby can be accessed by calling [] on the hash.

The same way each row of the CSV is represented. Just that each row (since you told CSV to use :headers) is being represented as a hash-like object.

If you omit :headers each row will be an array of arrays.

Maybe its time for you to open up an $ irb and play around with CSV directly. For that create yourself a simple csv file like the following, and save it to disk:

id,name
1,Overbryd
2,Boniface
3,Poignant

Then, open up a $ irb -r csv.

> CSV.foreach("test.csv") { |r| p r }
["id", "name"]
["1", "Overbryd"]
["2", "Boniface"]
["3", "Poignant"]
=> nil
> CSV.foreach("test.csv", headers: true) { |r| p r }
#<CSV::Row "id":"1" "name":"Overbryd">
#<CSV::Row "id":"2" "name":"Boniface">
#<CSV::Row "id":"3" "name":"Poignant">
=> nil
> CSV.foreach("test.csv", headers: true) do |row|
  puts row["id"]
end
1
2
3
=> nil

Also, please accept one of the given answers. People take time to answer your questions, their only reward is if you accept one of their answers.

Overbryd
  • 4,612
  • 2
  • 33
  • 33
  • I really appreciate you taking your time to answer my question. I am going to bookmark it till everything becomes a second nature. – boniface316 May 21 '15 at 00:31
0

header: true tells the CSV parser that you have a header row in your file. for example:

col1, col2, col3
1, 3, 4
3, 4, 2

has a header.

@books_in_stock << adds whatever comes after << to the @books_in_stock array

Mircea
  • 10,216
  • 2
  • 30
  • 46