This repository has been archived by the owner on Apr 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ba1a651
commit b1cddf0
Showing
5 changed files
with
108 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
*.iml | ||
*.ipr | ||
*.iws | ||
.idea/ | ||
target/ | ||
*.log | ||
.DS_Store | ||
application.conf | ||
data/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name := "stringmask" | ||
|
||
version := "1.0" | ||
|
||
scalaVersion := "2.11.7" | ||
|
||
libraryDependencies ++= Seq( | ||
"org.scala-lang" % "scala-reflect" % "2.11.7", | ||
"org.scalatest" %% "scalatest" % "2.2.6" % "test" | ||
) | ||
|
||
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=0.13.11 |
66 changes: 66 additions & 0 deletions
66
src/main/scala/com/softwaremill/tostringmask/CustomizeImpl.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package com.softwaremill.tostringmask | ||
|
||
import scala.annotation.StaticAnnotation | ||
import scala.language.experimental.macros | ||
import scala.reflect.macros.whitebox | ||
|
||
class customize extends StaticAnnotation { | ||
def macroTransform(annottees: Any*): Any = macro CustomizeImpl.impl | ||
} | ||
|
||
class mask extends StaticAnnotation | ||
|
||
|
||
object CustomizeImpl { | ||
|
||
def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { | ||
import c.universe._ | ||
|
||
def extractCaseClassesParts(classDecl: ClassDef) = classDecl match { | ||
case q"case class $className(..$fields) extends ..$parents { ..$body }" => | ||
(className, fields, parents, body) | ||
} | ||
|
||
def extractNewToString(typeName: TypeName, allFields: List[Tree]) = { | ||
val fieldListTree = allFields.foldLeft(List.empty[Tree]) { case (accList, fieldTree) => | ||
fieldTree match { | ||
case q"${Modifiers(fs, nm, List(q"new mask()"))} val $field: $fieldType = $sth" => | ||
accList :+ Literal(Constant("***")) | ||
case q"$m val $field: $fieldType = $sth" => | ||
accList :+ q"$field.toString" | ||
case _ => c.abort(c.enclosingPosition, "Cannot call .toString on tree " + showRaw(fieldTree)) | ||
} | ||
} | ||
val treesAsTuple = Apply(Select(Ident(TermName("scala")), TermName("Tuple" + fieldListTree.length)), fieldListTree) | ||
val typeNameStrTree = Literal(Constant(typeName.toString)) | ||
q""" | ||
override def toString: ${typeOf[String]} = { | ||
$typeNameStrTree + $treesAsTuple | ||
} | ||
""" | ||
} | ||
|
||
def modifiedDeclaration(classDecl: ClassDef) = { | ||
val (className, fields, parents, body) = extractCaseClassesParts(classDecl) | ||
val newToString = extractNewToString(className, fields) | ||
|
||
val params = fields.asInstanceOf[List[ValDef]] map { p => p.duplicate} | ||
|
||
c.Expr[Any]( | ||
q""" | ||
case class $className ( ..$params ) extends ..$parents { | ||
$newToString | ||
..$body | ||
} | ||
""" | ||
) | ||
} | ||
|
||
annottees map (_.tree) toList match { | ||
case (classDecl: ClassDef) :: Nil => | ||
modifiedDeclaration(classDecl) | ||
case _ => | ||
c.abort(c.enclosingPosition, "Invalid annottee, expected case class.") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import java.time.ZonedDateTime | ||
|
||
import com.softwaremill.tostringmask.{customize, mask} | ||
import org.scalatest.{FlatSpec, Matchers} | ||
|
||
class ToStringMaskTest extends FlatSpec with Matchers { | ||
|
||
behavior of "masking" | ||
|
||
@customize | ||
case class User20(id: Int, @mask name: String, @mask email: String, something: Long, @mask secretDob: ZonedDateTime) | ||
|
||
it should "mask fields" in { | ||
// given | ||
val u = User20(1, "Secret Person", "secret@email.com", 15, ZonedDateTime.now()) | ||
|
||
// then | ||
u.toString should be("User20(1,***,***,15,***)") | ||
} | ||
} |