I am happy to announce a new scala library for code generation.
This scala library allows scala code generation via transforming other scala code or by creating code from scratch.
A common use case is to load this in your build tool (i.e. sbt) and configure it to generate new code via existing project code, i.e. to combine 2 or more case classes into a generated case class that will contain all fields of the combined case classes.
The library is based on scala meta.
Why code generation and not macros? Because we can see the generated src code, if it doesn’t compile we can make sense of it, we can create code outside the compilation unit (i.e. multiple classes/objects and packages from 1 src class), we get full support from ide’s, it’s as typesafe as macros because the code won’t compile if it is incorrect, we don’t have to add any libary to our project’s classpath (only to our build tool’s classpath), we can generate code not only from scala declarations but i.e. from a database, csv or xml files. On the downside we have to add it as a build step to our build tool.
The library provides a number of classes that help parsing packages, parsing classes, objects, defs, vals etc and utility code to actually read existing src files from projects.
val cgProject = com.aktit.codegen.Project( "src_generated", // the folder where the generated code will be placed "src/main/scala" // a comma sep list of all project's src folders ) val pckg=cgProject.toPackage("com.aktit.example.combine.User") pckg.classes // all classes of User.scala pckg.objects // all objects pckg.classes.flatMap(_.vals) // all vals of all classes in User.scala ... and so on
Code can also be generated from scratch using one of fromSource(), parser(), withName() or withX() methods:
PackageEx.withName("com.aktit").syntax should be("package com.aktit") PackageEx.withName("com.aktit.code") .withClasses(Seq( ClassEx.withName("MyClass1") ))
Code can then be converted to a string or straight saved into the disk:
PackageEx.withName(“com.aktit”).syntax // code as string cgProject.save(PackageEx.withName(“com.aktit”)) // code saved to src_generated/com/aktit
There is a spark extension of the library that includes common spark use cases like creating a case class from a csv file or combining multiple case class fields into 1 new case class (for joins).
There is also an experimental module that creates reflection classes from existing case classes (handy to i.e. create libraries without the need of macros or reflection)