I’ve made a tool to make using and JSON encoding/decoding simple enum-like custom types that frequently change during development more maintenance-/pain- free. See the end of this post for how it works!
So I was working on part of an educational game that involves a storyline that branches and modifies according to player choices (like one of those old choose-your-own-adventure books). And I came across the same problem that has been aired on these forums several times before…
What happens at any particular point in the narrative depends on what has happened before and what choices the player makes. You could say the “view” of any given chapter depends upon what chapters have already been visited and what was done.
In writing the logic of this an obvious choice is to use custom types to label all the possible story segments and player achievements, so that the compiler:
- Prevents accidental references to non-existent items (by typo)
- Forces considering all possible situations when writing the logic.
This obviously works great, as it does for many other similar use cases.
However: as soon as you need to save state between games (localStorage or sending data to a server) these custom types need to be converted to JSON. Actually writing the encoders and decoders is trivial, since the custom types in this case are basically just glorified enums. But keeping them up-to-date is a pain point: if I add a bunch of new chapter names and accomplishments the compiler won’t…
- Remind me to add them to the decoder (although it will for the encoder).
- Catch any typos in the names of the JSON fields when writing either the decoder/encoder.
It’s true: neither is really that big a problem. But when I am going to be frequently updating the set of values in these types during developmemt it nevertheless can become a maintenance headache to avoid them and the problems they can cause. It starts to detract from the utility of using them.
So I decided to come up with a solution to make using simple custom types this way pain-free again, and knowing that it’s a common problem thought I’d share it…
I’ve written a simple command line tool (in Elm!) called
elm-enums. You can install it with:
npm install -g elm-enums
To use it you first create a file
enums.defs with all your enum-like types in. They are defined using the following syntax:
enum Mammals = [ Rodents , Bats , Insectivores , Bears , Carnivores ] enum Reptiles = [ Turtles , Lizards , Snakes , Crocodilia ]
where whitespace is optional and Elm style comments are permitted.
Then (making sure you are in the same directory as
elm-enums with no arguments. This will autogenerate a file
Enums.elm containing custom types and JSON encoders/decoders for all the
enums you specified in
You can then just import them into whatever modules need them:
import Enums exposing (Animals(..), encodeAnimals, decodeAnimals)
If you need to update the types, just edit
enums.defs and rerun
elm-enums. More details can be found in the README on the Github Project Page.
It’s fairly basic at the moment: you have to run it from the directory where you put
enums.defs and the characterset you can use for the names and values of the
enums is slightly more restrictive than technically Elm allows (basically only ASCII is supported at the moment… see the README)… mostly because that was all I needed, and it wasn’t clear if anybody else would ever want to use this! However it should be fairly straightforward to extend: one could even add functionality to give a list of all possible
enum values if that was something people wanted.
Feel free to peruse the source… it’s cobbled together rather quickly and not particularly polished but should nevertheless be quite straightforward to understand.