Skip to content

Instantly share code, notes, and snippets.

@afsalthaj
Last active August 10, 2018 14:27
Show Gist options
  • Save afsalthaj/2e019e81e22a89f6dc49047e0cefd30e to your computer and use it in GitHub Desktop.
Save afsalthaj/2e019e81e22a89f6dc49047e0cefd30e to your computer and use it in GitHub Desktop.
// 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