Skip to content

Commit 523a5e7

Browse files
committed
add Defaults giving access to a class's Default values
1 parent 99d3f81 commit 523a5e7

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Contents:
55

66
Type-level helpers
77
- EnumerateSingletons - listing all objects extending a sealed trait
8+
- Defaults - object giving names access to a class's default values
89

910
Collection extensions (org.cvogt.collection)
1011
- distinctBy - remove duplicates by key

src/main/scala/Defaults.scala

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.cvogt.scala
2+
3+
import scala.reflect.macros.whitebox.Context
4+
import scala.language.dynamics
5+
import scala.language.experimental.macros
6+
import macrocompat.bundle
7+
8+
object Defaults {
9+
/** returns the given type's default values in an anonymous class instance */
10+
def apply[T]: Any = macro DefaultsMacros.apply[T]
11+
}
12+
13+
@bundle
14+
class DefaultsMacros( val c: Context ) {
15+
import c.universe._
16+
def apply[T: c.WeakTypeTag] = {
17+
val T = weakTypeOf[T]
18+
if ( !isCaseClass( T ) )
19+
c.error( c.enclosingPosition, s"not a case class: $T" )
20+
val defs = caseClassFieldsTypes( T ).collect {
21+
case ( name, tpe, Some( default ) ) => q"def ${TermName( name )}: $tpe = $default"
22+
}
23+
q"new{ ..$defs }"
24+
}
25+
26+
private def isCaseClass( tpe: Type ) = tpe.typeSymbol.isClass && tpe.typeSymbol.asClass.isCaseClass
27+
28+
private def caseClassFieldsTypes( tpe: Type ): List[( String, Type, Option[Tree] )] = {
29+
tpe.companion.member( TermName( "apply" ) ).asTerm.alternatives.find( _.isSynthetic ).get.asMethod.paramLists.flatten.zipWithIndex.map {
30+
case ( field, i ) =>
31+
(
32+
field.name.toTermName.decodedName.toString,
33+
field.infoIn( tpe ),
34+
{
35+
val method = TermName( s"apply$$default$$${i + 1}" )
36+
tpe.companion.member( method ) match {
37+
case NoSymbol => None
38+
case _ => Some( q"${tpe.typeSymbol.companion}.$method" )
39+
}
40+
}
41+
)
42+
}.toList
43+
}
44+
}

src/test/scala/DefaultsTest.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.cvogt.scala.test
2+
3+
import org.cvogt.scala.Defaults
4+
5+
import org.scalatest.FunSuite
6+
7+
case class Foo(i: Int = 5, s: String)
8+
class DefaultsTest extends FunSuite {
9+
test( "case class" ) {
10+
val d = Defaults[Foo]
11+
12+
import scala.language.reflectiveCalls
13+
assert( d.i === 5 )
14+
}
15+
}

0 commit comments

Comments
 (0)