ScalaBuilder
ScalaBuilder is a new way to build objects using a ScalaFX-like DSL.
Install
Using Gradle
repositories {
mavenCentral()
}
dependencies {
implementation 'io.github.iltotore:scalabuilder_2.13:version'
}
Using SBT
libraryDependencies += "io.github.iltotore" %% "scalabuilder" % "version"
Actual problem
You have a case class:
case class Item(material: String,
amount: Int = 1,
displayName: Option[String] = Option.empty,
enchantments: Seq[Enchatment] = Seq.empty)
You can define your case class like this:
val item = Item("sword", 1, Option("King's sword"))
It can become pretty annoying to wrap in Option all your optional argument, in particular for bigger case classes.
This could be better using the builder pattern:
val item = Item.builder("sword")
.named("King's sword")
.withEnchantment(FireEnchatment(level = 2))
.build
The problem is can it feels less elegant when you use enclosed builders:
val item = Item.builder("sword")
.named("King's sword")
.withEnchantment(FireEnchatment(level = 2))
.withMeta(
WeaponMeta.builder
.withDamage(5)
.withDurability(20)
.withAttackSpeed(0.5)
.build
)
.build
Thanks to Scala's flexibility, you can define your Item like this:
val item = new Item.Builder("sword") {
name = "King's sword"
enchantments = Seq(FireEnchantment(2))
meta = new WeaponMeta.Builder {
damage = 5
durability = 10
attackSpeed = 0.5
}.build
}.build
by defining accessors like this:
private var name: Option[String] = Option.empty
def name: Option[String] = nameOpt
def name_=(value: String): Unit = nameOpt = Option(value)
Provided solution
Implicit build
Firstly, ScalaBuilder provides a simple implicit conversion method to build your object, allowing you to do:
import io.github.iltotore.scalabuilder.Builder.autoBuild
val item: Item = new Item.Builder("sword") {
name = "King's sword"
enchantments = Seq(FireEnchantment(2))
meta = new WeaponMeta.Builder {
damage = 5
durability = 10
attackSpeed = 0.5
}
}
ScalaBuilder generates the builder semi and fully-automatically using two annotations:
Property annotation on variable
You can use the @property(name)
annotation to generate variable accessors automatically:
@property("name")
private var nameOpt: Option[String] = Option.empty
will generate these methods:
private var nameOpt: Option[String] = Option.empty
def name: Option[String] = nameOpt
def name_=(value: String): Unit = nameOpt = Option(value)
Full builder generation
You can annotate your case class using `@buildable:
@buildable
case class Item(material: String,
amount: Int = 1,
displayName: Option[String] = Option.empty,
enchantments: Seq[Enchatment] = Seq.empty)
ScalaBuilder will generate your Item.Builder for you like shown before.