-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
271 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
target | ||
.idea | ||
.bsp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
src/main/scala-2.11/com/github/andyglow/config/ScalaVersionSpecific.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.github.andyglow.config | ||
|
||
import scala.collection.JavaConverters._ | ||
|
||
private[config] object ScalaVersionSpecific { | ||
|
||
implicit class CollectionsToScala[T](private val coll: java.lang.Iterable[T]) extends AnyVal { | ||
|
||
def scala: Iterable[T] = coll.asScala | ||
} | ||
|
||
implicit class MapsToScala[K, V](private val coll: java.util.Map[K, V]) extends AnyVal { | ||
|
||
def scala: Map[K, V] = coll.asScala.toMap | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/scala-2.12/com/github/andyglow/config/ScalaVersionSpecific.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.github.andyglow.config | ||
|
||
import scala.collection.JavaConverters._ | ||
|
||
private[config] object ScalaVersionSpecific { | ||
|
||
implicit class CollectionsToScala[T](private val coll: java.lang.Iterable[T]) extends AnyVal { | ||
|
||
def scala: Iterable[T] = coll.asScala | ||
} | ||
|
||
implicit class MapsToScala[K, V](private val coll: java.util.Map[K, V]) extends AnyVal { | ||
|
||
def scala: Map[K, V] = coll.asScala.toMap | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/scala-2.13/com/github/andyglow/config/ScalaVersionSpecific.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.github.andyglow.config | ||
|
||
import scala.jdk.CollectionConverters._ | ||
|
||
private[config] object ScalaVersionSpecific { | ||
|
||
implicit class CollectionsToScala[T](private val coll: java.lang.Iterable[T]) extends AnyVal { | ||
|
||
def scala: Iterable[T] = coll.asScala | ||
} | ||
|
||
implicit class MapsToScala[K, V](private val coll: java.util.Map[K, V]) extends AnyVal { | ||
|
||
def scala: Map[K, V] = coll.asScala.toMap | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package com.github.andyglow.config | ||
|
||
import java.text.NumberFormat | ||
import java.{util => ju} | ||
|
||
import com.typesafe.config._ | ||
|
||
import ScalaVersionSpecific._ | ||
|
||
/** Converts typesafe config into java Properties | ||
*/ | ||
object Flatten { | ||
|
||
final case class Settings(numberFmt: NumberFormat) | ||
|
||
final object Settings { | ||
implicit val defaultSettings: Settings = { | ||
val fmt = NumberFormat.getInstance() | ||
fmt.setGroupingUsed(false) | ||
|
||
Settings( | ||
numberFmt = fmt) | ||
} | ||
} | ||
|
||
sealed trait Adapter[T] { | ||
def init: T | ||
def put(props: T, k: String, v: String): T | ||
} | ||
|
||
object Adapter { | ||
|
||
implicit object PropertiesAdapter extends Adapter[ju.Properties] { | ||
override def init: ju.Properties = new ju.Properties | ||
override def put(props: ju.Properties, k: String, v: String): ju.Properties = { | ||
props.setProperty(k, v) | ||
props | ||
} | ||
} | ||
|
||
implicit object StringMapAdapter extends Adapter[Map[String, String]] { | ||
override def init: Map[String, String] = Map.empty | ||
override def put(props: Map[String, String], k: String, v: String): Map[String, String] = props.updated(k, v) | ||
} | ||
} | ||
|
||
def apply[T](v: Config)(implicit adapter: Adapter[T], settings: Settings): T = apply(v, adapter.init) | ||
def apply[T](v: Config, init: T)(implicit adapter: Adapter[T], settings: Settings): T = move(v.root, true, Nil, init) | ||
|
||
def apply[T](v: ConfigValue)(implicit adapter: Adapter[T], settings: Settings): T = apply(v, adapter.init) | ||
def apply[T](v: ConfigValue, init: T)(implicit adapter: Adapter[T], settings: Settings): T = move(v, true, Nil, init) | ||
|
||
private def move[T](v: ConfigValue, isRoot: Boolean, path: List[String], props: T)(implicit adapter: Adapter[T], settings: Settings): T = { | ||
import settings._ | ||
def k = if (isRoot) "root" else path mkString "." | ||
|
||
v match { | ||
case ConfStr(v) => adapter.put(props, k, v) | ||
case ConfNum(v) => adapter.put(props, k, numberFmt.format(v)) | ||
case ConfBool(v) => adapter.put(props, k, v.toString) | ||
case ConfList(v) => v.scala.zipWithIndex.foldLeft(props) { case (props, (v, i)) => move(v, false, path :+ i.toString, props) } | ||
case ConfObj(v) => v.scala.foldLeft(props) { case (props, (f, v)) => move(v, false, path :+ f, props) } | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
src/test/scala/com/github/andyglow/config/FlattenSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package com.github.andyglow.config | ||
|
||
import java.{ util => ju } | ||
import com.typesafe.config.ConfigFactory | ||
import org.scalatest.matchers.should.Matchers._ | ||
import org.scalatest.funsuite._ | ||
//import ScalaVersionSpecific._ | ||
|
||
class FlattenSpec extends AnyFunSuite { | ||
import FlattenSpec._ | ||
|
||
test("apply[Map](conf)") { | ||
val props = Flatten[Map[String, String]](conf) | ||
props should contain only ( | ||
"arr.0" -> "abc", | ||
"arr.1" -> "def", | ||
"bool" -> "true", | ||
"complex.arr.0.id" -> "1", | ||
"complex.arr.0.name" -> "foo", | ||
"complex.arr.1.id" -> "2", | ||
"complex.arr.1.name" -> "bar", | ||
"double" -> "123.67", | ||
"int" -> "20", | ||
"long" -> "987234985769873", | ||
"obj.f1" -> "f1", | ||
"obj.nested.arr.0" -> "0", | ||
"obj.nested.arr.1" -> "2", | ||
"obj.nested.f2" -> "f2", | ||
"str" -> "str") | ||
} | ||
|
||
test("apply(conf, init: Map)") { | ||
val props = Flatten(conf, Map("some.initial" -> "value", "bool" -> "false")) | ||
props should contain only ( | ||
"some.initial" -> "value", | ||
"arr.0" -> "abc", | ||
"arr.1" -> "def", | ||
"bool" -> "true", | ||
"complex.arr.0.id" -> "1", | ||
"complex.arr.0.name" -> "foo", | ||
"complex.arr.1.id" -> "2", | ||
"complex.arr.1.name" -> "bar", | ||
"double" -> "123.67", | ||
"int" -> "20", | ||
"long" -> "987234985769873", | ||
"obj.f1" -> "f1", | ||
"obj.nested.arr.0" -> "0", | ||
"obj.nested.arr.1" -> "2", | ||
"obj.nested.f2" -> "f2", | ||
"str" -> "str") | ||
} | ||
|
||
|
||
test("apply[Properties](conf)") { | ||
val props = propsToMap { Flatten[ju.Properties](conf) } | ||
props should contain only ( | ||
"arr.0" -> "abc", | ||
"arr.1" -> "def", | ||
"bool" -> "true", | ||
"complex.arr.0.id" -> "1", | ||
"complex.arr.0.name" -> "foo", | ||
"complex.arr.1.id" -> "2", | ||
"complex.arr.1.name" -> "bar", | ||
"double" -> "123.67", | ||
"int" -> "20", | ||
"long" -> "987234985769873", | ||
"obj.f1" -> "f1", | ||
"obj.nested.arr.0" -> "0", | ||
"obj.nested.arr.1" -> "2", | ||
"obj.nested.f2" -> "f2", | ||
"str" -> "str") | ||
} | ||
|
||
test("apply(conf, init: Properties)") { | ||
val init = new ju.Properties | ||
init.setProperty("some.initial", "value") | ||
init.setProperty("bool", "false") | ||
val props = propsToMap { Flatten(conf, init) } | ||
props should contain only ( | ||
"some.initial" -> "value", | ||
"arr.0" -> "abc", | ||
"arr.1" -> "def", | ||
"bool" -> "true", | ||
"complex.arr.0.id" -> "1", | ||
"complex.arr.0.name" -> "foo", | ||
"complex.arr.1.id" -> "2", | ||
"complex.arr.1.name" -> "bar", | ||
"double" -> "123.67", | ||
"int" -> "20", | ||
"long" -> "987234985769873", | ||
"obj.f1" -> "f1", | ||
"obj.nested.arr.0" -> "0", | ||
"obj.nested.arr.1" -> "2", | ||
"obj.nested.f2" -> "f2", | ||
"str" -> "str") | ||
} | ||
|
||
test("apply(value)") { | ||
Flatten[Map[String, String]](conf.getValue("str")) should contain only ("root" -> "str") | ||
Flatten[Map[String, String]](conf.getValue("arr")) should contain only ("0" -> "abc", "1" -> "def") | ||
} | ||
} | ||
|
||
object FlattenSpec { | ||
|
||
val conf = ConfigFactory.parseString( | ||
"""str = str | ||
|bool = true | ||
|int = 20 | ||
|long = 987234985769873 | ||
|double = 123.67 | ||
|arr = [ abc, def ] | ||
|complex.arr = [ | ||
| { id: 1, name: foo }, | ||
| { id: 2, name: bar }] | ||
|obj { | ||
| f1 = f1 | ||
| nested { | ||
| f2 = f2 | ||
| arr = [ 0, 2 ] | ||
| } | ||
|} | ||
|""".stripMargin) | ||
|
||
private def propsToMap(props: ju.Properties): Map[String, String] = { | ||
props.stringPropertyNames().toArray(Array.empty[String]).foldLeft[Map[String, String]](Map.empty) { case (acc, k) => | ||
val v = props.getProperty(k) | ||
acc.updated(k, v) | ||
} | ||
} | ||
} |