Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Forked from matsu-chara/OptionValueAccessor.scala
Last active August 29, 2015 14:24
Show Gist options
  • Save xuwei-k/6ea0346ba71533f207c2 to your computer and use it in GitHub Desktop.
Save xuwei-k/6ea0346ba71533f207c2 to your computer and use it in GitHub Desktop.
name := "OptionValueAccessor"
version := "1.0"
scalaVersion := "2.11.6"
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
scalacOptions += "-language:dynamics"
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)}})"
}
}
}
}
}
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