Created
August 17, 2016 19:00
-
-
Save cvogt/8fc07d624d1660ad09f6b973074300c2 to your computer and use it in GitHub Desktop.
Scalable code-generation
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
import sbt._ | |
import Keys._ | |
import Tests._ | |
object stagedBuild extends Build { | |
lazy val mainProject = Project( | |
id="main", | |
base=file("."), | |
settings = sharedSettings ++ Seq( | |
slick <<= codeGenTask, // register manual sbt command | |
sourceGenerators in Compile <+= codeGenTask // register automatic code generation on every compile, remove for only manual use | |
) | |
).dependsOn( codegenProject ) | |
/** codegen project containing the customized code generator */ | |
lazy val codegenProject = Project( | |
id="codegen", | |
base=file("codegen"), | |
settings = sharedSettings | |
) | |
// shared sbt config between main project and codegen project | |
val sharedSettings = Project.defaultSettings ++ Seq( | |
scalaVersion := "2.11.7" | |
) | |
// code generation task that calls the customized code generator | |
lazy val slick = TaskKey[Seq[File]]("codegen") | |
lazy val codeGenTask = (sourceManaged, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) => | |
val outputDir = (dir / "generated").getPath // place generated files in sbt's managed sources folder | |
toError(r.run("demo.CodeGen", cp.files, Array(outputDir), s.log)) | |
val fname = outputDir + "/demo/Generated.scala" | |
Seq(file(fname)) | |
} | |
} |
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
package demo | |
trait Type{ | |
def scalaName: String | |
def mongooseName: String | |
} | |
object StringType extends Type{ | |
def scalaName = "String" | |
def mongooseName = "String" | |
} | |
object IntType extends Type{ | |
def scalaName = "Int" | |
def mongooseName = "Integer" | |
} | |
case class Entity( | |
mongoName: String, | |
scalaName: String, | |
fields: Map[String, Type], | |
parents: Seq[String], | |
body: String | |
) | |
object Model{ | |
val traits = List( "Foo", "Bar" ) | |
val entities = List( | |
Entity( | |
mongoName = "person", | |
scalaName = "Person", | |
fields = Map( | |
"name" -> StringType, | |
"age" -> IntType | |
), | |
Seq("Foo","Bar") | |
) | |
) | |
} | |
case class CodeGenerator(model: Model.type){ | |
import model._ | |
case class ClassGenerator( entity: Entity ){ | |
def parents = if(entity.parents.isEmpty)"" else ("extends " ++ entity.parents.mkString(" with ")) | |
def generate = ( | |
""" | |
package demo | |
""" | |
++ | |
traits.map(t => "sealed trait "+t).mkString("\n") | |
++ | |
s""" | |
/** maps to mongo collection ${entity.mongoName} */ | |
case class ${entity.scalaName}("""++entity.fields.map{case(name, tpe) => name++": "++tpe.scalaName}.mkString(", ")++s""") $parents{ | |
$body | |
} | |
object ${entity.scalaName}{ | |
implicit def jsonFormat: Format[${entity.scalaName}] = Json.format | |
} | |
""" | |
) | |
} | |
def generate = entities.map(ClassGenerator(_).generate).mkString | |
} | |
object CodeGen{ | |
def main(args: Array[String]) = { | |
//val outputDir = args.head | |
val output: String = CodeGenerator(Model).generate | |
println(output) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I was trying this generator. It was at first giving error that the path doesn't exist. So I created the path, including an empty file. Then the error is not coming, but nothing is getting generated in the file.
println(output)
is however printing the generated code.I am new to the custom sbt tasks, so not sure what is going wrong.