Skip to content

Commit 2e1451f

Browse files
committed
access default values of any class, not just case classes
1 parent 25576b0 commit 2e1451f

File tree

2 files changed

+17
-15
lines changed

2 files changed

+17
-15
lines changed

src/main/scala/Defaults.scala

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
11
package org.cvogt.scala
22

3-
import scala.reflect.macros.whitebox.Context
4-
import scala.language.dynamics
53
import scala.language.experimental.macros
4+
import scala.reflect.macros.whitebox.Context
65

76
object Defaults {
87
/** returns the given type's default values in an anonymous class instance */
9-
def apply[T]: Any = macro DefaultsMacros.defaults[T]
8+
def apply[T]: AnyRef = macro DefaultsMacros.defaults[T]
109
}
1110

1211
class DefaultsMacros( val c: Context ) {
1312
import c.universe._
14-
def defaults[T: c.WeakTypeTag] = {
13+
def defaults[T: c.WeakTypeTag]: Tree = {
1514
val T = weakTypeOf[T]
16-
if ( !isCaseClass( T ) )
17-
c.error( c.enclosingPosition, s"not a case class: $T" )
18-
val defs = caseClassFieldsTypes( T ).collect {
15+
val defs = constructorFieldsTypesDefaults( T ).collect {
1916
case ( name, tpe, Some( default ) ) => q"def ${TermName( name )}: $tpe = $default"
2017
}
2118
q"new{ ..$defs }"
2219
}
2320

24-
private def isCaseClass( tpe: Type ) = tpe.typeSymbol.isClass && tpe.typeSymbol.asClass.isCaseClass
25-
26-
private def caseClassFieldsTypes( tpe: Type ): List[( String, Type, Option[Tree] )] = {
27-
tpe.companion.member( TermName( "apply" ) ).asTerm.alternatives.find( _.isSynthetic ).get.asMethod.paramLists.flatten.zipWithIndex.map {
21+
def constructorFieldsTypesDefaults( tpe: Type ): List[( String, Type, Option[Tree] )] = {
22+
val m = tpe.decls.collectFirst {
23+
case m: MethodSymbol if m.isPrimaryConstructor => m
24+
}.head.paramLists.flatten.zipWithIndex
25+
m.map {
2826
case ( field, i ) =>
2927
(
3028
field.name.toTermName.decodedName.toString,
3129
field.infoIn( tpe ),
3230
{
33-
val method = TermName( s"apply$$default$$${i + 1}" )
31+
val method = TermName( "<init>$default$"+(i + 1) ).encodedName.toTermName
3432
tpe.companion.member( method ) match {
3533
case NoSymbol => None
3634
case _ => Some( q"${tpe.typeSymbol.companion}.$method" )

src/test/scala/DefaultsTest.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import org.cvogt.scala.Defaults
55
import org.scalatest.FunSuite
66

77
case class Foo(i: Int = 5, s: String)
8+
class Bar(i: Int = 5, s: String)
89
class DefaultsTest extends FunSuite {
9-
test( "case class" ) {
10-
val d = Defaults[Foo]
10+
test( "defaults" ) {
11+
val f = Defaults[Foo]
12+
val b = Defaults[Bar]
1113

1214
import scala.language.reflectiveCalls
13-
assert( d.i === 5 )
15+
assert( f.i === 5 )
16+
import scala.language.reflectiveCalls
17+
assert( b.i === 5 )
1418
}
1519
}

0 commit comments

Comments
 (0)