From 5ec1f66a88855fa07e29bd160bb5a401b4061853 Mon Sep 17 00:00:00 2001 From: Oliver Steele Date: Wed, 28 Jun 2017 16:43:18 -0400 Subject: [PATCH] Implement remaining numeric filters --- README.md | 12 ++++++++---- filters/filter_test.go | 29 ++++++++++++++++++++++++----- filters/filters.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4bdea1c..7265314 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ - [ ] Control Flow - [x] `if`/`else`/`elsif` - [x] `unless` - - [ ] `case`/`when` + - [ ] `case` + - [x] `when` + - [ ] `else` - [ ] Iteration - [x] modifiers (`limit`, `reversed`, `offset`) - [ ] `range` @@ -28,10 +30,12 @@ - [ ] `tablerow` - [ ] `cycle` - [x] Raw - - [ ] Variables + - [x] Variables - [x] Assign - [x] Capture -- [ ] Filters (partial) +- [ ] Filters + - [ ] `sort_natural`, `uniq`, `escape`, `truncatewords`, `url_decode`, `url_encode` + - [x] everything else ## Install @@ -76,7 +80,7 @@ Kyoung-chan Lee's for formatting dates. Michael Hamrah's [Lexing with Ragel and Parsing with Yacc using Go](https://medium.com/@mhamrah/lexing-with-ragel-and-parsing-with-yacc-using-go-81e50475f88f) was essential to understanding `go yacc`. -The [original Liquid engine](https://shopify.github.io/liquid), of course, for the design and documentation of the Liquid template language. +The [original Liquid engine](https://shopify.github.io/liquid), of course, for the design and documentation of the Liquid template language. Many of the tag and filter test cases are taken directly from the Liquid documentation. (That said, this is a clean-room implementation to make sure it just implements the documented design.) diff --git a/filters/filter_test.go b/filters/filter_test.go index 1588017..ffd7228 100644 --- a/filters/filter_test.go +++ b/filters/filter_test.go @@ -86,14 +86,33 @@ var filterTests = []struct { {`183.357 | ceil`, 184}, {`"3.5" | ceil`, 4}, - // {`16 | divided_by: 4`, 4}, - // {`5 | divided_by: 3`, 1}, - // {`20 | divided_by: 7.0`, 123}, - {`1.2 | floor`, 1}, {`2.0 | floor`, 2}, {`183.357 | floor`, 183}, - // TODO divided_by, minus, modulo, plus, round,times + + {`4 | plus: 2`, 6}, + {`183.357 | plus: 12`, 195.357}, + + {`4 | minus: 2`, 2}, + {`16 | minus: 4`, 12}, + {`183.357 | minus: 12`, 171.357}, + + {`3 | times: 2`, 6}, + {`24 | times: 7`, 168}, + {`183.357 | times: 12`, 2200.284}, + + {`3 | modulo: 2`, 1}, + {`24 | modulo: 7`, 3}, + // {`183.357 | modulo: 12`, 3.357}, // TODO test suit use inexact + + {`16 | divided_by: 4`, 4}, + {`5 | divided_by: 3`, 1}, + {`20 | divided_by: 7`, 2}, + {`20 | divided_by: 7.0`, 2.857142857142857}, + + {`1.2 | round`, 1}, + {`2.7 | round`, 3}, + {`183.357 | round: 2`, 183.36}, // Jekyll extensions; added here for convenient testing // TODO add this just to the test environment diff --git a/filters/filters.go b/filters/filters.go index cd3cb98..6562a69 100644 --- a/filters/filters.go +++ b/filters/filters.go @@ -74,6 +74,34 @@ func DefineStandardFilters() { expressions.DefineFilter("abs", math.Abs) expressions.DefineFilter("ceil", math.Ceil) expressions.DefineFilter("floor", math.Floor) + expressions.DefineFilter("modulo", math.Mod) + expressions.DefineFilter("minus", func(a, b float64) float64 { + return a - b + }) + expressions.DefineFilter("plus", func(a, b float64) float64 { + return a + b + }) + expressions.DefineFilter("times", func(a, b float64) float64 { + return a * b + }) + expressions.DefineFilter("divided_by", func(a float64, b interface{}) interface{} { + switch bt := b.(type) { + case int, int16, int32, int64: + return int(a) / bt.(int) + case float32, float64: + return a / float64(b.(float64)) + default: + return nil + } + }) + expressions.DefineFilter("round", func(n float64, places interface{}) float64 { + pl, ok := places.(int) + if !ok { + pl = 0 + } + exp := math.Pow10(pl) + return math.Floor(n*exp+0.5) / exp + }) // sequences expressions.DefineFilter("size", generics.Length)