Monday, December 5, 2016

Using Rug with Elm

At elm-conf and CodeMesh and YOW! Australia this year, I did live demos using automated code modification with Atomist Rug.

Rug is now officially open source, and the Rug CLI is available so that you can try (and change! and improve!) these editors on your own Elm code. This blog post tells you how.

I usually start a new Elm project as a static page, make it look like something; then turn it into a beginner program, add some interactivity; then turn it into an advanced program and add subscriptions. I like how this flow lets me start super-simple, and then add the pieces for access to the world as I need it.

Now you can do this too!

Watch out: these editors (and the parser behind them) work for the code I've tried them on. As you try them, you'll find cases I didn't cover. Please file an issue when you do, or find me on Atomist-Community slack.

Install Rug

The local version of the Rug runtime is the Rug CLI. Complete installation instructions are here.

TL;DR for Mac:
brew tap atomist/tap
brew install rug-cli

Generate a project

This will create a directory containing a new static Elm app, with a build script etc. This will put a project named banana under your current directory, make it a git repo and make an initial commit:
rug generate -R jessitron:elm-rugs:StaticPage banana
Inside banana, edit src/Main.elm. Put something in that empty div.
Run ./build
Open target/index.html to see the results.

Upgrade it to a beginner program

After your banana looks OK, make it interactive. Run this inside your project directory:
rug edit jessitron:elm-rugs:UpgradeToBeginnerProgram
Now your src/Main.elm contains the beginnings of a beginner program. The model is empty and the only message is Noop, which does nothing. This is the beginner program template from the Elm tutorial, except that the view function is populated based on your main from the static page.

You could add a button:
rug edit jessitron:elm-rugs:AddButton button_text="Push Me" button_message=ButtonPushed
Now your src/Main.elm contains a new message type, ButtonPushed. Your update function handles it, but does nothing interesting.
type Msg
    = Noop

update : Msg -> Model -> Model
update msg model =
    case msg of
        Noop ->

ButtonPushed ->            model
Find a new function hanging out at the end of the file, buttonPushedButton. Incorporate that into your view to display the button. Run ./build and refresh target/index.html; push the button and see the message in the debugger.

Try adding a text input in a similar way, with
rug edit jessitron:elm-rugs:AddTextInput input_name=favoriteColor
This adds a function, a message, and a field to the model so that you'll have access to the content of the text input.

Try passing -R to rug, and it'll make a commit for you after the editor completes. You have to make a commit yourself right before running rug, or it'll complain.

For further edit operations, see my elm-rugs repo. You can upgrade to a full program, and add subscriptions to clicks and window size.

Change these editors! Add more!

The best part of running locally is running local versions.
Clone my repository: git clone
Now, go to the secret directory holding the editors: cd elm-repo/.atomist/editors
Here, you can see the scripts that work on the code, like AddButton.rug.

To run the local versions, be in that elm-rugs directory, and point rug at your project directory with -C:
rug -l -C /path/to/my/projects/banana edit AddButton button_message=Yay button_text="Say hooray"
I don't have to qualify the editor name with jessitron:elm-rugs when it's local.

There's more information in the Atomist docs on how rug works. TL;DR is, the files in the top level of elm-rugs/ are the starting point for newly generated project. NewStaticPage.rug, as a generator, starts from those and then changes the project name. The editors all start from whatever project they're invoked on, and they can change files in place, or create new ones from templates in the elm-rugs/.atomist/templates directory. (Most of my templates are straight files, with a .vm suffix to make Rug's merge function work.)

Questions very welcome on either the elm-lang slack in the #atomist channel, or the Atomist community slack on the #rug-elm channel.

Pull requests are even more welcome. Issues, too. These rugs work for the narrow cases I've tested them on. It'll be a community effort to refine and expand them!