Skip to content

Commit

Permalink
Merge branch 'master' into scala-version-root-project
Browse files Browse the repository at this point in the history
  • Loading branch information
ruippeixotog committed Sep 28, 2019
2 parents cc447ee + e326635 commit addcc20
Show file tree
Hide file tree
Showing 25 changed files with 205 additions and 212 deletions.
14 changes: 10 additions & 4 deletions build.sbt
Expand Up @@ -8,13 +8,19 @@ lazy val core = (project in file("core")).
settings(commonSettings).
dependsOn(macros)

// A special module for now, since `tests` depend on it. We should improve this organization later by separating the
// test helpers (which all projects' tests should depend on) from the core+generic test implementations.
lazy val generic = (project in file("modules/generic")).
// Two special modules for now, since `tests` depend on them. We should improve this organization later by separating
// the test helpers (which all projects' tests should depend on) from the core+generic test implementations.
lazy val `generic-base` = (project in file("modules/generic-base")).
enablePlugins(SbtOsgi, TutPlugin).
dependsOn(core).
settings(commonSettings, tutTargetDirectory := baseDirectory.value)

lazy val generic = (project in file("modules/generic")).
enablePlugins(SbtOsgi, TutPlugin).
dependsOn(core, `generic-base`).
settings(commonSettings, tutTargetDirectory := baseDirectory.value)
// -----

lazy val macros = (project in file("macros")).
enablePlugins(TutPlugin).
settings(commonSettings)
Expand All @@ -40,7 +46,7 @@ lazy val docs = (project in file("docs")).
def module(proj: Project) = proj.
enablePlugins(SbtOsgi, TutPlugin).
dependsOn(core).
dependsOn(tests % "test->test"). // In order to reuse the DerivationSuite scalacheck generators
dependsOn(tests % "test").
dependsOn(generic % "Tut"). // Allow auto-derivation in documentation
settings(commonSettings, tutTargetDirectory := baseDirectory.value)

Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/tut/docs/library-integrations.md
Expand Up @@ -13,7 +13,7 @@ The core of PureConfig eschews unnecessary dependencies. Separate modules exist
- [`pureconfig-cats`](https://github.com/pureconfig/pureconfig/tree/master/modules/cats) provides converters for [Cats](http://typelevel.org/cats/) data structures and Cats typeclass instances;
- [`pureconfig-cats-effect`](https://github.com/pureconfig/pureconfig/tree/master/modules/cats-effect) uses [cats-effect](https://github.com/typelevel/cats-effect) to load and save configurations in a side-effect free manner;
- [`pureconfig-circe`](https://github.com/pureconfig/pureconfig/tree/master/modules/circe) provides converters for Circe's Json AST;
- [`pureconfig-cron4s`](https://github.com/pureconfig/pureconfig/tree/master/modules/cron4s) provides converters for [Cron4s](https://alonsodomin.github.io/cron4s/) types;
- [`pureconfig-cron4s`](https://github.com/pureconfig/pureconfig/tree/master/modules/cron4s) provides converters for [Cron4s](https://github.com/alonsodomin/cron4s) types;
- [`pureconfig-enum`](https://github.com/pureconfig/pureconfig/tree/master/modules/enum) provides converters for enums generated by [julienrf's enum library](https://github.com/julienrf/enum);
- [`pureconfig-enumeratum`](https://github.com/pureconfig/pureconfig/tree/master/modules/enumeratum) provides converters for enums generated by [Enumeratum](https://github.com/lloydmeta/enumeratum);
- [`pureconfig-fs2`](https://github.com/pureconfig/pureconfig/tree/master/modules/fs2) provides support for reading configuration from and writing to [fs2](https://github.com/functional-streams-for-scala/fs2/) streams;
Expand Down
2 changes: 1 addition & 1 deletion modules/cron4s/README.md
@@ -1,7 +1,7 @@

# Cron4s module for PureConfig

Adds support for [Cron4s](https://alonsodomin.github.io/cron4s/)'s CronExpr class to PureConfig.
Adds support for [Cron4s](https://github.com/alonsodomin/cron4s)'s CronExpr class to PureConfig.

## Add pureconfig-cron4s to your project

Expand Down
5 changes: 2 additions & 3 deletions modules/cron4s/build.sbt
@@ -1,9 +1,8 @@
name := "pureconfig-cron4s"

crossScalaVersions ~= { _.filterNot(_.startsWith("2.13")) }
crossScalaVersions ~= { _.filterNot(_.startsWith("2.11")) }

libraryDependencies ++= Seq(
"com.github.alonsodomin.cron4s" %% "cron4s-core" % "0.5.0")
libraryDependencies += "com.github.alonsodomin.cron4s" %% "cron4s-core" % "0.6.0"

developers := List(
Developer("bardurdam", "Bárður Viberg Dam", "bardurdam@gmail.com", url("https://github.com/bardurdam")))
Expand Down
2 changes: 1 addition & 1 deletion modules/cron4s/src/main/tut/README.md
@@ -1,7 +1,7 @@

# Cron4s module for PureConfig

Adds support for [Cron4s](https://alonsodomin.github.io/cron4s/)'s CronExpr class to PureConfig.
Adds support for [Cron4s](https://github.com/alonsodomin/cron4s)'s CronExpr class to PureConfig.

## Add pureconfig-cron4s to your project

Expand Down
Expand Up @@ -24,7 +24,7 @@ class Cron4sSuite extends BaseSuite {

val errors = ConfigReaderFailures(
ConvertFailure(
CannotConvert("10-65 * * * * *", "CronExpr", "Expected '\" \" | 0-59' at position 2 but found '\"-65 * * * * *\"'"),
CannotConvert("10-65 * * * * *", "CronExpr", "blank expected at position 3 but found '-'"),
None,
"schedule"))

Expand Down
@@ -1,6 +1,6 @@
package pureconfig.generic

import com.typesafe.config.{ ConfigFactory, ConfigObject, ConfigValue, ConfigValueType }
import com.typesafe.config.{ ConfigObject, ConfigValue, ConfigValueType }
import pureconfig._
import pureconfig.error._
import pureconfig.generic.error.{ NoValidCoproductChoiceFound, UnexpectedValueForFieldCoproductHint }
Expand Down Expand Up @@ -112,39 +112,6 @@ object FieldCoproductHint {
val defaultMapping: String => String = ConfigFieldMapping(PascalCase, KebabCase)
}

/**
* Hint applicable to sealed families of case objects where objects are written and read as strings with their type
* names. Trying to read or write values that are not case objects results in failure.
*
* @tparam T the type of the coproduct or sealed family for which this hint applies
*/
@deprecated("Use `pureconfig.generic.semiauto.deriveEnumerationReader[T]`, `pureconfig.generic.semiauto.deriveEnumerationWriter[T]` and `pureconfig.generic.semiauto.deriveEnumerationConvert[T]` instead", "0.11.0")
class EnumCoproductHint[T] extends CoproductHint[T] {

/**
* Returns the field value for a class or coproduct option name.
*
* @param name the name of the class or coproduct option
* @return the field value associated with the given class or coproduct option name.
*/
protected def fieldValue(name: String): String = name.toLowerCase

def from(cur: ConfigCursor, name: String) = cur.asString.right.map { str =>
if (str == fieldValue(name)) Some(ConfigCursor(ConfigFactory.empty.root, cur.pathElems)) else None
}

// TODO: improve handling of failures on the write side
def to(cv: ConfigValue, name: String) = cv match {
case co: ConfigObject if co.isEmpty => Right(fieldValue(name).toConfig)
case _: ConfigObject => Left(ConfigReaderFailures(ConvertFailure(
NonEmptyObjectFound(name), ConfigValueLocation(cv), "")))
case _ => Left(ConfigReaderFailures(ConvertFailure(
WrongType(cv.valueType, Set(ConfigValueType.OBJECT)), ConfigValueLocation(cv), "")))
}

def tryNextOnFail(name: String) = false
}

/**
* Hint where all coproduct options are tried in order. `from` will choose the first option able to deserialize
* the config without errors, while `to` will write the config as is, with no disambiguation information.
Expand Down
@@ -0,0 +1,39 @@
package pureconfig.generic

import com.typesafe.config.{ ConfigFactory, ConfigObject, ConfigValue, ConfigValueType }
import pureconfig._
import pureconfig.error._
import pureconfig.syntax._

/**
* Hint applicable to sealed families of case objects where objects are written and read as strings with their type
* names. Trying to read or write values that are not case objects results in failure.
*
* @tparam T the type of the coproduct or sealed family for which this hint applies
*/
@deprecated("Use `pureconfig.generic.semiauto.deriveEnumerationReader[T]`, `pureconfig.generic.semiauto.deriveEnumerationWriter[T]` and `pureconfig.generic.semiauto.deriveEnumerationConvert[T]` instead", "0.11.0")
class EnumCoproductHint[T] extends CoproductHint[T] {

/**
* Returns the field value for a class or coproduct option name.
*
* @param name the name of the class or coproduct option
* @return the field value associated with the given class or coproduct option name.
*/
protected def fieldValue(name: String): String = name.toLowerCase

def from(cur: ConfigCursor, name: String) = cur.asString.right.map { str =>
if (str == fieldValue(name)) Some(ConfigCursor(ConfigFactory.empty.root, cur.pathElems)) else None
}

// TODO: improve handling of failures on the write side
def to(cv: ConfigValue, name: String) = cv match {
case co: ConfigObject if co.isEmpty => Right(fieldValue(name).toConfig)
case _: ConfigObject => Left(ConfigReaderFailures(ConvertFailure(
NonEmptyObjectFound(name), ConfigValueLocation(cv), "")))
case _ => Left(ConfigReaderFailures(ConvertFailure(
WrongType(cv.valueType, Set(ConfigValueType.OBJECT)), ConfigValueLocation(cv), "")))
}

def tryNextOnFail(name: String) = false
}
@@ -1,11 +1,9 @@
package pureconfig.module.joda

import org.joda.time._
import org.scalacheck.Arbitrary
import JodaSuite._
import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter }
import pureconfig.module.joda.configurable.ConfigurableSuite.{ dateTimeArbitrary, zoneIdArbitrary }
import pureconfig.BaseSuite
import pureconfig.module.joda.arbitrary._

class JodaSuite extends BaseSuite {

Expand All @@ -20,20 +18,3 @@ class JodaSuite extends BaseSuite {
checkReadString[DateTimeFormatter](
"yyyy-MM-dd'T'HH:mm:ss.SSSZZZ" -> DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ"))
}

object JodaSuite {
implicit val instantArbitrary: Arbitrary[Instant] =
Arbitrary(Arbitrary.arbitrary[Long].map(new Instant(_)))

implicit val intervalArbitrary: Arbitrary[Interval] =
Arbitrary(Arbitrary.arbitrary[(DateTime, DateTime)]
.map { i =>
val (from, to) = if (i._1.isBefore(i._2)) i else i.swap
// Comparing new Interval(foo) with Interval.parseWithOffset(foo) will return false
// See http://www.joda.org/joda-time/apidocs/org/joda/time/Interval.html#parseWithOffset-java.lang.String-
Interval.parseWithOffset(new Interval(from, to).toString)
})

implicit val durationArbitrary: Arbitrary[Duration] =
Arbitrary(Arbitrary.arbitrary[Long].map(new Duration(_)))
}
@@ -0,0 +1,69 @@
package pureconfig.module.joda

import scala.collection.JavaConverters._

import org.joda.time._
import org.scalacheck.{ Arbitrary, Gen }
import pureconfig.gen._

package object arbitrary {
private def nanoToMilli(n: Int): Int = n / 1000000

implicit val instantArbitrary: Arbitrary[Instant] =
Arbitrary(Arbitrary.arbitrary[Long].map(new Instant(_)))

implicit val intervalArbitrary: Arbitrary[Interval] =
Arbitrary(Arbitrary.arbitrary[(DateTime, DateTime)]
.map { i =>
val (from, to) = if (i._1.isBefore(i._2)) i else i.swap
// Comparing new Interval(foo) with Interval.parseWithOffset(foo) will return false
// See http://www.joda.org/joda-time/apidocs/org/joda/time/Interval.html#parseWithOffset-java.lang.String-
Interval.parseWithOffset(new Interval(from, to).toString)
})

implicit val durationArbitrary: Arbitrary[Duration] =
Arbitrary(Arbitrary.arbitrary[Long].map(new Duration(_)))

implicit val localTimeArbitrary: Arbitrary[LocalTime] = Arbitrary(
genLocalTime.map { t =>
new LocalTime(t.getHour, t.getMinute, t.getSecond, nanoToMilli(t.getNano))
})

implicit val localDateArbitrary: Arbitrary[LocalDate] = Arbitrary(
genLocalDate.map { d =>
new LocalDate(d.getYear, d.getMonthValue, d.getDayOfMonth)
})

implicit val localDateTimeArbitrary: Arbitrary[LocalDateTime] = Arbitrary(
genLocalDateTime.map { d =>
new LocalDateTime(
d.getYear, d.getMonthValue, d.getDayOfMonth,
d.getHour, d.getMinute, d.getSecond, nanoToMilli(d.getNano))
})

implicit val monthDayArbitrary: Arbitrary[MonthDay] = Arbitrary(
genMonthDay.map { m =>
new MonthDay(m.getMonthValue, m.getDayOfMonth)
})

implicit val yearMonthArbitrary: Arbitrary[YearMonth] = Arbitrary(
genYearMonth.map { y =>
new YearMonth(y.getYear, y.getMonthValue)
})

implicit val zoneIdArbitrary: Arbitrary[DateTimeZone] =
Arbitrary(Gen.oneOf(DateTimeZone.getAvailableIDs.asScala.toSeq).map(DateTimeZone.forID))

implicit val dateTimeArbitrary: Arbitrary[DateTime] =
Arbitrary(
for {
zoneId <- zoneIdArbitrary.arbitrary
localDateTime <- localDateTimeArbitrary.arbitrary if !zoneId.isLocalDateTimeGap(localDateTime)
} yield localDateTime.toDateTime(zoneId))

implicit val periodArbitrary: Arbitrary[Period] =
Arbitrary(Arbitrary.arbitrary[Int].map { i =>
// Generated large longs crash Period constructor internally
new Period(i.toLong)
})
}
Expand Up @@ -2,12 +2,8 @@ package pureconfig.module.joda.configurable

import org.joda.time._
import org.joda.time.format.{ DateTimeFormat, ISOPeriodFormat, PeriodFormatter }
import org.scalacheck.{ Arbitrary, Gen }
import ConfigurableSuite._
import pureconfig.configurable.{ ConfigurableSuite => JTime }
import scala.collection.JavaConverters._

import pureconfig.BaseSuite
import pureconfig.module.joda.arbitrary._

class ConfigurableSuite extends BaseSuite {

Expand Down Expand Up @@ -39,50 +35,3 @@ class ConfigurableSuite extends BaseSuite {
implicit val periodInstance = periodConfigConvert(periodFormatter)
checkArbitrary[Period]
}

object ConfigurableSuite {
private def nanoToMilli(n: Int): Int = n / 1000000

implicit val localTimeArbitrary: Arbitrary[LocalTime] = Arbitrary(
JTime.localTimeArbitrary.arbitrary.map { t =>
new LocalTime(t.getHour, t.getMinute, t.getSecond, nanoToMilli(t.getNano))
})

implicit val localDateArbitrary: Arbitrary[LocalDate] = Arbitrary(
JTime.localDateArbitrary.arbitrary.map { d =>
new LocalDate(d.getYear, d.getMonthValue, d.getDayOfMonth)
})

implicit val localDateTimeArbitrary: Arbitrary[LocalDateTime] = Arbitrary(
JTime.localDateTimeArbitrary.arbitrary.map { d =>
new LocalDateTime(
d.getYear, d.getMonthValue, d.getDayOfMonth,
d.getHour, d.getMinute, d.getSecond, nanoToMilli(d.getNano))
})

implicit val monthDayArbitrary: Arbitrary[MonthDay] = Arbitrary(
JTime.monthDayArbitrary.arbitrary.map { m =>
new MonthDay(m.getMonthValue, m.getDayOfMonth)
})

implicit val yearMonthArbitrary: Arbitrary[YearMonth] = Arbitrary(
JTime.yearMonthArbitrary.arbitrary.map { y =>
new YearMonth(y.getYear, y.getMonthValue)
})

implicit val zoneIdArbitrary: Arbitrary[DateTimeZone] =
Arbitrary(Gen.oneOf(DateTimeZone.getAvailableIDs.asScala.toSeq).map(DateTimeZone.forID))

implicit val dateTimeArbitrary: Arbitrary[DateTime] =
Arbitrary(
for {
zoneId <- zoneIdArbitrary.arbitrary
localDateTime <- localDateTimeArbitrary.arbitrary if !zoneId.isLocalDateTimeGap(localDateTime)
} yield localDateTime.toDateTime(zoneId))

implicit val periodArbitrary: Arbitrary[Period] =
Arbitrary(Arbitrary.arbitrary[Int].map { i =>
// Generated large longs crash Period constructor internally
new Period(i.toLong)
})
}
6 changes: 3 additions & 3 deletions project/Dependencies.scala
Expand Up @@ -20,8 +20,8 @@ object Dependencies {
val typesafeConfig = "com.typesafe" % "config" % Version.typesafeConfig

// testing libraries
val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest % "test"
val scalaCheck = "org.scalacheck" %% "scalacheck" % Version.scalaCheck % "test"
val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest
val scalaCheck = "org.scalacheck" %% "scalacheck" % Version.scalaCheck
val scalaCheckShapeless =
"com.github.alexarchambault" %% s"scalacheck-shapeless_1.14" % Version.scalaCheckShapeless % "test"
"com.github.alexarchambault" %% s"scalacheck-shapeless_1.14" % Version.scalaCheckShapeless
}
2 changes: 1 addition & 1 deletion tests/build.sbt
Expand Up @@ -5,6 +5,6 @@ name := "pureconfig-tests"
libraryDependencies ++= Seq(
scalaTest,
scalaCheck,
scalaCheckShapeless)
scalaCheckShapeless % "test")

skip in publish := true

0 comments on commit addcc20

Please sign in to comment.