-
Notifications
You must be signed in to change notification settings - Fork 115
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
Magnolia derivation for Debug typeclass #1371
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package zio.debug.magnolia | ||
|
||
import zio.Scope | ||
import zio.prelude._ | ||
import zio.test.Assertion._ | ||
import zio.test.{ZIOSpecDefault, _} | ||
|
||
case class Lair(name: String, animal: Animal) | ||
|
||
object Lair { | ||
implicit val debug: Debug[Lair] = DeriveDebug.derived[Lair] | ||
} | ||
|
||
case class Animal(name: String, age: Int) | ||
|
||
object Animal { | ||
implicit val debug: Debug[Animal] = DeriveDebug.derived[Animal] | ||
} | ||
|
||
case class Adult(name: String, age: Int, chidren: List[Child]) | ||
case class Child(name: String, age: Int) | ||
|
||
object Adult { | ||
implicit val debug: Debug[Adult] = DeriveDebug.derived[Adult] | ||
} | ||
|
||
object Child { | ||
implicit val debug: Debug[Child] = DeriveDebug.derived[Child] | ||
} | ||
|
||
object Test extends ZIOSpecDefault { | ||
|
||
override def spec: Spec[TestEnvironment with Scope, Any] = | ||
suite("DeriveDebug")( | ||
test("should derive Debug for case class") { | ||
val animal = Animal("tiger", 10) | ||
|
||
assert(animal.debug.render)(equalTo("Animal(name = \"tiger\", age = 10)")) | ||
|
||
}, | ||
test("should derive Debug for nested case class") { | ||
val lair = Lair("jungle", Animal("tiger", 10)) | ||
|
||
assert(lair.debug.render)(equalTo("Lair(name = \"jungle\", animal = Animal(name = \"tiger\", age = 10))")) | ||
}, | ||
test("should derive Debug for case class with list") { | ||
val adult = Adult("John", 30, List(Child("Alice", 5), Child("Bob", 10))) | ||
|
||
assert(adult.debug.render)( | ||
equalTo( | ||
"Adult(name = \"John\", age = 30, chidren = List(Child(name = \"Alice\", age = 5), Child(name = \"Bob\", age = 10)))" | ||
) | ||
) | ||
} | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package zio.debug.magnolia | ||
|
||
import magnolia1._ | ||
import zio.prelude.Debug | ||
import zio.prelude.Debug.Repr | ||
|
||
import scala.collection.immutable.ListMap | ||
|
||
object DeriveDebug { | ||
|
||
type Typeclass[T] = Debug[T] | ||
|
||
def join[T](ctx: CaseClass[Debug, T]): Debug[T] = | ||
if (ctx.isValueClass) { (a: T) => | ||
Repr.VConstructor( | ||
ctx.typeName.owner.split('.').toList, | ||
ctx.typeName.short, | ||
ctx.parameters.map(p => p.typeclass.debug(p.dereference(a))).toList | ||
) | ||
} else if (ctx.isObject) { (_: T) => | ||
Repr.Object(ctx.typeName.owner.split('.').toList, ctx.typeName.short) | ||
} else { (a: T) => | ||
Repr.Constructor( | ||
ctx.typeName.owner.split('.').toList, | ||
ctx.typeName.short, | ||
ListMap.apply(ctx.parameters.map(p => p.label -> p.typeclass.debug(p.dereference(a))): _*) | ||
) | ||
} | ||
|
||
def split[T](ctx: SealedTrait[Debug, T]): Debug[T] = | ||
new Debug[T] { self => | ||
def debug(a: T): Repr = ctx.split(a) { sub => | ||
sub.typeclass.debug(sub.cast(a)) | ||
} | ||
} | ||
|
||
def derived[T]: Debug[T] = macro Magnolia.gen[T] | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about adding an extension method on the Debug companion object, so that it also contains the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whhhhhaou that exactly what I did not knew how to do ! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hum, I suppose then that I should merge magnolia and core module, right ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Nope. Have That's why we'll make it an extension method of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :-/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok @sideeffffect I found :S |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package zio.debug.magnolia | ||
|
||
import magnolia1._ | ||
|
||
import scala.collection.immutable.ListMap | ||
import scala.language.experimental.macros | ||
import zio.prelude.Debug | ||
import zio.prelude.Debug.Repr | ||
|
||
object DeriveDebug extends AutoDerivation[Debug] { | ||
|
||
type Typeclass[T] = Debug[T] | ||
|
||
def join[T](ctx: CaseClass[Debug, T]): Debug[T] = | ||
if (ctx.isValueClass) { (a: T) => | ||
Repr.VConstructor( | ||
ctx.typeInfo.owner.split('.').toList, | ||
ctx.typeInfo.short, | ||
ctx.parameters.map(p => p.typeclass.debug(p.deref(a))).toList | ||
) | ||
} else if (ctx.isObject) { (_: T) => | ||
Repr.Object(ctx.typeInfo.owner.split('.').toList, ctx.typeInfo.short) | ||
} else { (a: T) => | ||
Repr.Constructor( | ||
ctx.typeInfo.owner.split('.').toList, | ||
ctx.typeInfo.short, | ||
ListMap.from(ctx.parameters.map(p => p.label -> p.typeclass.debug(p.deref(a)))) | ||
) | ||
} | ||
|
||
def split[T](ctx: SealedTrait[Debug, T]): Debug[T] = | ||
new Debug[T] { self => | ||
def debug(a: T): Repr = ctx.choose(a) { sub => | ||
sub.typeclass.debug(sub.cast(a)) | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,6 +76,17 @@ object BuildHelper { | |
Test / parallelExecution := false | ||
) | ||
|
||
val magnoliaSettings = | ||
libraryDependencies += { | ||
scalaVersion.value match { | ||
case Scala3 => | ||
"com.softwaremill.magnolia1_3" %% "magnolia" % "1.3.7" | ||
case _ => | ||
"com.softwaremill.magnolia1_2" %% "magnolia" % "1.1.10" | ||
// libraryDependencies += compilerPlugin("org.typelevel" %% "kind-projector" % "0.13.3" cross CrossVersion.full) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commented code in build |
||
} | ||
} | ||
|
||
// Keep this consistent with the version in .core-tests/shared/src/test/scala/REPLSpec.scala | ||
val replSettings = makeReplSettings { | ||
"""|import zio._ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package name should be
zio.prelude.magnolia
.