Skip to content

Commit

Permalink
readme: prepare for v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Amine Mike committed Jan 10, 2025
1 parent d5a8c04 commit 3051ebc
Showing 1 changed file with 83 additions and 26 deletions.
109 changes: 83 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,49 +22,106 @@ transition from `ruby/prettyprint` to this gem.

`Wadler` is implemented on top of `Oppen`, and it provides more options than
`ruby/prettyprint`, notably:
1. Consistent and inconsistent breaking.
1. Explicit breaking, which is achievable in `ruby/prettyprint` with some
monkeypatching.

> [!CAUTION]
> This is still under development.
## Usage

A few examples of the API usage can be found in [examples/](examples/README.md).
1. [Consistent](examples/wadler_group/consistent.rb) and [inconsistent](examples/wadler_group/inconsistent.rb) breaking.
1. [Explicit breaking](examples/wadler_break_and_breakable/break.rb), which is achievable in `ruby/prettyprint` with some monkeypatching.
1. [Trimming of trailing whitespaces](examples/oppen_and_wadler_customization/whitespace.rb).
1. [Display a `String` on line break](examples/wadler_break_and_breakable/line_continuation.rb).
1. A bunch of helper methods to simplify common patterns like surrounding or
separating tokens (TODO link).

## Oppen vs Wadler

`Wadler` calls `Oppen` under the hood, so it's not a separate implementation,
and it's not calling ruby's `prettyprint`.

Both implementations have their use cases:
1. Oppen gives more control over tokens sent to the printer.
1. Wadler gives a more _"functional"_ API, which is far nicer to work with.
- Oppen gives more control over tokens sent to the printer.
- Wadler gives a more _"functional"_ API, which is far nicer to work with.

That being said, both APIs in this gem can achieve the same results, especially
on consistent and inconsistent breaking.

## Noteworthy details

### Difference with Oppen's original algorithm
## Oppen's API example

```ruby
tokens = [
Oppen.begin_inconsistent,
Oppen.string('Hello'),
Oppen.break(', '),
Oppen.string('World!'),
Oppen.line_break,
Oppen.string('How are you doing?'),
Oppen.end,
Oppen.eof,
]

puts Oppen.print(tokens: tokens)
# Hello, World!
# How are you doing?
```

## Wadler's API example

```ruby
out = Oppen::Wadler.new(width: 20)

out.group(indent: 2) {
out.group {
out
.text('def')
.breakable
.text('foo')
}
out.parens_break_none {
out.separate(%w[bar baz bat qux], ',', break_type: :inconsistent) { |param|
out.text(param)
}
}
}
out.group(indent: 2) {
out.break
out.nest(indent: 2) {
out
.text('puts')
.breakable(line_continuation: ' \\')
.text('42')
}
}
out
.break
.text('end')

puts out.output
# def foo(bar, baz,
# bat, qux)
# puts \
# 42
# end
```

## More examples

More examples of the APIs usage can be found in [examples/](examples/README.md).

## Difference with Oppen's original algorithm

1. We took liberty to rename functions to make the API more modern and closer to
what we expect when writing Ruby code. All correspondences with the algorithm
as described in Oppen's paper are noted in the comments of classes and methods.
1. We do not raise exceptions when we overflow the margin. The only exceptions
that we raise indicate a bug in the implementation. Please report them.

### Difference with `ruby/prettyprint`

Oppen's algorithm and `ruby/prettyprint` do not have the same starting positions
for a group's indentation. That's why you need to pay particular attention to
calls for `nest`; you might want to decrease them by `1` if you care about keeping
the same behavior.

This is what we do in our test suite to verify the correspondence of the `Wadler`
API and the `ruby/prettyprint`. We decided to shift the burden to the user because
we think that the deicision taken by `ruby/prettyprint` does not suit us.
1. The stacks described by the algorithm do not have a fixed size in our
implementation: we upsize them when they are full.
1. We trim trailing whitespaces.
1. We anchor the printing of nested groups on the screen's left margin instead
of the last line's width.
1. We print `groups` more eagerly.
1. We introduced new tokens and added more customizations to the original ones.
1. In order to not indent empty lines, we indent a line before displaying its
first `String` token instead of after the previous line break.

For more information about the original algorithm and the main differences with
our implementation, please refer to (TODO link to oppen_algorithm.md).

## Related projects

Expand Down

0 comments on commit 3051ebc

Please sign in to comment.