我正在用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
最佳答案
在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
实现允许您在数组中重复散列,如果一个面额与其初始值amount不同,则可能导致错误您只需使用哈希将面额和金额存储为键值: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}
那是Ruby2.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}]