Skip to content

Commit

Permalink
Make use of the asString method of ConfigReader in fromString
Browse files Browse the repository at this point in the history
  • Loading branch information
jcazevedo committed Sep 29, 2018
1 parent 570b926 commit c3d66f4
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 40 deletions.
33 changes: 25 additions & 8 deletions core/src/main/scala/pureconfig/BasicReaders.scala
Expand Up @@ -24,22 +24,39 @@ import pureconfig.error._
trait PrimitiveReaders {

implicit val stringConfigReader = ConfigReader.fromCursor(_.asString)

implicit val charConfigReader = ConfigReader.fromNonEmptyString[Char](s =>
s.size match {
case 1 => Right(s.charAt(0))
case len => Left(WrongSizeString(1, len))
})

implicit val booleanConfigReader = ConfigReader.fromCursor(_.asBoolean)
implicit val doubleConfigReader = ConfigReader.fromNonEmptyString[Double](catchReadError({
case v if v.last == '%' => v.dropRight(1).toDouble / 100d
case v => v.toDouble
}))
implicit val floatConfigReader = ConfigReader.fromNonEmptyString[Float](catchReadError({
case v if v.last == '%' => v.dropRight(1).toFloat / 100f
case v => v.toFloat
}))

implicit val doubleConfigReader = ConfigReader.fromCursor({ cur =>
val asStringReader = catchReadError({
case v if v.last == '%' => v.dropRight(1).toDouble / 100f
case v => v.toDouble
})

cur.asString.right.flatMap(s => cur.scopeFailure(asStringReader(s)))
.left.flatMap(_ => cur.asDouble)
})

implicit val floatConfigReader = ConfigReader.fromCursor({ cur =>
val asStringReader = catchReadError({
case v if v.last == '%' => v.dropRight(1).toFloat / 100f
case v => v.toFloat
})

cur.asString.right.flatMap(s => cur.scopeFailure(asStringReader(s)))
.left.flatMap(_ => cur.asFloat)
})

implicit val intConfigReader = ConfigReader.fromCursor(_.asInt)

implicit val longConfigReader = ConfigReader.fromCursor(_.asLong)

implicit val shortConfigReader = ConfigReader.fromCursor(_.asShort)
}

Expand Down
11 changes: 5 additions & 6 deletions core/src/main/scala/pureconfig/ConfigConvert.scala
Expand Up @@ -9,9 +9,8 @@ package pureconfig
import scala.reflect.ClassTag
import scala.util.Try

import com.typesafe.config.{ ConfigValue, ConfigValueFactory }
import pureconfig.ConvertHelpers._
import pureconfig.error.{ ConfigReaderFailures, FailureReason }
import pureconfig.error.FailureReason

/**
* Trait for objects capable of reading and writing objects of a given type from and to `ConfigValues`.
Expand Down Expand Up @@ -49,10 +48,10 @@ object ConfigConvert extends ConvertHelpers {
def to(t: T) = writer.value.to(t)
}

def viaString[T](fromF: String => Either[FailureReason, T], toF: T => String): ConfigConvert[T] = new ConfigConvert[T] {
override def from(cur: ConfigCursor): Either[ConfigReaderFailures, T] = stringToEitherConvert(fromF)(cur)
override def to(t: T): ConfigValue = ConfigValueFactory.fromAnyRef(toF(t))
}
def viaString[T](fromF: String => Either[FailureReason, T], toF: T => String): ConfigConvert[T] =
fromReaderAndWriter(
Derivation.Successful(ConfigReader.fromString(fromF)),
Derivation.Successful(ConfigWriter.toString(toF)))

def viaStringTry[T: ClassTag](fromF: String => Try[T], toF: T => String): ConfigConvert[T] = {
viaString[T](tryF(fromF), toF)
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/scala/pureconfig/ConfigReader.scala
Expand Up @@ -143,9 +143,8 @@ object ConfigReader extends BasicReaders with CollectionReaders with ExportedRea
def fromFunction[A](fromF: ConfigValue => Either[ConfigReaderFailures, A]) =
fromCursor(fromF.compose(_.value))

def fromString[A](fromF: String => Either[FailureReason, A]): ConfigReader[A] = new ConfigReader[A] {
override def from(cur: ConfigCursor): Either[ConfigReaderFailures, A] = stringToEitherConvert(fromF)(cur)
}
def fromString[A](fromF: String => Either[FailureReason, A]): ConfigReader[A] =
ConfigReader.fromCursor(_.asString).emap(fromF)

def fromStringTry[A](fromF: String => Try[A])(implicit ct: ClassTag[A]): ConfigReader[A] = {
fromString[A](tryF(fromF))
Expand Down
15 changes: 1 addition & 14 deletions core/src/main/scala/pureconfig/ConvertHelpers.scala
@@ -1,10 +1,9 @@
package pureconfig

import scala.reflect.ClassTag
import scala.util.{ Failure, Success, Try }
import scala.util.control.NonFatal
import scala.util.{ Failure, Success, Try }

import com.typesafe.config._
import pureconfig.error._

/**
Expand All @@ -30,18 +29,6 @@ trait ConvertHelpers {
case Failure(e) => Left(ExceptionThrown(e))
}

private[pureconfig] def stringToEitherConvert[T](fromF: String => Either[FailureReason, T]): ConfigCursor => Either[ConfigReaderFailures, T] = { cur =>
// Because we can't trust Typesafe Config not to throw, we wrap the
// evaluation into a `try-catch` to prevent an unintentional exception from escaping.
try {
cur.scopeFailure {
fromF(cur.asString.fold(_ => cur.value.render(ConfigRenderOptions.concise), identity))
}
} catch {
case NonFatal(t) => cur.failed(ExceptionThrown(t))
}
}

private[pureconfig] def ensureNonEmpty[T](implicit ct: ClassTag[T]): String => Either[FailureReason, String] = {
case "" => Left(EmptyStringFound(ct.toString))
case x => Right(x)
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/scala/pureconfig/DurationUtils.scala
Expand Up @@ -6,8 +6,9 @@ package pureconfig
import scala.concurrent.duration.Duration.{ Inf, MinusInf }
import scala.concurrent.duration.{ DAYS, Duration, FiniteDuration, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, SECONDS, TimeUnit }
import scala.util.Try
import scala.util.control.NonFatal

import pureconfig.error.{ CannotConvert, FailureReason }
import pureconfig.error.{ CannotConvert, ExceptionThrown, FailureReason }

/**
* Utility functions for converting a `String` to a `Duration` and vice versa. The parser accepts the HOCON unit
Expand All @@ -25,6 +26,8 @@ private[pureconfig] object DurationUtils {
case ex: NumberFormatException =>
val err = s"${ex.getMessage}. (try a number followed by any of ns, us, ms, s, m, h, d)"
Left(CannotConvert(string, "Duration", err))
case NonFatal(t) =>
Left(ExceptionThrown(t))
}
}

Expand Down
32 changes: 24 additions & 8 deletions tests/src/test/scala/pureconfig/BasicConvertersSuite.scala
Expand Up @@ -27,16 +27,22 @@ class BasicConvertersSuite extends BaseSuite {

checkArbitrary[Duration]
checkFailure[Duration, EmptyStringFound](ConfigValueFactory.fromAnyRef(""))
checkFailure[Duration, CannotConvert](ConfigValueFactory.fromIterable(List(1).asJava))
checkFailures[Duration](
ConfigValueFactory.fromIterable(List(1).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.LIST, Set(ConfigValueType.STRING)), None, "")))

checkArbitrary[JavaDuration]
checkFailure[JavaDuration, EmptyStringFound](ConfigValueFactory.fromAnyRef(""))
checkFailure[JavaDuration, CannotConvert](ConfigValueFactory.fromIterable(List(1).asJava))
checkFailures[JavaDuration](
ConfigValueFactory.fromIterable(List(1).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.LIST, Set(ConfigValueType.STRING)), None, "")))

checkArbitrary[FiniteDuration]
checkFailure[FiniteDuration, EmptyStringFound](ConfigValueFactory.fromAnyRef(""))
checkFailures[FiniteDuration](
ConfigValueFactory.fromIterable(List(1).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.LIST, Set(ConfigValueType.STRING)), None, "")))
checkFailure[FiniteDuration, CannotConvert](
ConfigValueFactory.fromIterable(List(1).asJava),
ConfigConvert[Duration].to(Duration.MinusInf),
ConfigConvert[Duration].to(Duration.Inf))

Expand Down Expand Up @@ -90,11 +96,19 @@ class BasicConvertersSuite extends BaseSuite {

checkArbitrary[Double]
checkArbitrary2[Double, Percentage](_.toDoubleFraction)
checkFailure[Double, EmptyStringFound](ConfigValueFactory.fromAnyRef(""))
checkFailure[Double, CannotConvert](ConfigValueFactory.fromIterable(List(1, 2, 3, 4).asJava))
checkFailures[Double](
ConfigValueFactory.fromAnyRef("") -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.STRING, Set(ConfigValueType.NUMBER)), None, "")),
ConfigValueFactory.fromIterable(List(1, 2, 3, 4).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.LIST, Set(ConfigValueType.NUMBER)), None, "")))

checkArbitrary[Float]
checkArbitrary2[Float, Percentage](_.toFloatFraction)
checkFailures[Float](
ConfigValueFactory.fromAnyRef("") -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.STRING, Set(ConfigValueType.NUMBER)), None, "")),
ConfigValueFactory.fromIterable(List(1, 2, 3, 4).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.LIST, Set(ConfigValueType.NUMBER)), None, "")))

checkArbitrary[Int]

Expand Down Expand Up @@ -128,9 +142,11 @@ class BasicConvertersSuite extends BaseSuite {
ConfigValueFactory.fromMap(Map("3" -> 2, "1" -> 4).asJava) -> List(4, 2),
ConfigValueFactory.fromMap(Map("1" -> 1, "a" -> 2).asJava) -> List(1))

checkFailure[immutable.List[Int], WrongType](
ConfigValueFactory.fromMap(Map("b" -> 1, "a" -> 2).asJava),
ConfigValueFactory.fromMap(Map().asJava))
checkFailures[immutable.List[Int]](
ConfigValueFactory.fromMap(Map("b" -> 1, "a" -> 2).asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.OBJECT, Set(ConfigValueType.LIST)), None, "")),
ConfigValueFactory.fromMap(Map().asJava) -> ConfigReaderFailures(
ConvertFailure(WrongType(ConfigValueType.OBJECT, Set(ConfigValueType.LIST)), None, "")))

checkArbitrary[immutable.ListSet[Int]]

Expand Down

0 comments on commit c3d66f4

Please sign in to comment.