我正在Ruby中建立一个具有以下哈希值的收银机:
@change = [
{ :denomination => 0.01, :amount => 5 },
{ :denomination => 0.02, :amount => 5 },
{ :denomination => 0.05, :amount => 5 },
{ :denomination => 0.10, :amount => 5 },
{ :denomination => 0.20, :amount => 5 },
{ :denomination => 0.50, :amount => 5 },
{ :denomination => 1.00, :amount => 5 },
{ :denomination => 2.00, :amount => 5 }
]
用户进行购买时,他们使用的硬币以数组形式作为参数传递。
def pay(coins = [])
coins.each do |coin|
coin = @change.find { |x| x[:denomination] == coin }
coin[:amount] += 1
end
end
当我从终端手动在irb中进行测试时,此方法工作正常。但是,当我尝试运行rspec
时,它失败并显示NoMethodError:
Failure/Error: coin[:amount] += 1
NoMethodError:
undefined method `[]' for nil:NilClass
我真的看不到为什么出现NoMethodError失败,尤其是在终端中运行正常时。谁能帮忙吗?
谢谢:)
更新:
规范:
describe '#pay' do
it 'updates the change' do
till.pay([0.5])
expect(till.change).to include(:denomination=>0.5, :amount=>6)
end
end
答案 0 :(得分:3)
在nil
对象中调用[]时出错。
如果传递的面额不在@change
实例变量中,则@change.find { ... }
的结果将为nil
,并在[]
中调用nil
对象将引发NoMethodError。
这种情况您还没有涉及,可以通过在next
枚举器中使用each
来解决:
coins.each do |coin|
current_denomination = @change.find { |x| x[:denomination] == coin }
next unless current_denomination
current_denomination[:amount] += 1
end
p pay([0.05, 0.05, 2.0, 100])
如果相同的硬币和面额没有变化,您只需“跳”到硬币中的下一个元素。
请注意,@change
的当前实现允许您重复数组中的哈希值,如果面额与其数量的初始值不同,则可能导致错误。您可以只使用哈希将面额和金额都存储为键值:
p [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0].to_h { |a| [a, 5] }
# {0.01=>5, 0.02=>5, 0.05=>5, 0.1=>5, 0.2=>5, 0.5=>5, 1.0=>5, 2.0=>5}
那是Ruby 2.6 +。
作为实现的一个细微调整,您可以将@change
移到一个单独的方法上,然后在其上调用tap
来调用和使用该方法:
DENOMINATIONS = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0].freeze
HASH_KEYS = %i[denomination amount].freeze
def initial_coins
DENOMINATIONS.zip(Array.new(8, 5)).map { |coin| HASH_KEYS.zip(coin).to_h }
end
def pay(coins = [])
initial_coins.tap do |this|
coins.each do |coin|
current_denomination = this.find { |initial_coin| initial_coin[:denomination] == coin }
next unless current_denomination
current_denomination[:amount] += 1
end
end
end
pp pay([0.05, 0.05, 2.0, 100])
# [{:denomination=>0.01, :amount=>5},
# {:denomination=>0.02, :amount=>5},
# {:denomination=>0.05, :amount=>7},
# {:denomination=>0.1, :amount=>5},
# {:denomination=>0.2, :amount=>5},
# {:denomination=>0.5, :amount=>5},
# {:denomination=>1.0, :amount=>5},
# {:denomination=>2.0, :amount=>6}]