Skip to content

Commit

Permalink
Add ChronoUnit ConfigReader (#1117)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdedetrich authored Aug 29, 2021
1 parent 6cc794d commit 7e536dd
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 5 deletions.
9 changes: 5 additions & 4 deletions core/src/main/scala/pureconfig/BasicReaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.math.{BigDecimal => JavaBigDecimal, BigInteger}
import java.net.{URI, URL}
import java.nio.file.{Path, Paths}
import java.time._
import java.time.temporal.ChronoUnit
import java.time.{Duration => JavaDuration}
import java.util.UUID
import java.util.regex.Pattern
Expand Down Expand Up @@ -67,10 +68,7 @@ trait PrimitiveReaders {
trait JavaEnumReader {

implicit def javaEnumReader[A <: java.lang.Enum[A]](implicit tag: ClassTag[A]): ConfigReader[A] =
ConfigReader.fromString(catchReadError(s => {
val enumClass = tag.runtimeClass.asInstanceOf[Class[A]]
Enum.valueOf(enumClass, s)
}))
configurable.genericJavaEnumReader[A](identity)
}

/** Trait containing `ConfigReader` instances for classes related to file system paths and URIs.
Expand Down Expand Up @@ -109,6 +107,9 @@ trait JavaTimeReaders {
implicit val periodConfigReader: ConfigReader[Period] =
ConfigReader.fromNonEmptyString[Period](PeriodUtils.fromString)

implicit val chronoUnitReader: ConfigReader[ChronoUnit] =
configurable.genericJavaEnumReader[ChronoUnit](ConfigFieldMapping(KebabCase, ScreamingSnakeCase))

implicit val javaDurationConfigReader: ConfigReader[JavaDuration] =
ConfigReader.fromNonEmptyString[JavaDuration](catchReadError(JavaDuration.parse))

Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/pureconfig/BasicWriters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.math.{BigDecimal => JavaBigDecimal, BigInteger}
import java.net.{URI, URL}
import java.nio.file.Path
import java.time._
import java.time.temporal.ChronoUnit
import java.time.{Duration => JavaDuration}
import java.util.UUID
import java.util.regex.Pattern
Expand Down Expand Up @@ -65,11 +66,16 @@ trait JavaTimeWriters {
implicit val zoneOffsetConfigWriter: ConfigWriter[ZoneOffset] = ConfigWriter.toDefaultString[ZoneOffset]
implicit val zoneIdConfigWriter: ConfigWriter[ZoneId] = ConfigWriter.toDefaultString[ZoneId]
implicit val periodConfigWriter: ConfigWriter[Period] = ConfigWriter.toDefaultString[Period]
implicit val chronoUnitConfigWriter: ConfigWriter[ChronoUnit] =
ConfigWriter.toString[ChronoUnit](chronoUnitToString)

// see documentation for [[java.time.Year.parse]]
private[this] def yearToString(year: Year): String =
if (year.getValue > 9999) "+" + year else year.toString

private[this] def chronoUnitToString(chronoUnit: ChronoUnit): String =
ConfigFieldMapping(ScreamingSnakeCase, KebabCase)(chronoUnit.name)

implicit val yearConfigWriter: ConfigWriter[Year] = ConfigWriter.toString[Year](yearToString)
implicit val javaDurationConfigWriter: ConfigWriter[JavaDuration] = ConfigWriter.toDefaultString[JavaDuration]
}
Expand Down
12 changes: 11 additions & 1 deletion core/src/main/scala/pureconfig/configurable/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import java.time._
import java.time.format.DateTimeFormatter

import scala.collection.JavaConverters._
import scala.reflect.ClassTag

import com.typesafe.config.ConfigValueFactory

import pureconfig.ConfigConvert.{catchReadError, viaNonEmptyString}
import pureconfig.ConfigConvert.viaNonEmptyString
import pureconfig.ConvertHelpers.catchReadError
import pureconfig.error.FailureReason

/** Provides methods that create [[ConfigConvert]] instances from a set of parameters used to configure the instances.
Expand Down Expand Up @@ -74,4 +76,12 @@ package object configurable {
keyFormatter(key) -> writerV.to(value)
}.asJava)
)

def genericJavaEnumReader[A <: java.lang.Enum[A]](
transformValue: String => String
)(implicit tag: ClassTag[A]): ConfigReader[A] =
ConfigReader.fromString(catchReadError(s => {
val enumClass = tag.runtimeClass.asInstanceOf[Class[A]]
Enum.valueOf(enumClass, transformValue(s))
}))
}
2 changes: 2 additions & 0 deletions testkit/src/main/scala/pureconfig/arbitrary/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pureconfig
import java.io.File
import java.math.BigInteger
import java.nio.file.Path
import java.time.temporal.ChronoUnit
import java.time.{Duration => JavaDuration, _}
import java.util.UUID

Expand All @@ -20,6 +21,7 @@ package object arbitrary {
implicit val arbFiniteDuration: Arbitrary[FiniteDuration] = Arbitrary(genFiniteDuration)
implicit val arbInstant: Arbitrary[Instant] = Arbitrary(genInstant)
implicit val arbPeriod: Arbitrary[Period] = Arbitrary(genPeriod)
implicit val arbChronoUnit: Arbitrary[ChronoUnit] = Arbitrary(Gen.oneOf(ChronoUnit.values()))
implicit val arbYear: Arbitrary[Year] = Arbitrary(genYear)
implicit val arbUUID: Arbitrary[UUID] = Arbitrary(Gen.uuid)
implicit val arbPath: Arbitrary[Path] = Arbitrary(genPath)
Expand Down
8 changes: 8 additions & 0 deletions tests/src/test/scala/pureconfig/BasicConvertersSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.io.File
import java.math.{BigDecimal => JavaBigDecimal, BigInteger}
import java.net.{URI, URL}
import java.nio.file.Path
import java.time.temporal.ChronoUnit
import java.time.{Duration => JavaDuration, _}
import java.util.UUID
import java.util.regex.Pattern
Expand Down Expand Up @@ -71,6 +72,8 @@ class BasicConvertersSuite extends BaseSuite {

checkArbitrary[Period]

checkArbitrary[ChronoUnit]

checkReadString[Period](
"1d" -> Period.ofDays(1),
"42" -> Period.ofDays(42),
Expand All @@ -79,6 +82,11 @@ class BasicConvertersSuite extends BaseSuite {
"2y" -> Period.ofYears(2)
)

checkReadString[ChronoUnit](
"half-days" -> ChronoUnit.HALF_DAYS,
"weeks" -> ChronoUnit.WEEKS
)

checkRead[Period](ConfigValueFactory.fromAnyRef(42) -> Period.ofDays(42))

checkFailure[Period, CannotConvert](ConfigValueFactory.fromAnyRef("4kb"), ConfigValueFactory.fromAnyRef("x weeks"))
Expand Down

0 comments on commit 7e536dd

Please sign in to comment.