All Projects → japgolly → mr.boilerplate

japgolly / mr.boilerplate

Licence: Apache-2.0 license
Online app to generate Scala boilerplate

Programming Languages

scala
5932 projects
HTML
75241 projects

Projects that are alternatives of or similar to mr.boilerplate

Swiftcolorgen
A tool that generate code for Swift projects, designed to improve the maintainability of UIColors
Stars: ✭ 152 (+375%)
Mutual labels:  code-generator, code-generation
regen
Easy C++ reflection and code generation
Stars: ✭ 29 (-9.37%)
Mutual labels:  code-generator, code-generation
Jennifer
Jennifer is a code generator for Go
Stars: ✭ 2,257 (+6953.13%)
Mutual labels:  code-generator, code-generation
typed-astunparse
Python 3 AST unparser with type comments support.
Stars: ✭ 27 (-15.62%)
Mutual labels:  code-generator, code-generation
django-code-generator
Generate code from your Django models for faster development
Stars: ✭ 35 (+9.38%)
Mutual labels:  code-generator, code-generation
Dbcc
CAN DBC to C (and CSV, JSON and XML) compiler using the mpc parser combinator library
Stars: ✭ 142 (+343.75%)
Mutual labels:  code-generator, code-generation
evon
Fast and versatile event dispatcher code generator for Golang
Stars: ✭ 15 (-53.12%)
Mutual labels:  code-generator, code-generation
Goreuse
Generic Code for Go
Stars: ✭ 93 (+190.63%)
Mutual labels:  code-generator, code-generation
oag
Idiomatic Go (Golang) client package generation from OpenAPI documents
Stars: ✭ 51 (+59.38%)
Mutual labels:  code-generator, code-generation
WebApiToTypeScript
A tool for code generating TypeScript endpoints for your ASP.NET Web API controllers
Stars: ✭ 26 (-18.75%)
Mutual labels:  code-generator, code-generation
Php Code Generator
PHP code generator library
Stars: ✭ 141 (+340.63%)
Mutual labels:  code-generator, code-generation
EasyEE-Auto
EasyEE 自动化代码生成器。EasyEE Automated code generator.
Stars: ✭ 39 (+21.88%)
Mutual labels:  code-generator, code-generation
Toolkit
Collection of useful patterns
Stars: ✭ 137 (+328.13%)
Mutual labels:  code-generator, code-generation
Xcassetpacker
A command line tool for converting a folder of images into an .xcasset package for Xcode
Stars: ✭ 150 (+368.75%)
Mutual labels:  code-generator, code-generation
Geco
Simple code generator based on a console project, running on .Net core and using C# interpolated strings
Stars: ✭ 97 (+203.13%)
Mutual labels:  code-generator, code-generation
Evolutility Ui Jquery
Model-driven Web UI for CRUD using REST or localStorage.
Stars: ✭ 164 (+412.5%)
Mutual labels:  code-generator, code-generation
Scala Db Codegen
Scala code/boilerplate generator from a db schema
Stars: ✭ 49 (+53.13%)
Mutual labels:  code-generator, code-generation
Mid
mid is a generic domain-specific language for generating code and documentation
Stars: ✭ 68 (+112.5%)
Mutual labels:  code-generator, code-generation
celerio
Celerio is a code generator tool for data-driven application.
Stars: ✭ 73 (+128.13%)
Mutual labels:  code-generator, code-generation
kube-code-generator
Kubernetes code generator docker image
Stars: ✭ 60 (+87.5%)
Mutual labels:  code-generator, code-generation

Mr. Boilerplate

This is a code generator with a little webapp UI to help generate tedious, Scala boilerplate.

Try it online right now here: https://japgolly.github.io/mr.boilerplate/

Why?

Sometimes boilerplate is simply unavoidable.

Macros can be a pretty good solution but there are trade-offs that can be(come) unacceptable.

Codecs are a great example because they define external interfaces, and the fact that your own code compiles and passes its tests doesn't mean that you haven't broken the protocol with external people or services. Consider a simple example of someone writing a JSON codec. The evolution in a real-world project usually goes something like this...

import io.circe.generic.auto._

// or

import io.circe.generic.semiauto._
implicit val decoderPerson: Decoder[Person] = deriveDecoder[Person]
implicit val encoderPerson: Encoder[Person] = deriveEncoder[Person]

And then a few versions later, someone does a bit of refactoring, does a new deployment, and suddenly people in your environment are saying things are broken. Oh right, the refactor affected the field names, the macro happily revised the codec, devs didn't realise.

(Regardless of macro or not, it's a good habit to store real JSON blobs in your tests for protocol stability. It's generally not feasible to do that for all possible paths but 80%+ is usually very easy and high value. But I digress...)

Ok, we don't want things breaking when someone refactors things; let's make the protocols explicit.

implicit val decoderPerson: Decoder[Person] =
  Decoder.forProduct3("name", "address", "phone")(Person.apply)

implicit val encoderPerson: Encoder[Person] =
  Encoder.forProduct3("name", "address", "phone")(a => (a.name, a.address, a.phone))

That's better. A few versions later we need to change the name field to {"surname":xxx, "given":yyy} instead of just a string. We need to still be backwards-compatible though so now we need to rewrite the whole thing like this:

implicit val decoderPerson: Decoder[Person] =
  Decoder.instance { c =>
    for {
      name    <- /* custom logic here*/
      address <- c.get[String]("address")
      phone   <- c.get[Option[String]]("phone")
    } yield Person(name, address, phone)
  }

implicit val encoderPerson: Encoder[Person] =
  Encoder.instance(value => Json.obj(
    "name"    -> /* custom logic here*/,
    "address" -> value.address.asJson,
    "phone"   -> value.phone.asJson,
  ))

It's a pain. Especially when there's a lot of it to do, or especially when the types are large. With Mr. Boilrerplate you can just paste in the data definition, and immediately copy the forProduct codecs back out. In future when you need to start adding custom logic to a codec, repaste the definition, click a checkbox for manual-style codecs, and copy the expanded code back into your codebase. Big time saver.

Nice Features

For monomorphic types, it generates simple vals:

implicit val decoder: Decoder[Person] =
  Decoder.forProduct3("name", "address", "phone")(Person.apply)

For polymorphic types, it generates defs with correct type parameters, and type constraints and/or direct implicit evidences depending on the fields.

// case class NonEmptyList[+A](head: A, tail: List[A])
implicit def decoder[A: Decoder]: Decoder[NonEmptyList[A]] = // [A: Decoder] here
  Decoder.forProduct2("head", "tail")(NonEmptyList.apply[A]) // <-- .apply[A] here

// case class Roles[F[_], A](roles: F[A])
implicit def decoder[F[_], A](implicit ev1: Decoder[F[A]]): Decoder[Roles[F, A]] = // ev1 here
  Decoder[F[A]].map(Roles.apply[F, A]) // <-- .apply[F,A] here

Can I add more generators, or generation options?

Absolutely! Submit a PR. Once merged I'll update the live site.

Generators are pretty simple to write. All the Scala type logic is done by the library.

Have a look at the Circe generator source code and its unit test.

It looks a bit big only because it can generate code in a number of different styles according to its options.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].