Shopify/liquid — pull request #443 by dylanahsmith (2014-09-12 14:18:32+00:00)
Title: Parse expressions in Liquid::Variable#parse.

cc @camilo, @sunblaze, @grollest

## Problem

Right now we are doing the expression parsing during liquid rendering. Since we memoize the result, this doesn't cause problems when always doing a parse followed by a render. However, this reduce the benefits we can get from caching the parsed liquid template to re-use, since it won't include expression parsing.

## Solution

Pull #391 already separated `Context#[]` into `Expression.parse` and `context.evaluate`, so was just a matter of using these two new methods in the Variable class.

## Benchmarks

I used pull #442 to benchmark the results so that it is easier to see how this distributes the time spent parsing and rendering.

Using master code:

```
~/src/liquid(benchmark-load-render)$ bundle exec rake benchmark:run
Rehearsal ----------------------------------------------------------
parse: 3.770000 0.050000 3.820000 ( 3.819407)
marshal load: 1.320000 0.010000 1.330000 ( 1.326707)
render: 4.400000 0.040000 4.440000 ( 4.447144)
marshal load & render: 5.780000 0.020000 5.800000 ( 5.806654)
parse & render: 8.130000 0.030000 8.160000 ( 8.154378)
------------------------------------------------ total: 23.550000sec

user system total real
parse: 3.600000 0.020000 3.620000 ( 3.619495)
marshal load: 1.320000 0.010000 1.330000 ( 1.331599)
render: 4.260000 0.020000 4.280000 ( 4.279742)
marshal load & render: 5.720000 0.020000 5.740000 ( 5.748194)
parse & render: 8.320000 0.050000 8.370000 ( 8.368795)
```

using code from this branch:

```
~/src/liquid(completely-parse-variables)$ bundle exec rake benchmark:run
Rehearsal ----------------------------------------------------------
parse: 5.140000 0.040000 5.180000 ( 5.186593)
marshal load: 1.680000 0.010000 1.690000 ( 1.687120)
render: 3.450000 0.030000 3.480000 ( 3.482392)
marshal load & render: 5.200000 0.030000 5.230000 ( 5.225160)
parse & render: 8.650000 0.040000 8.690000 ( 8.690502)
------------------------------------------------ total: 24.270000sec

user system total real
parse: 5.070000 0.030000 5.100000 ( 5.102806)
marshal load: 1.560000 0.000000 1.560000 ( 1.560547)
render: 3.340000 0.020000 3.360000 ( 3.360897)
marshal load & render: 5.340000 0.030000 5.370000 ( 5.367271)
parse & render: 8.810000 0.050000 8.860000 ( 8.860455)
```

So these changes increase the time to parse and decrease the time to render as expected.

The reason parse & render takes longer now is that we no longer memoize expressions that appear multiple times in the source. This could be done, but we don't really have a proper parse context, unlike rending which has a Liquid::Context object to store the cached expressions.