Skip to content

Commit

Permalink
Add ip4s module
Browse files Browse the repository at this point in the history
  • Loading branch information
david.geirola committed Nov 1, 2021
1 parent d5bb042 commit d169c32
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 1 deletion.
3 changes: 2 additions & 1 deletion build.sbt
Expand Up @@ -54,7 +54,8 @@ lazy val fs2 = module(project) in file("modules/fs2")
lazy val generic = genericModule(project) in file("modules/generic") dependsOn `generic-base`
lazy val `generic-base` = genericModule(project) in file("modules/generic-base")
lazy val hadoop = module(project) in file("modules/hadoop")
lazy val http4s = module(project) in file("modules/http4s")
lazy val http4s = module(project) in file("modules/http4s") dependsOn ip4s
lazy val ip4s = module(project) in file("modules/ip4s")
lazy val javax = module(project) in file("modules/javax")
lazy val joda = module(project) in file("modules/joda")
lazy val magnolia = module(project) in file("modules/magnolia") dependsOn `generic-base`
Expand Down
1 change: 1 addition & 0 deletions docs/docs/docs/library-integrations.md
Expand Up @@ -20,6 +20,7 @@ The core of PureConfig eschews unnecessary dependencies. Separate modules exist
- [`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;
- [`pureconfig-hadoop`](https://github.com/pureconfig/pureconfig/tree/master/modules/hadoop) provides converters for [Hadoop](http://hadoop.apache.org//) types;
- [`pureconfig-http4s`](https://github.com/pureconfig/pureconfig/tree/master/modules/http4s) provides converters for [Http4s](http://http4s.org/) types;
- [`pureconfig-ip4s`](https://github.com/pureconfig/pureconfig/tree/master/modules/ip4s) provides converters for [Ip4s](https://github.com/Comcast/ip4s) types;
- [`pureconfig-javax`](https://github.com/pureconfig/pureconfig/tree/master/modules/javax) provides converters for classes in `javax` packages;
- [`pureconfig-joda`](https://github.com/pureconfig/pureconfig/tree/master/modules/joda) provides configurable converters for [Joda-Time](http://www.joda.org/joda-time/) types;
- [`pureconfig-magnolia`](https://github.com/pureconfig/pureconfig/tree/master/modules/magnolia) provides an alternative way to derive readers and writers for case classes and sealed traits using [Magnolia](https://propensive.com/opensource/magnolia);
Expand Down
38 changes: 38 additions & 0 deletions modules/ip4s/README.md
@@ -0,0 +1,38 @@

# Ip4s module for PureConfig

Adds support for [Ip4s](https://github.com/Comcast/ip4s)'s Hostname and Port class to PureConfig. PRs adding support
for other classes are welcome :)

## Add pureconfig-ip4s to your project

In addition to [core PureConfig](https://github.com/pureconfig/pureconfig), you'll need:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-ip4s" % "0.17.0"
```

## Example

To load an `Hostname` or a `Port` into a configuration, create a class to hold it:

```scala
import com.comcast.ip4s.{Hostname, Port}
import pureconfig._
import pureconfig.generic.auto._
import pureconfig.module.ip4s._

case class MyConfig(hostname: Hostname, port: Port)
```

We can read a `MyConfig` with the following code:

```scala
val source = ConfigSource.string(
"""{
|hostname: "0.0.0.0"
|port: 8080
|}""".stripMargin)

source.load[MyConfig]
```
11 changes: 11 additions & 0 deletions modules/ip4s/build.sbt
@@ -0,0 +1,11 @@
import Dependencies.Version._

name := "pureconfig-ip4s"

crossScalaVersions := Seq(scala212, scala213)

libraryDependencies ++= Seq("com.comcast" %% "ip4s-core" % "3.0.4")

developers := List(
Developer("geirolz", "David Geirola", "david.geirolz@gmail.com", url("https://github.com/geirolz"))
)
38 changes: 38 additions & 0 deletions modules/ip4s/docs/README.md
@@ -0,0 +1,38 @@

# Ip4s module for PureConfig

Adds support for [Ip4s](https://github.com/Comcast/ip4s)'s Hostname and Port class to PureConfig. PRs adding support
for other classes are welcome :)

## Add pureconfig-ip4s to your project

In addition to [core PureConfig](https://github.com/pureconfig/pureconfig), you'll need:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-ip4s" % "@VERSION@"
```

## Example

To load an `Hostname` or a `Port` into a configuration, create a class to hold it:

```scala mdoc:silent
import com.comcast.ip4s.{Hostname, Port}
import pureconfig._
import pureconfig.generic.auto._
import pureconfig.module.ip4s._

case class MyConfig(hostname: Hostname, port: Port)
```

We can read a `MyConfig` with the following code:

```scala mdoc:silent
val source = ConfigSource.string(
"""{
|hostname: "0.0.0.0"
|port: 8080
|}""".stripMargin)

source.load[MyConfig]
```
31 changes: 31 additions & 0 deletions modules/ip4s/src/main/scala/pureconfig/module/ip4s/package.scala
@@ -0,0 +1,31 @@
package pureconfig.module

import com.comcast.ip4s.{Hostname, Port}

import pureconfig.error.CannotConvert
import pureconfig.{ConfigReader, ConfigWriter}

package object ip4s {

implicit val hostnameWriter: ConfigWriter[Hostname] =
ConfigWriter[String].contramap(_.toString)

implicit val hostnameReader: ConfigReader[Hostname] =
ConfigReader.fromString(str =>
Hostname.fromString(str) match {
case Some(hostname) => Right(hostname)
case None => Left(CannotConvert(str, "Hostname", "Invalid hostname"))
}
)

implicit val portWriter: ConfigWriter[Port] =
ConfigWriter[Int].contramap(_.value)

implicit val portReader: ConfigReader[Port] =
ConfigReader[Int].emap(str =>
Port.fromInt(str) match {
case Some(port) => Right(port)
case None => Left(CannotConvert(str.toString, "Port", "Invalid port"))
}
)
}
46 changes: 46 additions & 0 deletions modules/ip4s/src/test/scala/pureconfig/module/ip4s/Ip4sTest.scala
@@ -0,0 +1,46 @@
package pureconfig.module.ip4s

import com.comcast.ip4s.{Hostname, Port}

import pureconfig.error.{CannotConvert, ConfigReaderFailures, ConvertFailure}
import pureconfig.syntax._
import pureconfig.{BaseSuite, ConfigWriter}

class Ip4sTest extends BaseSuite {

"reading the hostname config" should "parse the hostname" in {
val hostname = "0.0.0.0"
configString(hostname).to[Hostname].value shouldEqual Hostname.fromString(hostname).get
}

"reading the hostname config" should "get a CannotConvert error" in {
configString("...").to[Hostname].left.value shouldEqual ConfigReaderFailures(
ConvertFailure(CannotConvert("...", "Hostname", "Invalid hostname"), stringConfigOrigin(1), "")
)
}

"Hostname ConfigReader and ConfigWriter" should "be able to round-trip reading/writing of Hostname" in {
val expectedHostname = Hostname.fromString("0.0.0.0").get

val configValue = ConfigWriter[Hostname].to(expectedHostname)
configValue.to[Hostname].value shouldEqual expectedHostname
}

"reading the port config" should "parse the port" in {
val port = "8080"
configString(port).to[Port].value shouldEqual Port.fromString(port).get
}

"reading the port config" should "get a CannotConvert error" in {
configString("-1").to[Port].left.value shouldEqual ConfigReaderFailures(
ConvertFailure(CannotConvert("-1", "Port", "Invalid port"), stringConfigOrigin(1), "")
)
}

"Port ConfigReader and ConfigWriter" should "be able to round-trip reading/writing of Port" in {
val expectedPort = Port.fromInt(8080).get

val configValue = ConfigWriter[Port].to(expectedPort)
configValue.to[Port].value shouldEqual expectedPort
}
}

0 comments on commit d169c32

Please sign in to comment.