jonathan chow [PDF]

Nov 4, 2013 - Let's reduce the problem to a very specific one: taking any arbitrary case class and producing converter f

6 downloads 18 Views 2MB Size

Recommend Stories


Jonathan T. Chow
Never wish them pain. That's not who you are. If they caused you pain, they must have pain inside. Wish

CHOW CHOW
You miss 100% of the shots you don’t take. Wayne Gretzky

Rudolph Chow Presentation (PDF)
You have to expect things of yourself before you can do them. Michael Jordan

Lucky Chow
No matter how you feel: Get Up, Dress Up, Show Up, and Never Give Up! Anonymous

Jonathan Kluth Spaces 2016 PDF
Don't be satisfied with stories, how things have gone with others. Unfold your own myth. Rumi

Chow Chang Hoong
You're not going to master the rest of your life in one day. Just relax. Master the day. Than just keep

Ms. Joyce WC Chow
Courage doesn't always roar. Sometimes courage is the quiet voice at the end of the day saying, "I will

Winnie Ng Olivia Chow
I want to sing like the birds sing, not worrying about who hears or what they think. Rumi

Jonathan Greensmith
We must be willing to let go of the life we have planned, so as to have the life that is waiting for

Jonathan Baltrusaitis
Goodbyes are only for those who love with their eyes. Because for those who love with heart and soul

Idea Transcript


#defines

Map[String, Any]

trait Mappable[T] { def toMap(t: T): Map[String, Any] def fromMap(map: Map[String, Any]): T }

Mappable[T]

T

case class Person(name: String, age: Int) val PersonMapper = new Mappable[Person] { def toMap(p: Person) = Map( "name" -> p.name, "age" -> p.age) def fromMap(map: Map[String, Any]) = Person( map("name").asInstanceOf[String] map("age").asInstanceOf[Int]) }

Person

case class Person(name: String, age: Int, height: Double) val PersonMapper = new Mappable[Person] { // toMap: compiles even though it's incorrect def toMap(p: Person) = Map( "name" -> p.name, "age" -> p.age) // fromMap: fails to compile (as it should) def fromMap(map: Map[String, Any]) = Person( map("name").asInstanceOf[String] map("age").asInstanceOf[Int]) }

fromMap toMap

height

Mappable

import scala.reflect.macros.Context object Mappable { implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T] def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = { import c.universe._ val tpe = weakTypeOf[T] c.Expr[Mappable[T]] { q""" new Mappable[$tpe] { def toMap(t: $tpe) = ??? def fromMap(map: Map[String, Any]) = ??? } """ } }

implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T]

Mappable

macro materializeMappableImpl

def personToMap(p: Person) = { val mapper = materializeMappable[Person] mapper.toMap(p) }

Mapper[T]

// the compiler will insert materializeMappable[T] as the implicit parameter def mapify[T](t: T)(implicit mapper: Mappable[T]) = mapper.toMap(t)

def mapify[T: Mappable](t: T) = implicitly[Mappable[T]].toMap(t)

def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = { import c.universe._ // _... }

val tpe = weakTypeOf[T] c.Expr[Mappable[T]] { q""" new Mappable[$tpe] { def toMap(t: $tpe) = ??? def fromMap(map: Map[String, Any]) = ??? } """ }

WeakTypeTag

reify

splice

$variable reify

Expr Expr

Expr

Mappable[T] tpe

T

??? Mappable

Mapper

isCaseAccessor

fromMap

tpe declarations members

val declarations = tpe.declarations val ctor = declarations.collectFirst { case m: MethodSymbol if m.isPrimaryConstructor => m }.get val params = ctor.paramss.head

paramss

head

toMap

def toMap(p: Person) = Map( "name" -> p.name, "age" -> p.age)

Map.apply

String ->

val toMapParams = fields.map { field => val name = field.name val mapKey: String = name.decoded q"$mapKey -> t.$name" }

mapKey

String

String

Liftable

Literal(Constant(mapKey))

$op_names

contenttype

content$minustype t t t

toMap toMap

t

t

toMap

c.Expr[Mappable[T]] { q""" new Mappable[$tpe] { def toMap(t: $tpe) = Map(..$toMapParams) def fromMap(map: Map[String, Any]) = ??? } """ }

toMap

t ..$toMapParams List[T]

...

List[List[T]]

fromMap

Mappable

toMap

def mapify[T: Mappable](t: T) = implicitly[Mappable[T]].toMap(t) case class Item(name: String, price: Double) val map = mapify(Item("lunch", 15.5)) println(map("name")) // "lunch" println(map("price")) // 15.5

fromMap

def fromMap(map: Map[String, Any]) = Person( map("name").asInstanceOf[String] map("age").asInstanceOf[Int])

toMap

apply tpe

val companion = tpe.typeSymbol.companionSymbol def returnType(name: Name) = tpe.declaration(name).typeSignature

toMap fromMap

val fromMapParams = fields.map { field => val name = field.name val decoded = name.decoded val returnType = tpe.declaration(name).typeSignature q"map($decoded).asInstanceOf[$returnType]" } c.Expr[Mappable[T]] { q""" new Mappable[$tpe] { def toMap(t: $tpe) = Map(..$toMapParams) def fromMap(map: Map[String, Any]) = $companion(..$fromMapParams) } """ }

String map

fromMap apply

apply

def materialize[T: Mappable](map: Map[String, Any]) = implicitly[Mappable[T]].fromMap(map) case class Item(name: String, price: Double) val item = materialize[Item](Map("name" -> "dinner", "price" -> 25.8)) println(item.name) // "dinner" println(item.price) // 25.8

complete-example

import scala.reflect.macros.Context trait Mappable[T] { def toMap(t: T): Map[String, Any] def fromMap(map: Map[String, Any]): T } object Mappable { implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T] def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = { import c.universe._ val tpe = weakTypeOf[T] val companion = tpe.typeSymbol.companionSymbol val fields = tpe.declarations.collectFirst { case m: MethodSymbol if m.isPrimaryConstructor Þ m }.get.paramss.head val (toMapParams, fromMapParams) = fields.map { field Þ val name = field.name val decoded = name.decoded val returnType = tpe.declaration(name).typeSignature (q"$decoded Õ t.$name", q"map($decoded).asInstanceOf[$returnType]") }.unzip c.Expr[Mappable[T]] { q""" new Mappable[$tpe] { def toMap(t: $tpe): Map[String, Any] = Map(..$toMapParams) def fromMap(map: Map[String, Any]): $tpe = $companion(..$fromMapParams) } """ } } }

Smile Life

When life gives you a hundred reasons to cry, show life that you have a thousand reasons to smile

Get in touch

© Copyright 2015 - 2024 PDFFOX.COM - All rights reserved.