Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Ruby Ruby Collections Build a Grocery List Program Build a Grocery List Program: Part 4

My Attempt At The Grocery List *Extra Credit*

I spent a good four to five hours working on this. Between hashes not pushing and loops not looping I thought I was going to go insane. I used a global variable to remove the question from the list_name method to stop the program from asking the name of the grocery list twice. I think I read somewhere global variables are a bad idea but I couldn't think of another way to do it. Let me know what you think!

#this program is a loop that asks for items to retun a list with a title and quantites

print "Please title your list: "
@name = gets.chomp

def list_name
  list_name = @name
  hash = { "name" => list_name, "items" => Array.new }
  return hash
end

def add_item
  print "What item would you like to add?: "
  item = gets.chomp

  print "How much?: "
  quantity = gets.chomp.to_i

  hash = { "item" => item, "quantity" => quantity }
  return hash
end

list = list_name

def print_list(list)
  print "List Title: #{list_name['name']}\n\n"

  list["items"].each do |item|
    print "Item: " + item['item']
    print "\t\t\t"
    print "Quantity: " + item['quantity'].to_s + "\n"
  end
end

def continue_list()
  print "Would you like to add an item? (Y/N): "
  continue = gets.chomp.upcase
  if continue == "Y"
    return true
  else
    return false
  end
end

while continue_list() == true do
  list["items"].push(add_item())
end


puts "\n\nHere is your complete list!\n\n"
print_list(list)
Daniel Cunningham
Daniel Cunningham
21,109 Points

It looks like it works, but there are a lot of return statements... Just to share, I took a stab at this myself and came up with this.

class GroceryList
  attr_accessor :name, :list

  def initialize
    print "What is the list name?"
    @name = gets.chomp
    @list = {'name' => @name, "items" => []}
  end

  def add_list_item
    print "What is the item called?"
    item_name = gets.chomp

    print "How much?"
    quantity = gets.chomp.to_i
    hash = { "name" => item_name, "quantity" => quantity }
    list["items"] << hash
    add_item_check
  end

  def print_list
    puts "List: #{list['name']}"
    2.times {puts "----"}

    list["items"].each do |item|
      puts "Item: " + item['name'] + " || "+"Quantity: " + item['quantity'].to_s
      puts "----"
    end  
  end

  def add_item_check
    puts "add more items?"
    x = gets.chomp.upcase
    if x == "Y" || x== "YES"
      add_list_item()
    end
  end

end  


list = GroceryList.new 
list.add_list_item
list.print_list

I made a Class out of this and called an instance of the class. Turning it into a class isnt necessary at all, but I wanted to experiment with it. In this case, create_list() was replaced by an "initialize" method that will create the attributes and the name for the list. Then it has the following elements:

  1. Add_list_item calls the method "add_item_check" at the end <br>
  2. Add_item_check creates the loop if subject answers "yes" or "y", otherwise it ends the method.
  3. outside of the class methods, print_list is called when you're done adding items.

another way to clean up my code might be to put the add_item_check code directly into the add_list_item method, but this works for now.

2 Answers

Hi Spencer,

Like Daniel Cunningham said, there are a lot of return statements. Remember, Ruby has implicit returns.

Daniel also has a cool idea of using a class. It would be cool to see a 'runner' loop containing a case statement that allows a user to call the various methods that have been created. Just a thought!

Cheers, Jacob

Here's my take on this :)

def list_name
  puts "What do you want to call your list? "
  name = gets.chomp

  hash = {:name => name, :items => Array.new}
  return hash
end

def list_items
  puts "What item do you need? "
  item = gets.chomp
  puts "How many do you need? "
  quantity = gets.chomp.to_i

  hash = {:item => item, :quantity => quantity}
  return hash
end

def seperator(character='-')
  print character * 80
end

list = list_name
list[:items].push(list_items)

def list_output(list)
  list[:items].each do |item|
    puts "\tItem: " + item[:item] + "\t\t\t" +
    "Quantity: " + item[:quantity].to_s
    seperator()
  end
end

def list_loop(list)
  puts "Do you want to add another item, yes or no? "
  answer = gets.chomp.downcase
  if answer == "yes"
    list[:items].push(list_items)
    list_loop(list)
  else
    list_output(list)

  end

end

list
list_loop(list)
list_output(list)