Skip to content

Instantly share code, notes, and snippets.

@cwmyers
Created June 13, 2014 04:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwmyers/e07e706436fe4a7c92ef to your computer and use it in GitHub Desktop.
Save cwmyers/e07e706436fe4a7c92ef to your computer and use it in GitHub Desktop.
Validation Example
package com.rea-group.validation
import scalaz._, Scalaz._
import java.lang.NumberFormatException
import scala.collection.mutable.ListBuffer
object ValidationExample {
val suburbs = Map(3000 -> "Melbourne", 3121 -> "Richmond", 4000 -> "Brisbane", 2001 -> "Sydney")
def postCodeLookup(postCode: Int) = suburbs.get(postCode)
def isDigits(input: String): Boolean = input.matches("^[0-9]+$")
def createSuccessString(firstName: String, lastName: String, postCode: String, phoneNumber: String): String =
s"Validation succeed: $firstName $lastName of postcode $postCode has phone number $phoneNumber"
def createErrorString(errors: List[String]) = s"Failed to validate with the following errors: " + errors.mkString(", ")
// Old skool way of doing validations
def validateOldSkool(input: Map[String, String]): String = {
val errors = scala.collection.mutable.ListBuffer[String]()
val firstName = input.getOrElse("firstName", "")
if (firstName.isEmpty)
errors += "first name can't be empty"
val lastName = input.getOrElse("lastName", "")
if (lastName.isEmpty)
errors += "last name can't be empty"
val homePhone = input.getOrElse("homePhone", "")
var hasHomePhone = false
val phoneErrors = ListBuffer[String]()
if (!isDigits(homePhone)) {
phoneErrors += "Home phone needs to be digits"
} else {
hasHomePhone = true
}
val mobilePhone = input.getOrElse("mobilePhone", "")
var hasMobilePhone = false
if (!hasHomePhone) {
if (!isDigits(mobilePhone)) {
phoneErrors += "mobile phone needs to be digits"
} else {
hasMobilePhone = true
}
}
if (!hasHomePhone && !hasMobilePhone)
errors ++= phoneErrors
val phone = if (hasHomePhone) homePhone else mobilePhone
val postCode = input.getOrElse("postCode", "")
var postCodeInt = 0
var suburb = ""
try {
postCodeInt = Integer.parseInt(postCode)
val maybeSuburb: Option[String] = postCodeLookup(postCodeInt)
if (maybeSuburb.isDefined)
suburb = maybeSuburb.get
else
errors += "You don't live in a valid postcode area"
} catch {
case e: NumberFormatException => errors += "post code must be a number"
}
if (errors.isEmpty) {
createSuccessString(firstName, lastName, postCode, phone)
} else {
createErrorString(errors.toList)
}
}
// no skool like the new skool
def validate(input: Map[String, String]): String = {
val validatedFirstName = validateInput(input, "firstName").flatMap(firstName => validateName("first name", firstName))
val validatedLastName = validateInput(input, "lastName").flatMap(lastName => validateName("last name", lastName))
val validatedSuburb = validateInput(input, "postCode")
.flatMap(postCode => postCode.parseInt.leftMap(_ => "post code must be a number").toValidationNel)
.flatMap(postCode => postCodeLookup(postCode).toSuccess("not in a valid area").toValidationNel)
val mobilePhone = validatePhone(input, "mobilePhone", "mobile phone")
val homePhone = validatePhone(input, "homePhone", "home phone")
val validatedPhone = mobilePhone orElse homePhone
val successStringOrListOfErrors = accumulate(createSuccessString)(validatedFirstName, validatedLastName, validatedSuburb, validatedPhone)
successStringOrListOfErrors.valueOr(errors => createErrorString(errors.list))
}
def validateInput(input: Map[String, String], key: String) = input.get(key).toSuccess(s"Could not find $key").toValidationNel
def validatePhone(input: Map[String, String], key: String, label: String): ValidationNel[String, String] =
validateInput(input, key).flatMap {
phone =>
if (isDigits(phone)) phone.successNel else s"$label needs to be digits".failNel
}
def validateName(label: String, name: String): ValidationNel[String, String] =
if (!name.isEmpty) name.successNel else s"$label can't be empty".failNel
type V[X] = ValidationNel[String, X]
def accumulate[A, B, C, D, E](f: (A, B, C, D) => E) = Applicative[V].lift4(f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment