From 7a793ffa068fda8f2146f84fa785328d928dba03 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Wed, 12 Sep 2018 15:56:41 -0700 Subject: Move core types into core-types project Note that xyz.driver.core.FutureExtensions was moved to xyz.driver.core.rest as it (only) contained logic that dealt with service exceptions, something that belongs into core-rest and must not be depended upon by core-types. This is a breaking change. --- .../src/main/scala/xyz/driver/core/domain.scala | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 core-types/src/main/scala/xyz/driver/core/domain.scala (limited to 'core-types/src/main/scala/xyz/driver/core/domain.scala') diff --git a/core-types/src/main/scala/xyz/driver/core/domain.scala b/core-types/src/main/scala/xyz/driver/core/domain.scala new file mode 100644 index 0000000..f3b8337 --- /dev/null +++ b/core-types/src/main/scala/xyz/driver/core/domain.scala @@ -0,0 +1,73 @@ +package xyz.driver.core + +import com.google.i18n.phonenumbers.PhoneNumberUtil +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat +import scalaz.Equal +import scalaz.std.string._ +import scalaz.syntax.equal._ + +import scala.util.Try +import scala.util.control.NonFatal + +object domain { + + final case class Email(username: String, domain: String) { + + def value: String = toString + + override def toString: String = username + "@" + domain + } + + object Email { + implicit val emailEqual: Equal[Email] = Equal.equal { + case (left, right) => left.toString.toLowerCase === right.toString.toLowerCase + } + + def parse(emailString: String): Option[Email] = { + Some(emailString.split("@")) collect { + case Array(username, domain) => Email(username, domain) + } + } + } + + final case class PhoneNumber(countryCode: String, number: String, extension: Option[String] = None) { + + def hasExtension: Boolean = extension.isDefined + + /** This is a more human-friendly alias for #toE164String() */ + def toCompactString: String = s"+$countryCode$number${extension.fold("")(";ext=" + _)}" + + /** Outputs the phone number in a E.164-compliant way, e.g. +14151234567 */ + def toE164String: String = toCompactString + + /** + * Outputs the phone number in a "readable" way, e.g. "+1 415-123-45-67 ext. 1234" + * @throws IllegalStateException if the contents of this object is not a valid phone number + */ + @throws[IllegalStateException] + def toHumanReadableString: String = + try { + val phoneNumber = PhoneNumber.phoneUtil.parse(toE164String, "US") + PhoneNumber.phoneUtil.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL) + } catch { + case NonFatal(e) => throw new IllegalStateException(s"$toString is not a valid number", e) + } + + override def toString: String = s"+$countryCode $number${extension.fold("")(" ext. " + _)}" + } + + object PhoneNumber { + + private[PhoneNumber] val phoneUtil = PhoneNumberUtil.getInstance() + + def parse(phoneNumber: String): Option[PhoneNumber] = { + val validated = Try(phoneUtil.parseAndKeepRawInput(phoneNumber, "US")).toOption.filter(phoneUtil.isValidNumber) + validated.map { pn => + PhoneNumber( + pn.getCountryCode.toString, + pn.getNationalNumber.toString, + Option(pn.getExtension).filter(_.nonEmpty)) + } + } + } +} -- cgit v1.2.3