Skip to content

Commit

Permalink
Add minimum and maximum math functions
Browse files Browse the repository at this point in the history
  • Loading branch information
obourdon committed Dec 4, 2019
1 parent 3075677 commit cbf7b5c
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v0.24.0 (Unreleased)

IMPROVEMENTS:

* Add minimum and maximum math functions

## v0.23.0 (Nov 13, 2019)

IMPROVEMENTS:
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ this functionality might prove useful.
- [multiply](#multiply)
- [divide](#divide)
- [modulo](#modulo)
- [minimum](#minimum)
- [maximum](#maximum)
- [Plugins](#plugins)
- [Authoring Plugins](#authoring-plugins)
- [Important Notes](#important-notes)
Expand Down Expand Up @@ -2085,6 +2087,34 @@ This can also be used with a pipe function.
Please take careful note of the order of arguments.
##### `minimum`
Returns the minimum of the two values.
```liquid
{{ minimum 2 5 }} // 2
```
This can also be used with a pipe function.
```liquid
{{ 5 | minimum 2 }} // 2
```
##### `maximum`
Returns the maximum of the two values.
```liquid
{{ maximum 2 5 }} // 2
```
This can also be used with a pipe function.
```liquid
{{ 5 | maximum 2 }} // 2
```
## Plugins
### Authoring Plugins
Expand Down
142 changes: 142 additions & 0 deletions template/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,148 @@ func modulo(b, a interface{}) (interface{}, error) {
}
}

// minimum returns the minimum between a and b.
func minimum(b, a interface{}) (interface{}, error) {
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)

switch av.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if av.Int() < bv.Int() {
return av.Int(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Int() < int64(bv.Uint()) {
return av.Int(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if float64(av.Int()) < bv.Float() {
return av.Int(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("minimum: unknown type for %q (%T)", bv, b)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if int64(av.Uint()) < bv.Int() {
return av.Uint(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Uint() < bv.Uint() {
return av.Uint(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if float64(av.Uint()) < bv.Float() {
return av.Uint(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("minimum: unknown type for %q (%T)", bv, b)
}
case reflect.Float32, reflect.Float64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if av.Float() < float64(bv.Int()) {
return av.Float(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Float() < float64(bv.Uint()) {
return av.Float(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if av.Float() < bv.Float() {
return av.Float(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("minimum: unknown type for %q (%T)", bv, b)
}
default:
return nil, fmt.Errorf("minimum: unknown type for %q (%T)", av, a)
}
}

// maximum returns the maximum between a and b.
func maximum(b, a interface{}) (interface{}, error) {
av := reflect.ValueOf(a)
bv := reflect.ValueOf(b)

switch av.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if av.Int() > bv.Int() {
return av.Int(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Int() > int64(bv.Uint()) {
return av.Int(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if float64(av.Int()) > bv.Float() {
return av.Int(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("maximum: unknown type for %q (%T)", bv, b)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if int64(av.Uint()) > bv.Int() {
return av.Uint(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Uint() > bv.Uint() {
return av.Uint(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if float64(av.Uint()) > bv.Float() {
return av.Uint(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("maximum: unknown type for %q (%T)", bv, b)
}
case reflect.Float32, reflect.Float64:
switch bv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if av.Float() > float64(bv.Int()) {
return av.Float(), nil
}
return bv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if av.Float() > float64(bv.Uint()) {
return av.Float(), nil
}
return bv.Uint(), nil
case reflect.Float32, reflect.Float64:
if av.Float() > bv.Float() {
return av.Float(), nil
}
return bv.Float(), nil
default:
return nil, fmt.Errorf("maximum: unknown type for %q (%T)", bv, b)
}
default:
return nil, fmt.Errorf("maximum: unknown type for %q (%T)", av, a)
}
}

// blacklisted always returns an error, to be used in place of blacklisted template functions
func blacklisted(...string) (string, error) {
return "", errors.New("function is disabled")
Expand Down
2 changes: 2 additions & 0 deletions template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ func funcMap(i *funcMapInput) template.FuncMap {
"multiply": multiply,
"divide": divide,
"modulo": modulo,
"minimum": minimum,
"maximum": maximum,
}

for _, bf := range i.functionBlacklist {
Expand Down
22 changes: 22 additions & 0 deletions template/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,28 @@ func TestTemplate_Execute(t *testing.T) {
"1",
false,
},
{
"math_minimum",
&NewTemplateInput{
Contents: `{{ 3 | minimum 2 }}`,
},
&ExecuteInput{
Brain: NewBrain(),
},
"2",
false,
},
{
"math_maximum",
&NewTemplateInput{
Contents: `{{ 3 | maximum 2 }}`,
},
&ExecuteInput{
Brain: NewBrain(),
},
"3",
false,
},
{
"leaf_cert",
&NewTemplateInput{
Expand Down

0 comments on commit cbf7b5c

Please sign in to comment.