-
Notifications
You must be signed in to change notification settings - Fork 21
Pureconfig Toggle #982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Pureconfig Toggle #982
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
20c3271
Add Toggle trait to pureconfig module
3b4e3dc
unit tests refactor
64d0394
remove instances package
11e392d
remove unused imports
b562779
unit test fix
5c5ae80
more unit tests
9c011e2
scala 3 unit test fix
c6dd498
readme
0d1df5e
scala 3 unit test fix
82839b6
review fixes
7d1ac8e
unit tests fix
2e3130e
Update site/docs/subprojects/pureconfig.md
nb-ceffa cd7b11f
Update site/docs/subprojects/pureconfig.md
nb-ceffa ef2758b
Update site/docs/subprojects/pureconfig.md
nb-ceffa f48357a
Update site/docs/subprojects/pureconfig.md
nb-ceffa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
pureconfig/src/main/scala/com/avast/sst/pureconfig/WithConfig.scala
This file contains hidden or 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.avast.sst.pureconfig | ||
|
||
import com.typesafe.config.Config | ||
import pureconfig.ConfigReader | ||
|
||
/** Used to retrieve both parsed configuration object and underlying [[Config]] instance. */ | ||
final case class WithConfig[T](value: T, config: Config) | ||
|
||
object WithConfig { | ||
implicit def configReader[T: ConfigReader]: ConfigReader[WithConfig[T]] = | ||
for { | ||
config <- ConfigReader[Config] | ||
value <- ConfigReader[T] | ||
} yield WithConfig(value, config) | ||
|
||
} |
114 changes: 114 additions & 0 deletions
114
pureconfig/src/main/scala/com/avast/sst/pureconfig/util/Toggle.scala
This file contains hidden or 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,114 @@ | ||
package com.avast.sst.pureconfig.util | ||
|
||
import cats.{FlatMap, Functor, Monad, Monoid, Order, Semigroup} | ||
|
||
import java.util.Collections | ||
import com.typesafe.config.ConfigValueFactory | ||
import pureconfig.{ConfigReader, ConfigWriter} | ||
|
||
import scala.annotation.tailrec | ||
|
||
sealed trait Toggle[+T] { | ||
def toOption: Option[T] | ||
def fold[A](empty: => A, fromValue: T => A): A | ||
def isEmpty: Boolean | ||
} | ||
|
||
object Toggle { | ||
final case class Enabled[+T](value: T) extends Toggle[T] { | ||
override def toOption: Option[T] = Some(value) | ||
override def fold[A](empty: => A, fromValue: T => A): A = fromValue(value) | ||
override def isEmpty: Boolean = false | ||
def get: T = value | ||
} | ||
case object Disabled extends Toggle[Nothing] { | ||
override def toOption: Option[Nothing] = None | ||
override def fold[A](empty: => A, fromValue: Nothing => A): A = empty | ||
override def isEmpty: Boolean = true | ||
} | ||
|
||
object TogglePureConfigInstances { | ||
implicit def toggleConfigReader[T: ConfigReader]: ConfigReader[Toggle[T]] = { | ||
ConfigReader | ||
.forProduct1[ConfigReader[Toggle[T]], Boolean]("enabled") { enabled => | ||
if (enabled) implicitly[ConfigReader[T]].map(Enabled[T]) | ||
else ConfigReader.fromCursor(_ => Right(Disabled)) | ||
} | ||
.flatMap(identity) | ||
} | ||
|
||
implicit def toggleConfigWriter[T: ConfigWriter]: ConfigWriter[Toggle[T]] = { | ||
ConfigWriter.fromFunction[Toggle[T]] { | ||
case Enabled(value) => ConfigWriter[T].to(value).withFallback(ConfigValueFactory.fromMap(Collections.singletonMap("enabled", true))) | ||
case Disabled => ConfigValueFactory.fromMap(Collections.singletonMap("enabled", false)) | ||
} | ||
} | ||
} | ||
|
||
object ToggleStdInstances { | ||
implicit val functorForToggle: Functor[Toggle] = new ToggleFunctor | ||
implicit val flatMapForToggle: FlatMap[Toggle] = new ToggleFlatMap | ||
implicit val monadForToggle: Monad[Toggle] = new ToggleMonad | ||
implicit def monoidForToggle[A: Semigroup]: Monoid[Toggle[A]] = new ToggleMonoid[A] | ||
implicit def orderForToggle[A: Order]: Order[Toggle[A]] = new ToggleOrder[A] | ||
} | ||
|
||
class ToggleFunctor extends Functor[Toggle] { | ||
override def map[A, B](fa: Toggle[A])(f: A => B): Toggle[B] = { | ||
fa match { | ||
case Enabled(value) => Enabled(f(value)) | ||
case Disabled => Disabled | ||
} | ||
} | ||
} | ||
|
||
class ToggleFlatMap extends ToggleFunctor with FlatMap[Toggle] { | ||
override def flatMap[A, B](fa: Toggle[A])(f: A => Toggle[B]): Toggle[B] = { | ||
fa match { | ||
case Enabled(value) => f(value) | ||
case Disabled => Disabled | ||
} | ||
} | ||
|
||
override def tailRecM[A, B](a: A)(f: A => Toggle[Either[A, B]]): Toggle[B] = tailRecMPrivate(a)(f) | ||
|
||
@tailrec | ||
private def tailRecMPrivate[A, B](a: A)(f: A => Toggle[Either[A, B]]): Toggle[B] = { | ||
f(a) match { | ||
case Enabled(Left(value)) => tailRecMPrivate(value)(f) | ||
case Enabled(Right(value)) => Enabled(value) | ||
case Disabled => Disabled | ||
} | ||
} | ||
} | ||
|
||
class ToggleMonad extends ToggleFlatMap with Monad[Toggle] { | ||
override def pure[A](x: A): Toggle[A] = Enabled(x) | ||
} | ||
|
||
class ToggleMonoid[A](implicit A: Semigroup[A]) extends Monoid[Toggle[A]] { | ||
override def empty: Toggle[A] = Disabled | ||
override def combine(x: Toggle[A], y: Toggle[A]): Toggle[A] = | ||
x match { | ||
case Disabled => y | ||
case Enabled(a) => | ||
y match { | ||
case Disabled => x | ||
case Enabled(b) => Enabled(A.combine(a, b)) | ||
} | ||
} | ||
} | ||
|
||
class ToggleOrder[A](implicit A: Order[A]) extends Order[Toggle[A]] { | ||
override def compare(x: Toggle[A], y: Toggle[A]): Int = | ||
x match { | ||
case Disabled => if (y.isEmpty) 0 else -1 | ||
case Enabled(a) => | ||
y match { | ||
case Disabled => 1 | ||
case Enabled(b) => A.compare(a, b) | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains hidden or 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
111 changes: 111 additions & 0 deletions
111
pureconfig/src/test/scala-2/com/avast/sst/pureconfig/ToggleTest.scala
This file contains hidden or 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,111 @@ | ||
package com.avast.sst.pureconfig | ||
|
||
import cats.{Applicative, Eq, FlatMap, Functor, Monad, Monoid} | ||
import com.avast.sst.pureconfig.util.Toggle | ||
import com.avast.sst.pureconfig.util.Toggle.{Disabled, Enabled} | ||
import org.scalatest.diagrams.Diagrams | ||
import org.scalatest.funsuite.AnyFunSuite | ||
|
||
class ToggleTest extends AnyFunSuite with Diagrams { | ||
|
||
test("has Functor instance and map method works correctly") { | ||
import com.avast.sst.pureconfig.util.Toggle.ToggleStdInstances._ | ||
|
||
val oldValue = "some value" | ||
val newValue = "new value" | ||
val toggle: Toggle[String] = Enabled(oldValue) | ||
val toggle2: Toggle[String] = Disabled | ||
val result = Functor[Toggle].map(toggle)(_ => newValue) | ||
|
||
import cats.syntax.functor._ | ||
val result2 = toggle.map(_ => newValue) | ||
|
||
val result3 = toggle2.map(_ => newValue) | ||
|
||
assert(result.fold(false, value => value === newValue)) | ||
assert(result2.fold(false, value => value === newValue)) | ||
assert(result3.fold(true, _ => false)) | ||
} | ||
|
||
test("has FlatMap instance and flatMap method works correctly") { | ||
import com.avast.sst.pureconfig.util.Toggle.ToggleStdInstances._ | ||
|
||
val oldValue = "some value" | ||
val newValue = "new value" | ||
val toggle: Toggle[String] = Enabled(oldValue) | ||
val toggle2: Toggle[String] = Disabled | ||
val result = FlatMap[Toggle].flatMap(toggle)(_ => Enabled(newValue)) | ||
|
||
import cats.syntax.flatMap._ | ||
val result2 = toggle.flatMap(_ => Enabled(newValue)) | ||
|
||
val result3 = toggle2.flatMap(_ => Enabled(newValue)) | ||
val result4 = toggle.flatMap(_ => Disabled) | ||
|
||
assert(result.fold(false, value => value === newValue)) | ||
assert(result2.fold(false, value => value === newValue)) | ||
assert(result3 === Disabled) | ||
assert(result4 === Disabled) | ||
} | ||
|
||
test("has Applicative and Monad instance and pure method works correctly") { | ||
import com.avast.sst.pureconfig.util.Toggle.ToggleStdInstances._ | ||
val value = "some value" | ||
val result = Applicative[Toggle].pure(value) | ||
val result2 = Monad[Toggle].pure(value) | ||
|
||
import cats.syntax.applicative._ | ||
val result3 = value.pure[Toggle] | ||
|
||
assert(result.fold(false, value => value === value)) | ||
assert(result2.fold(false, value => value === value)) | ||
assert(result3.fold(false, value => value === value)) | ||
} | ||
|
||
test("has Monoid instance and combine method works correctly") { | ||
import com.avast.sst.pureconfig.util.Toggle.ToggleStdInstances._ | ||
|
||
val result = Monoid[Toggle[String]].empty | ||
|
||
val value1 = 1 | ||
val value2 = 2 | ||
val toggle1: Toggle[Int] = Enabled(value1) | ||
val toggle2: Toggle[Int] = Enabled(value2) | ||
val toggle3: Toggle[Int] = Disabled | ||
|
||
import cats.syntax.monoid._ | ||
val result2 = toggle1.combine(toggle2) | ||
val result3 = toggle1.combine(Disabled) | ||
val result4 = toggle3.combine(toggle2) | ||
val result5 = toggle3.combine(Disabled) | ||
|
||
assert(result === Disabled) | ||
assert(result2.fold(false, value => value === 3)) | ||
assert(result3.fold(false, value => value === 1)) | ||
assert(result4.fold(false, value => value === 2)) | ||
assert(result5 === Disabled) | ||
} | ||
|
||
test("has Order instance and compare method works correctly") { | ||
import com.avast.sst.pureconfig.util.Toggle.ToggleStdInstances._ | ||
|
||
val value1 = 1 | ||
val value2 = 2 | ||
val toggle1: Toggle[Int] = Enabled(value1) | ||
val toggle2: Toggle[Int] = Enabled(value2) | ||
val toggle3: Toggle[Int] = Disabled | ||
|
||
import cats.syntax.order._ | ||
val result1 = toggle1.compare(toggle2) | ||
val result2 = toggle1.compare(toggle1) | ||
val result3 = toggle2.compare(toggle1) | ||
val result4 = toggle3.compare(toggle2) | ||
val result5 = toggle3.compare(Disabled) | ||
|
||
assert(result1 < 0) | ||
assert(Eq[Int].eqv(result2, 0)) | ||
assert(result3 > 0) | ||
assert(result4 < 0) | ||
assert(Eq[Int].eqv(result5, 0)) | ||
} | ||
} |
This file contains hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.