Skip to content

Instantly share code, notes, and snippets.

Created July 9, 2011 08:55
Show Gist options
  • Save anonymous/1073449 to your computer and use it in GitHub Desktop.
Save anonymous/1073449 to your computer and use it in GitHub Desktop.
TDDBC TOKYO 1.5 VendingMachine
# -*- coding: utf-8 -*-
class Drink
attr_accessor :name, :price
def initialize(name, price)
self.name = name
self.price = price
end
end
class Money
attr_reader :value
end
[10, 50, 100, 500, 1000].each do |v|
klass = Class.new(Money) do
define_method :initialize do
@value = v
end
define_method :to_s do
"Money" + v.to_s
end
end
Kernel.const_set "Money#{v}", klass.new
end
class VendingMachine
attr_reader :amount, :sales, :charges
def initialize
@sales = 0
@amount = 0
cola = Drink.new "コーラ", 120
redbull = Drink.new "レッドブル", 200
water = Drink.new "水", 100
@drink = {1 => cola, 2 => redbull, 3 => water}
@stock = {1 => 5, 2 => 5, 3 => 5}
@charges = {
Money10 => 10,
Money50 => 10,
Money100 => 10,
Money500 => 10,
Money1000 => 5,
}
end
def count_stock(id)
@stock[id] || 0
end
def receive(money)
if money.is_a? Money
@amount += money.value
else
raise "変なもんいれんな"
end
ret = []
@charges[money] += 1
@drink.each do |id,drink|
if @amount >= drink.price
ret.push id
end
end
ret
end
def sell(id)
if @amount < @drink[id].price
raise "買えません"
end
if count_stock(id) <= 0
raise "売り切れです"
end
oturi = @amount - @drink[id].price
needed = {}
[1000,500,100,50,10].each do |m|
needed[Kernel.const_get "Money#{m}"] = oturi / m
oturi %= m
end
if needed.any? {|k,v| v > @charges[k]}
raise "お釣りがありません"
end
needed.each do |k,v|
@charges[k] -= v
end
@sales += @drink[id].price
@stock[id] -= 1
@amount = 0
end
end
# -*- coding: utf-8 -*-
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'vending_machine'
describe VendingMachine do
def buy_cola(just = nil)
if just
@vm.receive(Money100)
@vm.receive(Money10)
@vm.receive(Money10)
else
@vm.receive(Money500)
end
@vm.sell(1)
end
before do
@vm = VendingMachine.new
end
describe '#receive' do
context '千円札を投入すると' do
it '合計金額が千円' do
@vm.receive(Money1000)
@vm.amount.should == 1000
end
it 'コーラ, レッドブル, 水が買えることを示す' do
@vm.receive(Money1000).should == [1, 2, 3]
end
end
[Money10, Money50, Money100, Money500].each do |coin|
context "#{coin.value}円玉を投入すると" do
it "合計金額が#{coin.value}円" do
@vm.receive(coin)
@vm.amount.should == coin.value
end
end
end
context '二千円札を投入すると' do
it 'RuntimeError が発生する' do
expect{@vm.receive('二千円札')}.to raise_error(RuntimeError, "変なもんいれんな")
end
end
context '千円札と100円玉を投入すると' do
it '合計金額が1100円' do
@vm.receive(Money1000)
@vm.receive(Money100)
@vm.amount.should == 1100
end
end
context '100円玉を投入すると' do
it '水しか買えないことを示す' do
@vm.receive(Money100).should == [3]
end
end
context '120円を投入すると' do
it '水とコーラが買えることを示す' do
@vm.receive(Money100).should == [3]
@vm.receive(Money10).should == [3]
@vm.receive(Money10).should == [1,3]
end
end
end
describe '#count_stock' do
it 'コーラの在庫を返す' do
@vm.count_stock(1).should == 5
end
it 'レッドブルの在庫を返す' do
@vm.count_stock(2).should == 5
end
it '水の在庫を返す' do
@vm.count_stock(3).should == 5
end
end
describe '#sell' do
context 'id=1 を指定すると' do
before do
buy_cola
end
it 'コーラの在庫が減る' do
@vm.count_stock(1).should == 4
end
it 'おつりが返るので残金は0' do
@vm.amount.should == 0
end
end
context "id=2 を指定すると" do
it "レッドブルの在庫が減る" do
@vm.receive(Money500)
@vm.sell(2)
@vm.count_stock(2).should == 4
end
end
context '金額が足りない場合' do
it 'RuntimeError が発生する' do
@vm.receive(Money50)
expect{@vm.sell(1)}.to raise_error(RuntimeError, "買えません")
end
end
context "コーラの在庫がない場合" do
before do
5.times{ buy_cola(true) }
end
it "RuntimeError が発生する" do
expect{buy_cola}.to raise_error(RuntimeError, "売り切れです")
end
end
end
describe "#sales" do
context 'コーラを二本買った場合' do
before do
2.times { buy_cola }
end
it '売り上げ合計金額を返す' do
@vm.sales.should == 240
end
end
end
describe "#charges" do
it "千円札5枚、硬貨はそれぞれ10枚保持している" do
@vm.charges.should == {
Money10 => 10,
Money50 => 10,
Money100 => 10,
Money500 => 10,
Money1000 => 5,
}
end
context "100円玉を投入すると" do
it "100円玉が11枚になる" do
@vm.receive Money100
@vm.charges.should == {
Money10 => 10,
Money50 => 10,
Money100 => 11,
Money500 => 10,
Money1000 => 5,
}
end
end
context "500円玉を投入してコーラを買うと" do
it "おつり分が減る" do
buy_cola
@vm.charges.should == {
Money10 => 7,
Money50 => 9,
Money100 => 7,
Money500 => 11,
Money1000 => 5,
}
end
end
context "10円玉の残りが1枚で500円玉でコーラを買うと" do
before do
3.times{buy_cola}
end
it "おつりがないので RuntimeError" do
expect{buy_cola}.to raise_error(RuntimeError, "お釣りがありません")
@vm.count_stock(1).should == 2
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment