Skip to content

Commit

Permalink
CanBuildFromDecoder: support any Map type
Browse files Browse the repository at this point in the history
  • Loading branch information
kitbellew committed May 17, 2021
1 parent 50bf1ec commit fa9839a
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ object ConfDecoder {
stringConfDecoder.flatMap { path =>
Configured.fromExceptionThrowing(Paths.get(path))
}

implicit def canBuildFromOption[A](
implicit ev: ConfDecoder[A],
classTag: ClassTag[A]
Expand All @@ -110,11 +111,21 @@ object ConfDecoder {
case Conf.Null() => Configured.ok(None)
case _ => ev.read(conf).map(Some(_))
}

// XXX: remove this method when MIMA no longer an issue
@deprecated("Use canBuildFromAnyMapWithStringKey instead", "0.9.2")
implicit def canBuildFromMapWithStringKey[A](
implicit ev: ConfDecoder[A],
classTag: ClassTag[A]
): ConfDecoder[Map[String, A]] =
CanBuildFromDecoder.map[A]
CanBuildFromDecoder.map[A, Map]

implicit def canBuildFromAnyMapWithStringKey[A, CC[_, _]](
implicit ev: ConfDecoder[A],
factory: Factory[(String, A), CC[String, A]],
classTag: ClassTag[A]
): ConfDecoder[CC[String, A]] =
CanBuildFromDecoder.map[A, CC]

implicit def canBuildFromConfDecoder[C[_], A](
implicit ev: ConfDecoder[A],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ object ConfEncoder {
): ConfEncoder[Option[A]] =
_.fold[Conf](Conf.Null())(ev.write)

implicit def MapEncoder[A](
implicit def MapEncoder[A, CC[String, A] <: collection.Map[String, A]](
implicit ev: ConfEncoder[A]
): ConfEncoder[Map[String, A]] =
(value: Map[String, A]) => Conf.Obj(value.mapValues(ev.write).toList)
): ConfEncoder[CC[String, A]] =
(value: CC[String, A]) =>
Conf.Obj(value.view.map { case (k, v) => k -> ev.write(v) }.toList)

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import metaconfig.Configured.Ok

object CanBuildFromDecoder {

def map[A](
def map[A, CC[_, _]](
implicit ev: ConfDecoder[A],
factory: Factory[(String, A), CC[String, A]],
classTag: ClassTag[A]
): ConfDecoder[Map[String, A]] =
): ConfDecoder[CC[String, A]] =
ConfDecoder.fromPartial(
s"Map[String, ${classTag.runtimeClass.getName}]"
) {
case Conf.Obj(values) =>
val factory = Map.canBuildFrom[String, A]
build(values, ev, factory)(_._2, (x, y) => (x._1, y))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package metaconfig.cli

import scala.collection.immutable.ListMap

import metaconfig._
import metaconfig.generic.Surface

case class Site(
foo: String = "foo",
custom: Map[String, String] = Map.empty
custom: Map[String, String] = Map.empty,
custom2: ListMap[String, String] = ListMap.empty
)

object Site {
implicit val surface: Surface[Site] = generic.deriveSurface[Site]
implicit val codec: ConfCodec[Site] = generic.deriveCodec[Site](Site())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ class BaseCliParserSuite extends munit.FunSuite {
def check(
name: String,
args: List[String],
expectedOptions: Options
expectedOptions: Options,
unexpectedOptions: Options = null
)(implicit loc: munit.Location): Unit = {
test(name) {
val conf = Conf.parseCliArgs[Options](args).get
val obtainedOptions = ConfDecoder[Options].read(conf).get
val obtained = toString(obtainedOptions)
val expected = toString(expectedOptions)
assertNoDiff(obtained, expected)
if (null != unexpectedOptions)
assertNotEquals(obtained, toString(unexpectedOptions))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package metaconfig.cli

import scala.collection.immutable.ListMap

import metaconfig._

class CliParserSuite extends BaseCliParserSuite {
Expand Down Expand Up @@ -157,6 +159,38 @@ class CliParserSuite extends BaseCliParserSuite {
)
)

check(
"mapCustom2",
"--site.custom2.key1" :: "value1" ::
"--site.custom2.key2" :: "value2" ::
"--site.custom2.key3" :: "value3" ::
"--site.custom2.key4" :: "value4" ::
"--site.custom2.key5" :: "value5" ::
Nil,
Options(
site = Site(
custom2 = ListMap(
"key1" -> "value1",
"key2" -> "value2",
"key3" -> "value3",
"key4" -> "value4",
"key5" -> "value5"
)
)
),
Options(
site = Site(
custom2 = ListMap(
"key5" -> "value5",
"key2" -> "value2",
"key3" -> "value3",
"key4" -> "value4",
"key1" -> "value1"
)
)
)
)

check(
"inline",
"--foo" :: "blah" ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ class CliSuite extends munit.FunSuite {
|--config-path String (default: "fox.conf")
|--remaining-args List[String] (default: [])
|--conf Conf (default: {})
|--site Site (default: {"foo": "foo", "custom": {}})
|--site Site (default: {"foo": "foo", "custom": {}, "custom2": {}})
|--foo String (default: "foo")
|--custom Map[String, String] (default: {})
|--custom2 ListMap[String, String] (default: {})
|""".stripMargin
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class HoconPrinterRoundtripSuite extends munit.ScalaCheckSuite {
val a = Conf.parseString(conf).get
val hocon = Conf.printHocon(a)
val b = Conf.parseString(hocon).get
val isEqual = a == b
assertEquals(a, b)
}
def ignore(conf: String): Unit = super.test(conf.ignore) {}
Expand Down

0 comments on commit fa9839a

Please sign in to comment.