class Machine
Attributes
available_change[RW]
products[RW]
Public Class Methods
new(products:, available_change:)
click to toggle source
# File lib/machine/machine.rb, line 14 def initialize(products:, available_change:) @products = products @available_change = transform_keys_to_cash(available_change) end
Public Instance Methods
refill_cash(cash)
click to toggle source
# File lib/machine/machine.rb, line 31 def refill_cash(cash) reload_cash(cash_refills: cash) end
refill_products(products)
click to toggle source
# File lib/machine/machine.rb, line 27 def refill_products(products) reload_products(product_refills: products) end
select_product(product:, coins:)
click to toggle source
# File lib/machine/machine.rb, line 19 def select_product(product:, coins:) raise ArgumentError unless coins.is_a? Array raise NoMoneyError if coins.empty? product = products[product] raise OutOfSelectedProductError if product.nil? || product[:available].zero? find_product(product: product[:product], cash_values: Cash.cash_values(coins)) end
Private Instance Methods
calculate_change(product_price:, coins:)
click to toggle source
# File lib/machine/machine.rb, line 66 def calculate_change(product_price:, coins:) sorted_coins = coins.sort.reverse! sorted_coins.each do |coin| product_price -= coin end raise MoreMoneyError if product_price.positive? product_price.abs end
calculate_coin_denominations(change:)
click to toggle source
# File lib/machine/machine.rb, line 75 def calculate_coin_denominations(change:) available_coins = remaining_change.keys.sort.reverse! change_array = [] available_coins.each do |coin| next if (change - coin).negative? until (change - coin).negative? change -= coin change_array << coin end end decrement_available_change(change_array) change_array end
change(product_price:, coins:)
click to toggle source
# File lib/machine/machine.rb, line 62 def change(product_price:, coins:) @change ||= calculate_change(product_price: product_price, coins: coins) end
correct_change_given?(product_price:, coins: [])
click to toggle source
# File lib/machine/machine.rb, line 57 def correct_change_given?(product_price:, coins: []) raise ArgumentError unless coins.is_a? Array true if exact_change?(coins: coins) && (product_price - coins.first).zero? end
decrement_available_change(change_array)
click to toggle source
# File lib/machine/machine.rb, line 125 def decrement_available_change(change_array) change_array.each { |change| available_change[change] -= 1 } end
decrement_available_products(product)
click to toggle source
# File lib/machine/machine.rb, line 133 def decrement_available_products(product) products[product.name][:available] -= 1 end
exact_change?(coins:)
click to toggle source
# File lib/machine/machine.rb, line 113 def exact_change?(coins:) coins.length == 1 end
find_product(product:, cash_values:)
click to toggle source
# File lib/machine/machine.rb, line 35 def find_product(product:, cash_values:) product_price = product.cash_value if correct_change_given?(product_price: product_price, coins: cash_values) increment_available_change(cash_values) decrement_available_products(product) return product_and_change(product) end raise OutOfMoneyError if remaining_change.empty? increment_available_change(cash_values) change = change(product_price: product_price, coins: cash_values) coins = calculate_coin_denominations(change: change) decrement_available_products(product) product_and_change(product, Cash.string_values(coins)) end
increment_available_change(cash)
click to toggle source
# File lib/machine/machine.rb, line 129 def increment_available_change(cash) cash.each { |coin| available_change[coin] += 1 } end
product_and_change(product, change = nil)
click to toggle source
# File lib/machine/machine.rb, line 50 def product_and_change(product, change = nil) { product: product.name, change: change.nil? ? ["0"] : change } end
reload_cash(cash_refills:)
click to toggle source
# File lib/machine/machine.rb, line 103 def reload_cash(cash_refills:) raise ArgumentError if cash_refills.empty? raise InvalidCoinError unless (cash_refills.keys - Cash.valid_coins).empty? cash_value_refills = transform_keys_to_cash(cash_refills) cash_value_refills.each do |coin, amount| next if amount.negative? available_change[coin] += amount end end
reload_products(product_refills:)
click to toggle source
# File lib/machine/machine.rb, line 89 def reload_products(product_refills:) raise ArgumentError unless product_refills.is_a? Array raise ArgumentError unless product_refills.all? { |product_refill| product_refill[:product].is_a? Product } raise ArgumentError if product_refills.empty? product_refills.each do |product_refill| product_name = product_refill[:product].name if products[product_name].nil? products[product_name] = product_refill else products[product_name][:available] += product_refill[:available] end end end
remaining_change()
click to toggle source
# File lib/machine/machine.rb, line 117 def remaining_change available_change.select { |coin, remaining| remaining.positive? } end
transform_keys_to_cash(coins)
click to toggle source
# File lib/machine/machine.rb, line 121 def transform_keys_to_cash(coins) coins.transform_keys! { |coin| Cash.cash_value(coin) } end