Shopify/liquid — pull request #458 by dylanahsmith (2014-10-14 07:57:25+00:00)
Title: Create a BlockBody class to decouple block body parsing from tags.

@pushrax & @shopify/liquid for review

## Problem

Block tags with multiple blocks have been implemented by manipulating the nodelist during block parsing. This makes block parsing a leaky abstraction, since the state of block parsing is manipulated in the custom tag code.

There was also an unnatural inheritance hierarchy, since a Document < Block < Tag, would mean that a Document is a tag, which isn't really true. The fact that tags can have multiple blocks or a non-tag like Document can have a block means that there should be a composition relationship to implement this cleanly.

One of the motivations behind this refactoring is that the state of the block body and block parsing can be encapsulated in such a way that it can be cleanly implemented in [liquid-c](https://github.com/shopify/liquid-c) with C code.

## Solution

Add a BlockBody class which now does all the block parsing. Now Document is a BlockBody, and tags with multiple blocks store multiple instances of BlockBody.

## Compatibility

This breaks compatibility with any code that implements custom tags with multiple blocks. I checked Shopify and Jekyll and didn't see any custom tags that do this, so I don't know how common this is. See the changes to the Case, For, If and Unless tags for examples of how these custom tags would need to be changed to work with these changes.

## Benchmark

When running the benchmarks I noticed parsing time does seem to have increased when running with this pull request, but this affect doesn't seem very noticeable when benchmarking parsing and rendering together.

2 runs on master:

```
parse: 28.7 (±10.4%) i/s - 1698 in 60.050428s
parse & run: 12.6 (±8.0%) i/s - 748 in 60.077487s
```

```
parse: 29.1 (±10.3%) i/s - 1718 in 60.032670s
parse & run: 12.8 (±7.8%) i/s - 761 in 60.004524s
```

2 runs on this pull request:

```
parse: 28.3 (±10.6%) i/s - 1674 in 60.019216s
parse & run: 12.8 (±7.8%) i/s - 765 in 60.039647s
```

```
parse: 28.6 (±10.5%) i/s - 1692 in 59.994088s
parse & run: 12.7 (±7.9%) i/s - 754 in 60.045035s
```