Ruby Association Final Report

In accordance with the Ruby Association’s timeline, this is the final report on the Ruby formatter project.

Deliverables

When the project was initially proposed to create a standard library formatter, a list of 5 delivers was created. Below I detail what the initial proposal for each one was, as well as the work that ended up being done.

ripper updates

A definitive representation of the Ruby syntax tree based on ripper was proposed. The existing ripper subclasses ship without location information for inner nodes, discard comments in the final representation, and don’t have named fields. These issues and more are remedied in the new Ripper::Tree subclass. This subclass is now backing the formatter here as the basis for the syntax tree. Its main benefits are:

This work hasn’t been merged upstream, but the pull request has been opened here.

prettyprint updates

Updates and enhancements to the prettyprint library were proposed. In general, prettyprint is well suited to printing out object descriptions but lacks enough necessary functionality to be able to accurately print a programming language like Ruby. Many (non-breaking) updates were made to the prettyprint library to enhance it enough to power the formatter. The following issues have been addressed:

These issues were addressed with a small algorithm change and the additional of many node types in the print tree. From the user of this class’s perspective, nothing is different. Internally however, there’s a bunch of additional functionality and a lot more control over the printing algorithm! Also the ability to debug has been greatly enhanced with pretty_print methods on each of the nodes and the ability to walk the print tree nodes before they’re printed.

This work hasn’t been merged upstream, but the pull request has been opened here.

Formatter

A formatter for Ruby source code was proposed. With the work done on the ripper subclass and the prettyprint updates, this amounted to combining those two efforts by defining formatting functions on each of the node types.

That work was all bundled up into the syntax_tree gem (now published). You can see how all of that formatting is performed here. Particularly look at all of the format methods, as well as the various classes and modules created to support those methods.

CLI

A CLI for formatting files was proposed. When the formatter was finished, this was a matter of triggering its execution from the command line.

This work has been bundled up into the cli.rb file in the syntax_tree gem. It includes the proposed functionality of formatting Ruby code. It also supports various other helpful functionality, a subset of which is listed below.

Language server

A language server supporting the formatOnSave option was proposed.

A subset of the language server protocol has been implemented in the syntax_tree gem and supports the formatOnSave option here. A couple other features were added as well (the ability to disassemble the YARV bytecode for a given method, various inlayed code hints, as well as the ability to see the syntax tree). These features and more were also built into a VSCode plugin to make it easier for developers to integrate into their workflows.

Future work

I still plan to build lots of additional functionality into syntax_tree and its related projects. Some of that functionality includes:

If you’re interested in following this project, you can watch the ruby-syntax-tree/syntax_tree repository or check/subscribe to this blog. I’ve also started a blog series describing how this project was built, which you can start reading with the introductory post.

← Back to home