Forked from matsu-chara/OptionValueAccessor.scala
Last active
August 29, 2015 14:24
-
-
Save xuwei-k/6ea0346ba71533f207c2 to your computer and use it in GitHub Desktop.
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
name := "OptionValueAccessor" | |
version := "1.0" | |
scalaVersion := "2.11.6" | |
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value | |
scalacOptions += "-language:dynamics" |
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
package OptionValueAccessor | |
import scala.language.experimental.macros | |
import scala.reflect.macros.whitebox | |
object OptionValueAccessor { | |
implicit def unwrapOptValue[A](a: OptValue[A]): Option[A] = a.unwrap | |
implicit class OptValue[A](val unwrap: Option[A]) extends Dynamic { | |
def wrap: OptValue[A] = new OptValue(unwrap) | |
def selectDynamic(name: String): Any = macro Impl.Opt.selectDynamicImpl | |
} | |
object Impl { | |
object Opt { | |
def selectDynamicImpl(c: whitebox.Context)(name: c.Expr[String]): c.Tree = { | |
import c.universe._ | |
val nameStr = name.tree match { | |
case pq"${n: String}" if n.startsWith("_") => | |
n.drop(1) | |
case _ => | |
c.abort(c.enclosingPosition, s"#$name not found.") | |
} | |
c.typecheck(q"${c.prefix}.unwrap").tpe.typeArgs match { | |
case h :: Nil if h <:< c.typecheck(q"scala.Option[Any](null)").tpe => | |
q"new OptionValueAccessor.OptValue(${c.prefix}.unwrap.flatten.map {_.${TermName(nameStr)}})" | |
case _ => | |
q"new OptionValueAccessor.OptValue(${c.prefix}.unwrap.map {_.${TermName(nameStr)}})" | |
} | |
} | |
} | |
} | |
} |
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
package OptionValueAccessor | |
import OptionValueAccessor._ | |
object OptionValueAccessorTest { | |
case class A(foo: Int) | |
case class B(bar: Option[A]) | |
case class C(hoge: Option[B]) | |
case class D(fuga: Option[C]) | |
case class E(value: D) | |
def main(args: Array[String]): Unit = { | |
val edcba: Option[E] = Some(E(D(Some(C(Some(B(Some(A(1))))))))) | |
val x: Option[Int] = OptValue(edcba).wrap._value._fuga._hoge._bar._foo | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment