# Contributing

Want to contribute? There's a few moving parts that you'll need to know about:

- Ripper - The Ruby Parser used by this Project
- Prettier - Provides building blocks for formatting documents in a stylistic way
- Testing - Ensuring that there are no formatting or semantic regressions

Your input Ruby code is parsed by Ripper, and pretty printed using the building blocks provided by Prettier. To ensure there are no regressions, Jest snapshots are used to keep track of the formatting before and after. Additionally there are Ruby tests written with Minitest to ensure there are no semantic regressions after the code has been tidied up.

## Ripper

Ripper is the built-in CRuby lexer and parser that understands your Ruby code. It is able to read your source code and provide access to the tokens and the abstract syntax tree associated with your code.

You can explore Ripper within an interactive Ruby terminal. The process of identifying the tokens within your source code is called lexing:

```ruby
$ irb
> require 'ripper'
 => true
> Ripper.tokenize("puts('hello world')")
 => ["puts", "(", "'", "hello world", "'", ")"]
```

Once the tokens are understood, Ripper constructs an abstract syntax tree:

```ruby
$ irb
> require 'ripper'
> pp Ripper.sexp("puts('hello world')")
[:program,
 [[:method_add_arg,
   [:fcall, [:@ident, "puts", [1, 0]]],
   [:arg_paren,
    [:args_add_block,
     [[:string_literal,
       [:string_content, [:@tstring_content, "hello world", [1, 6]]]]],
     false]]]]]
```

Sometimes it can be useful to view this visually with
[Ripper Preview](https://ripper-preview.herokuapp.com).

The JavaScript Prettier process spawns a Ruby process within [parse.js](src/parse.js), which interacts with a custom wrapper written around Ripper called RipperJS. By default Ripper discards source code comments from the abstract syntax view. RipperJS attempts to bridge this gap by attaching the original comments to the abstract syntax tree generated by Ripper. Full details are within [ripper.rb](src/ripper.rb)

If you want to check out the enhanced abstract syntax tree generated by RipperJS:

```
bin/sexp file.rb
```

Or to view the output on a code snippet:

```
bin/sexp "# comment example\nputs('hello world')"
```

It's worth noting that there are multiple Ruby parsers available, but for this project Ripper has been chosen for the following reasons:

- Ripper is the built in reference implementation for CRuby
- Ripper is stable and always provides access to the latest syntax that Ruby supports
- Ripper is written in C, and it's fast

### Useful links

- [Ruby's parser](https://github.com/ruby/ruby/blob/trunk/parse.y) - the Ruby parser that will give
  you the names of the nodes as well as their structure
- [Ripper test parser events](https://github.com/ruby/ruby/blob/trunk/test/ripper/test_parser_events.rb) -
  Ripper test file that gives you code examples of each kind of node
- [How Ripper parses variables](https://rmosolgo.github.io/blog/2018/05/21/how-ripper-parses-variables/)
- [Ripper events](https://rmosolgo.github.io/ripper_events/)
- [Ripper preview](https://ripper-preview.herokuapp.com) - Visualize Ruby's abstract syntax tree

## Prettier

[Prettier](https://prettier.io/) provides support for third party plugins by providing access to its
document builders. In plugin-ruby the input Ruby file is parsed with Ripper, then printed with
Prettier. The printing logic for Ruby can be found within [print.js](src/print.js)

### Useful links

- [Prettier plugin documentation](https://prettier.io/docs/en/plugins.html)
- [Available commands](https://github.com/prettier/prettier/blob/master/commands.md)
- [Writing a Prettier plugin](https://medium.com/@fvictorio/how-to-write-a-plugin-for-prettier-a0d98c845e70)

## Testing

There are two types of testing performed within this project:

- Visual formatting regressions
- Semantic regressions

**Formatting regressions** are verified by running the Prettier plugin against a series of
pre-determined [Ruby test cases](test/cases) and saving the the output to a file for later
comparison. If in the future Prettier formats this file differently, the tests will no longer match
the stored snapshot and fail. The JavaScript testing framework Jest provides this functionality.
Rubocop is additionally ran over these files to ensure that they also match the community standards.

**Semantic regressions** are verified with with Minitest. After formatting the
[Ruby test cases](test/cases) the file is ran with Minitest to ensure that it behaves exactly the
same way before and after formatting has been applied.

## Useful commands

After checking out the repo, run `yarn` and `bundle` to install dependencies.

**Running tests**

```
yarn run test
```

**Updating Jest snapshots**

```
yarn run test -u
```

**Viewing the output of RipperJS on a file**

```
bin/sexp file.rb
```

**Viewing the output of RipperJS on code**

```
bin/sexp 'your_ruby_code(1, 2, 3)'
```

**Viewing the output of Prettier on a file**

```
bin/print file.rb
```

**Viewing the output of Prettier on code**

```
bin/print 'your_ruby_code(1, 2, 3)'
```
