I have written some code out of the Ruby Pickaxe book and I am trying to get it to work. (around page 62 of "Programming Ruby The Pragmatic Programmer's Guide") **Edit: More info on the book: (C) 2009, for Ruby 1.9
Given this error message, I am not quite sure how to identify what is going wrong. I appreciate any help in understanding what is going wrong here.
How does one know what to identify and solve? I am wondering if Ruby's CSV functionality is really just this easy-- no gem/bundle install to run?
I would really like to be able to run my test_code.rb file, but I am unable to figure out this error.
Thank you for your time, Patrick
Note: all of these files are in the same directory.
IRB command, followed by the error message it generates:
2.1.1 :005 > load "test_code.rb"
LoadError: cannot load such file -- csv-reader
from /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from test_code.rb:3:in `<top (required)>'
from (irb):5:in `load'
from (irb):5
from /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
I don't know how relevant this is, based on the error message, but thought I'd include it. kernel_require.rb line 55:
if Gem::Specification.unresolved_deps.empty? then
begin
RUBYGEMS_ACTIVATION_MONITOR.exit
return gem_original_require(path)
ensure
RUBYGEMS_ACTIVATION_MONITOR.enter
end
end
line 9-11 of irb:
require "irb"
IRB.start(__FILE__)
First file of program: csv-reader.rb
require 'csv'
require 'book-in-stock'
class CsvReader
def initialize
@books_in_stock = []
end
def read_in_csv_data(csv_file_name)
CSV.foreach(csv_file_name, headers: true) do |row|
@books_in_stock << BookInStock.new(row["ISBN"], row["Amount"])
end
end
def total_value_in_stock
sum = 0.0
@books_in_stock.each {|book| sum += book.price}
end
def number_of_each_isbn
end
end
Second file: book-in-stock.rb
class BookInStock
attr_reader :isbn
attr_accessor :price
def initialize(isbn, price)
@isbn = isbn
@price = Float(price)
end
def price_in_cents
Integer(price*100 + 0.5)
end
def price_in_cents=(cents)
@price = cents / 100.0
end
end
Third file: stock-stats.rb
require 'csv-reader'
reader = CsvReader.new
ARGV.each do |csv_file_name|
STDERR.puts "Processing #{csv_file_name}"
reader.read_in_csv_data(csv_file_name)
end
puts "Total value = #{reader.total_value_in_stock}"
Fourth file: test_code.rb
# this is the test code file
require 'csv-reader'
require 'book-in-stock'
require 'stock-stats'
# code to call
reader = CsvReader.new
reader.read_in_csv_data("file1.csv")
reader.read_in_csv_data("file2.csv")
puts "Total value in stock = #{reader.total_value_in_stock}"
# code to call
book = BookInStock.new("isbn1", 33.80)
puts "Price = #{book.price}"
puts "Price in cents = #{book.price_in_cents}"
book.price_in_cents = 1234
puts "Price = #{book.price}"
puts "Price in cents = #{book.price_in_cents}"
CSV files: file1.csv
ISBN, Amount
isbn1, 49.00
isbn2, 24.54
isbn3, 33.23
isbn4, 15.55
file2.csv
ISBN, Amount
isbn5-file2, 39.98
isbn6-file2, 14.84
isbn7-file2, 43.63
isbn8-file2, 25.55
Edit
After Frederick Cheung's suggestion to change require to require_relative (for all but the 1st line of csv-reader.rb), the script is running, but a method is not working (see below)
(I did receive an error about this line: @price = Float(price) and changed it to @price = price.to_f and it runs just fine. )
3 Questions:
-> I changed the header of my csv files to "ISBN, Amount". Previously Amount was amount (not capitalized). Does this matter (i.e. the capitalizing of the header)?
-> While we're on the subject, what is the "row" keyword doing in the following #read_in_csv_data method?
-> Now that my code runs it appears that the output for "Total value in stock" is not summing up all of the prices in the csv file. Could a Rubyist please help me understand why this is happening?
The method
def read_in_csv_data(csv_file_name)
CSV.foreach(csv_file_name, headers: true) do |row|
@books_in_stock << BookInStock.new(row["ISBN"], row["Amount"])
end
end
and call seem fine to me...
reader = CsvReader.new
reader.read_in_csv_data("file1.csv")
reader.read_in_csv_data("file2.csv")
Here is the current output from terminal:
Total value = []
Price = 33.8
Price in cents = 3380
Price = 12.34
Price in cents = 1234
Total value in stock = [#<BookInStock:0xb8168a60 @isbn="isbn1", @price=0.0>, #<BookInStock:0xb8168740 @isbn="isbn2", @price=0.0>, #<BookInStock:0xb8168358 @isbn="isbn3", @price=0.0>, #<BookInStock:0xb81546f0 @isbn="isbn4", @price=0.0>, #<BookInStock:0xb8156a18 @isbn="isbn5-file2", @price=0.0>, #<BookInStock:0xb8156784 @isbn="isbn6-file2", @price=0.0>, #<BookInStock:0xb81564a0 @isbn="isbn7-file2", @price=0.0>, #<BookInStock:0xb8156248 @isbn="isbn8-file2", @price=0.0>]
Thanks again.
Edit: Big thanks to 7Stud for a very thorough followup answer on every question I had. You have been exceptionally helpful. I have learned several important things thanks to your post.
Edit:
Still not able to get the code to run.
I am not sure how to add to / edit the $LOAD_PATH, so I tried putting all of the files into this directory: directory: ~MY_RUBY_HOME/lib/ruby/site_ruby/2.1.0/csv-reader (i.e. /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/csv-reader)
However, I still receive the same error message:
✘ ~MY_RUBY_HOME/lib/ruby/site_ruby/2.1.0/csv-reader ruby test_code.rb file1.csv file2.csv
/Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- ./csv_reader (LoadError)
from /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from test_code.rb:1:in `<main>'