Skip to content

Commit d738787

Browse files
Merge pull request #13 from alexarchambault/product-prefix
Override productPrefix and productElementName
2 parents a5b9faa + a94b548 commit d738787

File tree

6 files changed

+169
-1
lines changed

6 files changed

+169
-1
lines changed

src/main/scala/dataclass/Macros.scala

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import scala.annotation.tailrec
66
private[dataclass] class Macros(val c: Context) extends ImplTransformers {
77
import c.universe._
88

9+
import dataclass.Macros._
10+
911
private val debug = sys.env
1012
.get("DATACLASS_MACROS_DEBUG")
1113
.map(_.toBoolean)
@@ -165,12 +167,38 @@ private[dataclass] class Macros(val c: Context) extends ImplTransformers {
165167
}
166168

167169
val productMethods = {
170+
171+
val prodElemNameMethods =
172+
if (productElemNameAvailable) {
173+
val elemNameCases = paramss.flatten.zipWithIndex
174+
.map {
175+
case (param, idx) =>
176+
val name = param.name.decodedName.toString
177+
cq"$idx => $name"
178+
}
179+
180+
Seq(
181+
q"""
182+
override def productElementName(n: _root_.scala.Int): _root_.java.lang.String =
183+
n match {
184+
case ..$elemNameCases
185+
case n => throw new _root_.java.lang.IndexOutOfBoundsException(n.toString)
186+
}
187+
"""
188+
)
189+
} else
190+
Nil
191+
168192
val elemCases = paramss.flatten.zipWithIndex
169193
.map {
170194
case (param, idx) =>
171195
cq"$idx => this.${param.name}"
172196
}
173197
Seq(
198+
q"""
199+
override def productPrefix: _root_.java.lang.String =
200+
${tpname.decodedName.toString}
201+
""",
174202
q"""
175203
override def productArity: _root_.scala.Int = ${allParams.length}
176204
""",
@@ -181,7 +209,7 @@ private[dataclass] class Macros(val c: Context) extends ImplTransformers {
181209
case n => throw new _root_.java.lang.IndexOutOfBoundsException(n.toString)
182210
}
183211
"""
184-
)
212+
) ++ prodElemNameMethods
185213
}
186214

187215
val toStringMethod =
@@ -397,3 +425,13 @@ private[dataclass] class Macros(val c: Context) extends ImplTransformers {
397425
}
398426

399427
}
428+
429+
object Macros {
430+
431+
// productElementName added in 2.13
432+
private[dataclass] val productElemNameAvailable = {
433+
val sv = scala.util.Properties.versionNumberString
434+
!sv.startsWith("2.11.") && !sv.startsWith("2.12.")
435+
}
436+
437+
}

src/test/scala/dataclass/MoreFieldsTests.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dataclass
22

3+
import dataclass.TestUtil._
34
import shapeless.test.illTyped
45
import utest._
56

@@ -117,6 +118,40 @@ object MoreFieldsTests extends TestSuite {
117118
} catch {
118119
case _: IndexOutOfBoundsException =>
119120
}
121+
122+
if (productElemNameAvailable) {
123+
val names = foo.productElementNames.toVector
124+
val expectedNames = Seq("n", "s", "b", "d")
125+
assert(names == expectedNames)
126+
127+
try {
128+
foo.productElementName(-1)
129+
assert(false)
130+
} catch {
131+
case _: IndexOutOfBoundsException =>
132+
}
133+
134+
try {
135+
foo.productElementName(4)
136+
assert(false)
137+
} catch {
138+
case _: IndexOutOfBoundsException =>
139+
}
140+
}
141+
}
142+
143+
"productPrefix" - {
144+
@data class Foo(
145+
n: Int,
146+
s: String,
147+
@since("") b: Boolean = true,
148+
d: Double = 1.0
149+
)
150+
151+
val foo = Foo(1, "a")
152+
val prefix = foo.productPrefix
153+
val expectedPrefix = "Foo"
154+
assert(prefix == expectedPrefix)
120155
}
121156

122157
"has toString" - {

src/test/scala/dataclass/OneFieldTests.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dataclass
22

3+
import dataclass.TestUtil._
34
import shapeless.test.illTyped
45
import utest._
56

@@ -116,6 +117,33 @@ object OneFieldTests extends TestSuite {
116117
} catch {
117118
case _: IndexOutOfBoundsException =>
118119
}
120+
121+
if (productElemNameAvailable) {
122+
val names = foo.productElementNames.toVector
123+
val expectedNames = Seq("count")
124+
assert(names == expectedNames)
125+
126+
try {
127+
foo.productElementName(-1)
128+
assert(false)
129+
} catch {
130+
case _: IndexOutOfBoundsException =>
131+
}
132+
133+
try {
134+
foo.productElementName(1)
135+
assert(false)
136+
} catch {
137+
case _: IndexOutOfBoundsException =>
138+
}
139+
}
140+
}
141+
142+
"productPrefix" - {
143+
val foo = Foo(1)
144+
val prefix = foo.productPrefix
145+
val expectedPrefix = "Foo"
146+
assert(prefix == expectedPrefix)
119147
}
120148

121149
"type params" - {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dataclass
2+
3+
object TestUtil {
4+
5+
def productElemNameAvailable = dataclass.Macros.productElemNameAvailable
6+
7+
implicit class ProductElementName211_212(private val product: Product) {
8+
def productElementName(n: Int): String = ???
9+
def productElementNames: Iterator[String] = ???
10+
}
11+
12+
}

src/test/scala/dataclass/TwoFieldsTests.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dataclass
22

3+
import dataclass.TestUtil._
34
import shapeless.test.illTyped
45
import utest._
56

@@ -113,6 +114,33 @@ object TwoFieldsTests extends TestSuite {
113114
} catch {
114115
case _: IndexOutOfBoundsException =>
115116
}
117+
118+
if (productElemNameAvailable) {
119+
val names = foo.productElementNames.toVector
120+
val expectedNames = Seq("a", "other")
121+
assert(names == expectedNames)
122+
123+
try {
124+
foo.productElementName(-1)
125+
assert(false)
126+
} catch {
127+
case _: IndexOutOfBoundsException =>
128+
}
129+
130+
try {
131+
foo.productElementName(2)
132+
assert(false)
133+
} catch {
134+
case _: IndexOutOfBoundsException =>
135+
}
136+
}
137+
}
138+
139+
"productPrefix" - {
140+
val foo = Foo(1, "c")
141+
val prefix = foo.productPrefix
142+
val expectedPrefix = "Foo"
143+
assert(prefix == expectedPrefix)
116144
}
117145

118146
"type params" - {

src/test/scala/dataclass/ZeroFieldTests.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dataclass
22

3+
import dataclass.TestUtil._
34
import shapeless.test.illTyped
45
import utest._
56

@@ -111,6 +112,32 @@ object ZeroFieldTests extends TestSuite {
111112
} catch {
112113
case _: IndexOutOfBoundsException =>
113114
}
115+
116+
if (productElemNameAvailable) {
117+
val names = foo.productElementNames.toVector
118+
assert(names.isEmpty)
119+
120+
try {
121+
foo.productElementName(-1)
122+
assert(false)
123+
} catch {
124+
case _: IndexOutOfBoundsException =>
125+
}
126+
127+
try {
128+
foo.productElementName(0)
129+
assert(false)
130+
} catch {
131+
case _: IndexOutOfBoundsException =>
132+
}
133+
}
134+
}
135+
136+
"productPrefix" - {
137+
val foo = Foo()
138+
val prefix = foo.productPrefix
139+
val expectedPrefix = "Foo"
140+
assert(prefix == expectedPrefix)
114141
}
115142

116143
"serializable" - {

0 commit comments

Comments
 (0)