Last active
August 10, 2018 14:27
-
-
Save afsalthaj/2e019e81e22a89f6dc49047e0cefd30e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Trying to find case class names using shapeless involving a tree structure | |
import shapeless.{::, HList, HNil, LabelledGeneric, Lazy, Witness} | |
import shapeless.labelled.FieldType | |
import cats.evidence.{As, Is} | |
/** | |
* | |
* {{{ | |
case class BadVal(value: String) extends AnyVal | |
case class Bla(innerName: String, badVal: BadVal) | |
case class Afsal(s1: String, bla: Bla, s2: String) | |
case class Leigh( | |
x1: String, afsal: List[Afsal], f: String, d: BadVal, e: BadVal, | |
f2: List[BadVal], eO: Option[String], f1: Option[Afsal], f3: cats.Id[Afsal] | |
) | |
val r = Namer[Leigh] | |
println(r.names) | |
Res: | |
List( | |
x1, | |
afsal, | |
afsal.s1, | |
afsal.bla, | |
afsal.bla.innerName, | |
afsal.bla.badVal, | |
afsal.s2, | |
f, d, e, f2, eO, f1, | |
f1.s1, | |
f1.bla, | |
f1.bla.innerName, | |
f1.bla.badVal, | |
f1.s2, | |
f3, | |
f3.s1, | |
f3.bla, | |
f3.bla.innerName, | |
f3.bla.badVal, | |
f3.s2 | |
) | |
// Notes: | |
BadVal is considered as AnyVal and is nicely handled if you look at example. | |
Warning:! the implementation doesn't work for recursive data structures yet. | |
* }}} | |
* | |
*/ | |
trait Namer[A]{ | |
def names: List[String] | |
} | |
object Namer extends LowPriorityInstances0 { | |
def apply[A](implicit ev: Namer[A]): Namer[A] = ev | |
def toKey(raw: String): String = { | |
val str = new StringBuilder | |
var lastLower = false | |
raw.foreach { c => | |
if (c.isLower) { | |
lastLower = true | |
str += c | |
} else { | |
if (lastLower) str += '-' | |
lastLower = false | |
str += c.toLower | |
} | |
} | |
str.toString | |
} | |
} | |
trait LowPriorityInstances0 extends LowPriorityInstances1 { | |
implicit def hNilNamer: Namer[HNil] = | |
new Namer[HNil] { | |
def names: List[String] = Nil | |
} | |
// Needn't rely unused implicits warnings by compiler; its a lie | |
implicit def hListThatCanHaveFOfAnyVal[F[_], A, B, K <: Symbol, T <: HList]( | |
implicit | |
witness: Witness.Aux[K], | |
IsList: A Is F[B], | |
IsAnyVal: B As AnyVal, | |
D: Lazy[Namer[T]], | |
): Namer[FieldType[K, A] :: T] = | |
new Namer[FieldType[K, A] :: T]{ | |
override def names: List[String] = { | |
Namer.toKey(witness.value.name) :: D.value.names | |
} | |
} | |
implicit def namerA[A, R <: HList](implicit E: LabelledGeneric.Aux[A, R], D: Namer[R]): Namer[A] = { | |
new Namer[A] { | |
override def names: List[String] = D.names | |
} | |
} | |
} | |
trait LowPriorityInstances1 extends LowPriorityInstance2 { | |
implicit def hListWithSimpleAnyVal[A, K <: Symbol, T <: HList]( | |
implicit | |
witness: Witness.Aux[K], | |
IsAnyVal: A As AnyVal, | |
D: Lazy[Namer[T]], | |
): Namer[FieldType[K, A] :: T] = | |
new Namer[FieldType[K, A] :: T]{ | |
override def names: List[String] = { | |
Namer.toKey(witness.value.name) :: D.value.names | |
} | |
} | |
} | |
trait LowPriorityInstance2 extends LowPriorityInstance3 { | |
implicit def hLIstWithFofHListInsideIt[F[_], A, K <: Symbol, H, InnerT <: HList, T <: HList]( | |
implicit | |
witness: Witness.Aux[K], | |
IsList: H Is F[A], | |
eachH: LabelledGeneric.Aux[A, InnerT], | |
D: Lazy[Namer[T]], | |
E: Lazy[Namer[InnerT]] | |
): Namer[FieldType[K, H] :: T] = | |
new Namer[FieldType[K, H] :: T]{ | |
override def names: List[String] = { | |
Namer.toKey(witness.value.name) :: E.value.names.map(t => Namer.toKey(witness.value.name) + "." + t) ++ D.value.names | |
} | |
} | |
} | |
trait LowPriorityInstance3 extends LowPriorityInstance4 { | |
implicit def hListNamerWithHListInsideOfInsideOf[K <: Symbol, H, InnerT <: HList, T <: HList]( | |
implicit | |
witness: Witness.Aux[K], | |
eachH: LabelledGeneric.Aux[H, InnerT], | |
D: Lazy[Namer[T]], | |
E: Lazy[Namer[InnerT]] | |
): Namer[FieldType[K, H] :: T] = | |
new Namer[FieldType[K, H] :: T]{ | |
override def names: List[String] = { | |
Namer.toKey(witness.value.name) :: E.value.names.map(t => Namer.toKey(witness.value.name) + "." + t) ++ D.value.names | |
} | |
} | |
} | |
trait LowPriorityInstance4 { | |
implicit def simpleHList[A, K <: Symbol, H, T <: HList]( | |
implicit | |
witness: Witness.Aux[K], | |
D: Lazy[Namer[T]] | |
): Namer[FieldType[K, H] :: T] = | |
new Namer[FieldType[K, H] :: T]{ | |
override def names: List[String] = Namer.toKey(witness.value.name) :: D.value.names | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment