Skip to content

Commit a744873

Browse files
authored
Merge pull request #89 from GeluOltean/master
Define ShortClassNameSnakeCase TypeTags
2 parents 3a7908a + e0496fc commit a744873

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ThisBuild / scalaVersion := "2.13.3"
77

88
ThisBuild / crossScalaVersions := Seq(scalaVersion.value, "2.12.8")
99

10-
ThisBuild / versionPolicyIntention := Compatibility.BinaryAndSourceCompatible
10+
ThisBuild / versionPolicyIntention := Compatibility.BinaryCompatible
1111
// Temporary, because version 10.0.0 was invalid
1212
ThisBuild / versionPolicyPreviousVersions := Seq("10.0.1")
1313

library/src/main/scala/julienrf/json/derived/typetags.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package julienrf.json.derived
22

3-
import play.api.libs.json.{JsObject, JsResult, JsValue, Json, OFormat, OWrites, Reads, Writes, __}
3+
import play.api.libs.json.{JsObject, JsValue, Json, OFormat, OWrites, Reads, Writes, __}
44
import shapeless.Witness
55
import shapeless.labelled.FieldType
66
import scala.language.higherKinds
@@ -223,6 +223,16 @@ object TypeTag {
223223
}
224224
}
225225

226+
/** Use the class name converted to use snake_case as a type tag */
227+
trait ShortClassNameSnakeCase[A] extends TypeTag[A]
228+
229+
object ShortClassNameSnakeCase {
230+
implicit def fromWitness[K <: Symbol, A](implicit wt: Witness.Aux[K]): ShortClassNameSnakeCase[FieldType[K, A]] =
231+
new ShortClassNameSnakeCase[FieldType[K, A]] {
232+
def value: String = play.api.libs.json.JsonNaming.SnakeCase.apply(wt.value.name)
233+
}
234+
}
235+
226236
/** Use the fully qualified JVM name of the class as a type tag */
227237
trait FullClassName[A] extends TypeTag[A]
228238

@@ -258,6 +268,10 @@ object TypeTagSetting {
258268
type Value[A] = TypeTag.ShortClassName[A]
259269
}
260270

271+
object ShortClassNameSnakeCase extends TypeTagSetting {
272+
type Value[A] = TypeTag.ShortClassNameSnakeCase[A]
273+
}
274+
261275
object FullClassName extends TypeTagSetting {
262276
type Value[A] = TypeTag.FullClassName[A]
263277
}

library/src/test/scala/julienrf/json/derived/DerivedOFormatSuite.scala

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import org.scalacheck.{Arbitrary, Gen}
44
import org.scalacheck.Arbitrary.arbitrary
55
import org.scalatest.featurespec.AnyFeatureSpec
66
import org.scalatestplus.scalacheck.Checkers
7-
import play.api.libs.json.{Format, JsNumber, Json, OFormat, OWrites, Reads, Writes, __}
7+
import play.api.libs.json.{Format, JsArray, JsNumber, JsObject, Json, OFormat, OWrites, Reads, Writes, __}
88

99
class DerivedOFormatSuite extends AnyFeatureSpec with Checkers {
1010

@@ -161,7 +161,10 @@ class DerivedOFormatSuite extends AnyFeatureSpec with Checkers {
161161
}
162162
}
163163

164-
Feature("user-defined type tags") {
164+
Feature("type tags") {
165+
import TestHelpers._
166+
import julienrf.json.derived
167+
165168
Scenario("user-defined type tags") {
166169
sealed trait Foo
167170
case class Bar(x: Int) extends Foo
@@ -177,6 +180,23 @@ class DerivedOFormatSuite extends AnyFeatureSpec with Checkers {
177180
assert(json == Json.obj("_bar_" -> Json.obj("x" -> 42)))
178181
assert(fooFormat.reads(json).asEither == Right(foo))
179182
}
183+
184+
Scenario("ShortClassNameSnakeCase should format tag names using snake casing") {
185+
implicit lazy val demoClassFormat: OFormat[CompositeNameClass] = derived
186+
.withTypeTag
187+
.oformat[CompositeNameClass](TypeTagSetting.ShortClassNameSnakeCase)
188+
189+
val inner = Seq(FooBar(true), fooBarry(true), foo_barrier(true))
190+
val barFoo: CompositeNameClass = BarFoo(inner)
191+
val parsed = Json.toJsObject(barFoo)
192+
val parsedInner = ((parsed \ "bar_foo") \ "inner")
193+
.as[JsArray]
194+
.value
195+
.map(_.as[JsObject])
196+
197+
assert(validSnakeNames.contains(parsed.keys.head))
198+
assert(parsedInner.map(_.keys.head).forall(validSnakeNames.contains))
199+
}
180200
}
181201

182202
Feature("user-defined implicits") {
@@ -326,4 +346,14 @@ object TestHelpers {
326346
case class X(a: Int) extends ADTBase
327347
case class Y(b: String) extends ADTBase
328348
case class Z(l: ADTBase, r: ADTBase) extends ADTBase
349+
350+
sealed trait CompositeNameClass
351+
352+
case class FooBar(inner: Boolean) extends CompositeNameClass
353+
case class fooBarry(inner: Boolean) extends CompositeNameClass
354+
case class foo_barrier(inner: Boolean) extends CompositeNameClass
355+
case class BarFoo(inner: Seq[CompositeNameClass]) extends CompositeNameClass
356+
357+
lazy val validSnakeNames: Set[String] =
358+
Set("foo_bar", "foo_barry", "foo_barrier", "bar_foo")
329359
}

0 commit comments

Comments
 (0)