Skip to content

Commit 67907bb

Browse files
author
John Ollier
committed
Add main program file. Save product details to database. Implement show basket.
1 parent ac5e08d commit 67907bb

7 files changed

+158
-23
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.idea
22
.rspec
33
.DS_Store
4+
/supermarket.db
5+
*.db

Lib/basket.rb

+50-8
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,82 @@ def initialize(catalogue)
88
@catalogue.products_by_code.each_key { |p_code| @purchases[p_code] = 0 }
99
end
1010

11-
def show_basket
12-
# #{@basket} will call to_s method of Basket
11+
def show
12+
# #{@basket} will call to_s method of Basket - that's good for debugging, but not user friendly.
13+
message_lines = Array.new
14+
@purchases.each do |code, quantity|
15+
if quantity > 0
16+
product = @catalogue.products_by_code[code]
17+
price = product.price * quantity
18+
message_lines << checkout_line(product.name, quantity, price)
19+
end
20+
end
21+
message_lines << total_line(total)
22+
message_lines
1323
end
1424

1525
def total
1626
running_total = 0
1727
@purchases.each do |code, quantity|
1828
running_total = running_total + quantity * @catalogue.products_by_code[code].price
1929
end
20-
return running_total
30+
running_total
2131
end
2232

2333
# give our parameter a descriptive name
2434
def add(product_code)
2535
# what if the user passes a non existant product code
2636
if @purchases.key?(product_code)
2737
@purchases[product_code] = @purchases[product_code] + 1
38+
product = @catalogue.products_by_code[product_code]
39+
return add_line(product.name, product.price)
2840
else
29-
# TODO can do better than this
30-
print("Error: no product with code: #{product_code}")
41+
return "Error: no product with code: #{product_code}"
3142
end
3243
end
3344

3445
def remove(product_code)
3546
if @purchases.key?(product_code)
3647
if purchases[product_code] > 0
3748
purchases[product_code] = purchases[product_code] - 1
49+
product = @catalogue.products_by_code[product_code]
50+
return removed_line(product.name)
3851
else
39-
print("Warning: no product with code #{product_code} in basket")
52+
return "Warning: no product with code #{product_code} in basket"
4053
end
4154
else
42-
# TODO can do better than this
43-
print("Error: no product with code: #{product_code}")
55+
return "Error: no product with code: #{product_code} in catalogue"
56+
end
57+
end
58+
59+
private
60+
61+
def format_price(price_in_p)
62+
price_in_pounds = price_in_p / 100.0
63+
if price_in_p % 10 == 0
64+
price_in_pounds.to_s + '0'
65+
else
66+
price_in_pounds.to_s
4467
end
4568
end
4669

70+
def checkout_line(name, quantity, price)
71+
price_in_pounds = format_price(price)
72+
"#{quantity} x #{name} £#{price_in_pounds}"
73+
end
74+
75+
def add_line(name, price)
76+
price_in_pounds = format_price(price)
77+
"Added #{name} £#{price_in_pounds}"
78+
end
79+
80+
def removed_line(name)
81+
"Removed #{name}"
82+
end
83+
84+
def total_line(total_pence)
85+
total = format_price(total_pence)
86+
"Total #{total}"
87+
end
88+
4789
end

Lib/catalogue.rb

+23-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
1-
require 'product'
1+
require 'sqlite3'
2+
require_relative 'product'
23

34
class Catalogue
45

56
attr_reader :products_by_code
67

7-
def initialize()
8-
fruit_tea = Product.new('FR1','Fruit Tea', 311)
9-
strawberries = Product.new('SR1','Strawberries', 500)
10-
coffee = Product.new('CF1','Coffee', 1123)
11-
@products_by_code = {'FR1' => fruit_tea, 'SR1' => strawberries, 'CF1' => coffee}
8+
def initialize(db)
9+
10+
product_table = db.get_first_value "SELECT name FROM sqlite_master WHERE type='table' AND name='product';"
11+
12+
if product_table
13+
@products_by_code = {}
14+
product_results = db.execute "SELECT code, name, price FROM product;"
15+
product_results.each do |result|
16+
@products_by_code[result[0]] = Product.new(result[0], result[1], result[2])
17+
end
18+
else
19+
fruit_tea = Product.new('FR1', 'Fruit Tea', 311)
20+
strawberries = Product.new('SR1', 'Strawberries', 500)
21+
coffee = Product.new('CF1', 'Coffee', 1123)
22+
@products_by_code = {'FR1' => fruit_tea, 'SR1' => strawberries, 'CF1' => coffee}
23+
db.execute "CREATE TABLE IF NOT EXISTS product (code VARCHAR PRIMARY KEY, name VARCHAR NOT NULL, price INT NOT NULL);"
24+
@products_by_code.each do |product_code, product|
25+
db.execute "INSERT INTO product VALUES ('#{product_code}','#{product.name}', #{product.price.to_i} );"
26+
end
27+
28+
end
1229
end
1330

1431
end

Lib/main.rb

+35-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,40 @@
1-
puts "Welcome to the GDS supermarket"
1+
require './basket'
2+
require './catalogue'
23

3-
finish = false
4+
def print_message(lines)
5+
lines.each { |line| puts line }
6+
end
7+
8+
begin
9+
db = SQLite3::Database.new 'supermarket.db'
10+
11+
puts "Welcome to the GDS supermarket"
12+
13+
finish = false
14+
15+
catalogue = Catalogue.new(db)
16+
basket = Basket.new(catalogue)
17+
18+
while !finish
19+
puts "Please enter command from: add [product code], remove [product_code], checkout"
20+
command = gets.strip
21+
if command == 'checkout'
22+
puts basket.show
23+
finish = true
24+
elsif command =~ /add \w{3}/
25+
product_code = command.split(" ")[1]
26+
puts basket.add(product_code)
27+
elsif command =~ /remove \w{3}/
28+
product_code = command.split(" ")[1]
29+
puts basket.remove(product_code)
30+
else
31+
puts "You did not enter a valid command!"
32+
end
433

5-
while !finish
6-
puts "Please enter command"
7-
command = gets
8-
if command == 'checkout':
9-
finish = true
1034
end
1135

36+
rescue SQLite3::Exception => e
37+
puts e
38+
ensure
39+
db.close if db
1240
end

Spec/basket_spec.rb

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
require 'basket'
22
require 'catalogue'
33

4+
# here's a simple mock class, but for anything more complex use a mocking framework
5+
class MockDB
6+
def execute(s)
7+
# do nothing
8+
end
9+
10+
def get_first_value(s)
11+
nil
12+
end
13+
end
14+
15+
db = MockDB.new
16+
417
describe Basket do
5-
catalogue = Catalogue.new
18+
catalogue = Catalogue.new(db)
619
describe '#initialize' do
720
it "is empty initially" do
821
basket = Basket.new(catalogue)
@@ -59,5 +72,16 @@
5972
expect(basket.total).to eq(1745)
6073
end
6174
end
75+
describe '#show' do
76+
it "will show product names and quantities" do
77+
basket = Basket.new(catalogue)
78+
basket.add("FR1")
79+
basket.add("FR1")
80+
basket.add("CF1")
81+
message = basket.show
82+
expect(message[0]).to eq("2 x Fruit Tea £6.22")
83+
expect(message[1]).to eq("1 x Coffee £11.23")
84+
end
85+
end
6286
end
6387

Spec/catalogue_spec.rb

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
require 'catalogue'
22

3+
class MockDB
4+
def execute(s)
5+
# do nothing
6+
end
7+
8+
def get_first_value(s)
9+
return nil
10+
end
11+
end
12+
13+
db = MockDB.new
14+
315
describe Catalogue do
416
describe '#initialize' do
517
it "has all products" do
6-
catalogue = Catalogue.new
18+
catalogue = Catalogue.new(db)
719
# when testing methods test the data not a formatted message containing the data
820
expect(catalogue.products_by_code['FR1'].code).to eq('FR1')
921
end

readme.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## Supermarket checkout
2+
3+
We now need a database. You should install sqlite and the ruby driver for it.
4+
5+
brew install sqlite
6+
7+
gem install sqlite3
8+
9+
10+

0 commit comments

Comments
 (0)