GildedRose-Refactoring-Kata/swift/Sources/GildedRose/Rules/QualityModificationRules.swift

96 lines
2.9 KiB
Swift

//
// QualityModificationRule.swift
//
//
// Created by Lucas van Dongen on 23/11/2020.
//
import Foundation
// These rules are really simple, you could handle more complex ones within their own class
enum QualityModificationRule: Rule {
typealias RuleType = Self
case regular,
increasesQuality,
qualityIncreasesFasterBeforeExpireThenDropsToZero,
legendary
static func rule(for item: Item) -> RuleType {
switch item.name {
case "Aged Brie":
return .increasesQuality
case "Backstage passes to a TAFKAL80ETC concert":
return .qualityIncreasesFasterBeforeExpireThenDropsToZero
case "Sulfuras, Hand of Ragnaros":
return .legendary
default:
return .regular
}
}
func apply(to item: Item) -> Item {
switch self {
case .regular:
return applyRegularRule(to: item)
case .increasesQuality:
return applyIncreasesQualityRule(to: item)
case .qualityIncreasesFasterBeforeExpireThenDropsToZero:
return qualityIncreasesFasterBeforeExpireThenDropsToZeroRule(to: item)
case .legendary:
return applyLegendaryRule(to: item)
}
}
private func applyRegularRule(to item: Item) -> Item {
let modification = Self.isRegularItemExpired(sellIn: item.sellIn) ? -2 : -1
return Self.applyQualityThresholds(to: item, newQuality: item.quality + modification)
}
private func applyIncreasesQualityRule(to item: Item) -> Item {
Self.applyQualityThresholds(to: item, newQuality: item.quality + 1)
}
private func qualityIncreasesFasterBeforeExpireThenDropsToZeroRule(to item: Item) -> Item {
let newQuality: Int
switch item.sellIn {
case ...0:
newQuality = 0
case 0...5:
newQuality = item.quality + 3
case 5...10:
newQuality = item.quality + 2
case 10...:
newQuality = item.quality + 1
default:
fatalError("All values of `sellIn` should be covered")
}
return Self.applyQualityThresholds(to: item, newQuality: newQuality)
}
private func applyLegendaryRule(to item: Item) -> Item {
return item // No change
}
public static func applyQualityThresholds(to item: Item, newQuality: Int) -> Item {
let correctedQuality: Int
switch newQuality {
case ...0:
correctedQuality = 0
case 0...50:
correctedQuality = newQuality
case 50...:
correctedQuality = 50
default:
fatalError("All values of `quality` should be covered")
}
return Item(name: item.name, sellIn: item.sellIn, quality: correctedQuality)
}
public static func isRegularItemExpired(sellIn: Int) -> Bool {
return sellIn <= 0
}
}