An interpreter translate our plain language expression into information and find out what we need. Here we have a Unit Interpretor (Conversion Context) who does very diverse interpretation jobs. <!–more–>
enum UnitType : String {
case Gallon = "Gallon"
case Pint = "Pint"
case Cup = "Cup"
case USD = "USD"
case RMB = "RMB"
case EURO = "EURO"
case Meter = "Meter"
case Unkonwn = "Unknown"
init ( str : String ) {
switch str {
case "Gallon" , "Gallons" , "gallons" : self = . Gallon
case "Pint" , "Pints" , "pints" : self = . Pint
case "Cup" , "Cups" , "cups" : self = . Cup
case "USD" , "usd" , "Usd" : self = . USD
case "EURO" , "euro" , "Euro" : self = . EURO
case "RMB" , "rmb" , "Rmb" : self = . RMB
default : self = . Unkonwn
}
}
}
protocol Expression {
func getUnit ( quantity : Double , targetUnit : String ) -> Double
}
class Gallon : NSObject , Expression {
func getUnit ( quantity : Double , targetUnit : String ) -> Double {
let targetUnitType = UnitType ( str : targetUnit )
switch targetUnitType {
case . Gallon : return quantity
case . Pint : return quantity * 8
case . Cup : return quantity * 16
default :
print ( "conversion not supported" )
return - 1 // just saying it's a wrong number
}
}
}
class Pint : NSObject , Expression {
func getUnit ( quantity : Double , targetUnit : String ) -> Double {
let targetUnitType = UnitType ( str : targetUnit )
switch targetUnitType {
case . Gallon : return quantity * 0.125
case . Pint : return quantity
case . Cup : return quantity * 2
default :
print ( "conversion not supported" )
return - 1
}
}
}
class USD : NSObject , Expression {
func getUnit ( quantity : Double , targetUnit : String ) -> Double {
let targetUnitType = UnitType ( str : targetUnit )
switch targetUnitType {
case . USD : return quantity
case . EURO : return quantity * 0.92
case . RMB : return quantity * 6.21
default :
print ( "conversion not supported" )
return - 1
}
}
}
class RMB : NSObject , Expression {
func getUnit ( quantity : Double , targetUnit : String ) -> Double {
let targetUnitType = UnitType ( str : targetUnit )
switch targetUnitType {
case . USD : return quantity * 0.16
case . EURO : return quantity * 0.15
case . RMB : return quantity
default :
print ( "conversion not supported" )
return - 1
}
}
}
struct AppConfig {
static let AppName = "interpretor"
}
// The context to translate a sentence into related command and get the result.
class ConversionContext {
static let sharedInstance = ConversionContext ()
private func getTargetQuantity ( fromConversion : String , toConversion : String , quantity : Double ) -> Double {
if fromConversion != "" {
let classStr = UnitType ( str : fromConversion ). rawValue
guard let anyObjecType : AnyObject . Type = NSClassFromString ( "\(AppConfig.AppName).\(classStr)" )
else {
if classStr == "EURO" || classStr == "Cup" {
return - 1
} else {
return - 3
}
}
let nsObjecType : NSObject . Type = anyObjecType as ! NSObject . Type
guard let object = nsObjecType () as ? Expression else { return - 4 }
return object . getUnit ( quantity , targetUnit : toConversion )
}
return - 2
}
func getConversionFromInput ( input : String ) -> String {
let partsOfQues = input . componentsSeparatedByString ( " " )
let fromConversion = partsOfQues [ 1 ]
let toConversion = partsOfQues [ 3 ]
let quantity = Double ( partsOfQues [ 0 ]) !
let targetQuantity = getTargetQuantity ( fromConversion , toConversion : toConversion , quantity : quantity )
switch targetQuantity {
case - 1 : return "Currently we only support conversion from RMB, USD, Gallon and Pint. \(fromConversion) is not supported"
case - 3 : return "We can't recognize your input yet. Try something like RMB, rmb, Gallon, Gallons..."
case - 2 : return "Sorry, we couldn't identify the source conversion. Try something like [ 10 Gallons to Pints ]"
case - 4 : return "Couldn't convert. The object we created doesn't conform with Expression protocol"
case let x where x >= 0 : return "\(partsOfQues[0]) \(partsOfQues[1]) equals \(targetQuantity) \(partsOfQues[3])"
default : return "Some other unknow error happened "
}
}
}
func getOutput ( input : String ) -> String {
print ( "Getting user input:[ \(input) ]" )
let context = ConversionContext . sharedInstance
return context . getConversionFromInput ( input )
}
// Testing. User inputs a sentence and the conversionContext will translate it
let userInput = [
"10 Gallons is Pints" ,
"231 Gallo is Pints" ,
"32.11 Pints in Gallon" ,
"2001.99 USD to RMB" ,
"984.2323 rmb in EURO" ,
"23 Euro in RMB"
]
userInput . map { print ( "Output: [ \(getOutput($0)) ] \n " ) }