aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Pretty <jon.pretty@propensive.com>2017-10-30 19:25:07 +0100
committerJon Pretty <jon.pretty@propensive.com>2017-10-30 19:25:07 +0100
commit7b776425828d27b3112ad5bddafaa7564c326536 (patch)
treebe041b460d9fced354fa6a7dabd03d7ced185d5a
parent86c66ba93b5dc15301ac305fa28e24952e232613 (diff)
downloadmagnolia-7b776425828d27b3112ad5bddafaa7564c326536.tar.gz
magnolia-7b776425828d27b3112ad5bddafaa7564c326536.tar.bz2
magnolia-7b776425828d27b3112ad5bddafaa7564c326536.zip
Support for case objects
-rw-r--r--core/src/main/scala/magnolia.scala26
-rw-r--r--examples/src/main/scala/typeclasses.scala3
-rw-r--r--tests/src/main/scala/tests.scala (renamed from tests/src/main/scala/main.scala)23
3 files changed, 37 insertions, 15 deletions
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala
index c4c8113..ae582e4 100644
--- a/core/src/main/scala/magnolia.scala
+++ b/core/src/main/scala/magnolia.scala
@@ -24,6 +24,7 @@ trait JoinContext[Tc[_], T] {
def construct[R](param: ((Param[Tc, T]) => Any)): T
def typeName: String
def parameters: List[Param[Tc, T]]
+ def isObject: Boolean
}
object Magnolia {
@@ -34,7 +35,7 @@ object Magnolia {
def generic[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
import scala.util.{Try, Success, Failure}
-
+
def javaClassName(sym: Symbol): String =
if(sym.owner.isPackage) sym.fullName
else if(sym.owner.isModuleClass) s"${javaClassName(sym.owner)}$$${sym.name}"
@@ -85,7 +86,6 @@ object Magnolia {
genericType: Type,
typeConstructor: Type,
assignedName: TermName): Tree = {
-
val searchType = appliedType(typeConstructor, genericType)
findType(genericType).map { methodName =>
val methodAsString = methodName.encodedName.toString
@@ -123,6 +123,7 @@ object Magnolia {
val typeSymbol = genericType.typeSymbol
val classType = if(typeSymbol.isClass) Some(typeSymbol.asClass) else None
val isCaseClass = classType.map(_.isCaseClass).getOrElse(false)
+ val isCaseObject = classType.map(_.isModuleClass).getOrElse(false)
val isSealedTrait = classType.map(_.isSealed).getOrElse(false)
val isValueClass = genericType <:< typeOf[AnyVal]
@@ -130,7 +131,24 @@ object Magnolia {
// FIXME: Handle AnyVals
- if(isCaseClass) {
+ if(isCaseObject) {
+ val termSym = genericType.typeSymbol.companionSymbol
+ val obj = termSym.asTerm
+ val className = obj.name.toString
+ val impl = q"""
+ ${c.prefix}.join(new _root_.magnolia.JoinContext[$typeConstructor, $genericType] {
+ def construct[R](fn: ((Param[${typeConstructor}, $genericType]) => Any)): $genericType = $obj
+ def typeName: _root_.java.lang.String = $className
+ def parameters: _root_.scala.List[Param[$typeConstructor, $genericType]] = _root_.scala.List()
+ def isObject = true
+ })
+ """
+
+ Some(q"""
+ def $assignedName: $resultType = $impl
+ $assignedName
+ """)
+ } else if(isCaseClass) {
val caseClassParameters = genericType.decls.collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
}
@@ -172,6 +190,7 @@ object Magnolia {
def typeName: _root_.java.lang.String = $className
def parameters: _root_.scala.List[Param[$typeConstructor, $genericType]] =
_root_.scala.List(..$callables)
+ def isObject = false
})
"""
@@ -181,7 +200,6 @@ object Magnolia {
"""
}
} else if(isSealedTrait) {
-
val subtypes = classType.get.knownDirectSubclasses.to[List]
if(subtypes.isEmpty) {
diff --git a/examples/src/main/scala/typeclasses.scala b/examples/src/main/scala/typeclasses.scala
index d3017e5..ed59eda 100644
--- a/examples/src/main/scala/typeclasses.scala
+++ b/examples/src/main/scala/typeclasses.scala
@@ -14,7 +14,7 @@ import scala.annotation.unchecked.uncheckedVariance
object Show {
def join[T](context: JoinContext[Show, T])(value: T): String = context.parameters.map { param =>
s"${param.label}=${param.typeclass.show(param.dereference(value))}"
- }.mkString(s"{", ",", "}")
+ }.mkString(s"${context.typeName.split("\\.").last}(", ",", ")")
def split[T](subclasses: List[Subclass[Show, T]])(value: T): String =
subclasses.map { sub => sub.cast.andThen { value =>
@@ -81,6 +81,7 @@ trait Decoder[T] { def decode(str: String): T }
sealed trait Tree
case class Leaf(value: String) extends Tree
case class Branch(left: Tree, right: Tree) extends Tree
+case object Bud extends Tree
sealed trait Entity
diff --git a/tests/src/main/scala/main.scala b/tests/src/main/scala/tests.scala
index 99ffe56..6bfa1bd 100644
--- a/tests/src/main/scala/main.scala
+++ b/tests/src/main/scala/tests.scala
@@ -16,18 +16,20 @@ object Tests extends TestApp {
test("construct a Show product instance") {
import examples._
Show.generic[Person].show(Person("John Smith", 34))
- }.assert(_ == """{name=John Smith,age=34}""")
+ }.assert(_ == """Person(name=John Smith,age=34)""")
test("construct a Show coproduct instance") {
import examples._
Show.generic[Person].show(Person("John Smith", 34))
- }.assert(_ == "{name=John Smith,age=34}")
+ }.assert(_ == "Person(name=John Smith,age=34)")
+ Show.generic[Tree]
+
test("serialize a Branch") {
import magnolia.examples._
implicitly[Show[Branch]].show(Branch(Leaf("LHS"), Leaf("RHS")))
- }.assert(_ == "{left={value=LHS},right={value=RHS}}")
-
+ }.assert(_ == "Branch(left=Leaf(value=LHS),right=Leaf(value=RHS))")
+
test("test equality false") {
import examples._
Eq.generic[Entity].equal(Person("John Smith", 34), Person("", 0))
@@ -63,15 +65,11 @@ object Tests extends TestApp {
test("serialize a Leaf") {
implicitly[Show[Leaf]].show(Leaf("testing"))
- }.assert(_ == "{value=testing}")
+ }.assert(_ == "Leaf(value=testing)")
test("serialize a Branch as a Tree") {
implicitly[Show[Tree]].show(Branch(Leaf("LHS"), Leaf("RHS")))
- }.assert(_ == "{left={value=LHS},right={value=RHS}}")
-
- /*test("construct a decoder") {
- Decoder.generic[Tree].decode("string")
- }.assert(_ == (Leaf("something"): Tree))*/
+ }.assert(_ == "Branch(left=Leaf(value=LHS),right=Leaf(value=RHS))")
test("show error stack") {
scalac"""
@@ -84,5 +82,10 @@ object Tests extends TestApp {
| in parameter 'integer' of product type Alpha
| in parameter 'alpha' of product type Beta
|"""): Compilation))
+
+ //test("construct a decoder") {
+ //Decoder.generic[Tree].decode("string")
+ //}.assert(_ == (Leaf("something"): Tree))
+
}
}