Eval function

I would like to do this:

{{ $s := slice "add 5 1" "sub 6 2" "mul 7 3" "div 8 4" }}
{{ range $s }}
  {{ printf "%s = %d" . (eval .) }}
{{ end }}

To produce this:

add 5 1 = 6
sub 6 2 = 4
mul 7 3 = 21
div 8 4 = 2

The primary use cases are documentation development and testing.

Comments?

1 Like

What about resources.ExecuteAsTemplate?

1 Like

:+1:

This:

{{ $s := slice "add 5 1" "sub 6 2" "mul 7 3" "div 8 4" }}
{{ range $s }}
  {{ $f := printf "%d.tmp" now.UnixNano }}
  {{ $r := printf "{{ %s }}" . | resources.FromString $f }}
  {{ $r = $r | resources.ExecuteAsTemplate $f . }}
  {{ printf "<pre>%s = %s</pre>" . $r.Content | safeHTML }}
{{ end }}

Produces this:

add 5 1 = 6
sub 6 2 = 4
mul 7 3 = 21
div 8 4 = 2

Notes:

  1. This uses the same target path (a temp file) for resources.FromString and resources.ExecuteAsTemplate.
  2. The temp file had to be unique for each iteration of the range.
  3. When running with hugo server the temp file had to be unique for each rebuild and each iteration of the range.
  4. Items #2 and #3 lead me to now.UnixNano for the temp file name.

This seems fairly clean, but I’m sure there’s room for improvement.

How about:

{{ $f := printf "%s.txt" ($s | md5) }}

Note that using a MIME type that is defined (e.g. text/plain) is much faster. We have a slow path for unknown mime types.

Thanks. Works great. Revised code:

{{ $s := slice "add 5 1" "sub 6 2" "mul 7 3" "div 8 4" }}
{{ range $s }}
  {{ $f := printf "%s.txt" (. | md5) }}
  {{ $r := printf "{{ %s }}" . | resources.FromString $f }}
  {{ $r = $r | resources.ExecuteAsTemplate $f . }}
  {{ printf "<pre>%s = %s</pre>" . $r.Content | safeHTML }}
{{ end }}

Note that resources.FromString does not overwrite an existing file when ranging through the slice of commands or between rebuilds when running hugo server. That’s why I initially used now.UnixNano for the temporary file name.

When we use a hash value (md5) for the temporary file name, the code above does not do what we think it does when our slice of commands contains duplicate items. For example:

{{ $s := slice "add 5 1" "add 5 1" }}

When processing the second item, resources.ExecuteAsTemplate uses the resource created for the first item. But that’s OK because the expected result is the same.

Thank you very much for your help.

And finally, abstracted to a function…

layouts/partials/eval.html

{{ $f := printf "%s.txt" (. | md5) }}
{{ $r := printf "{{ %s }}" . | resources.FromString $f }}
{{ $r = $r | resources.ExecuteAsTemplate $f . }}
{{ return $r.Content }}

Example:

{{ $s := slice "add 5 1" "sub 6 2" "mul 7 3" "div 8 4"}}
{{ range $s }}
  {{ $r := partial "eval" . }}
  {{ printf "<pre>%s = %s</pre>" . $r | safeHTML }}
{{ end }}

Result:

add 5 1 = 6
sub 6 2 = 4
mul 7 3 = 21
div 8 4 = 2
1 Like

I don’t think your reasoning is correct, which I think would be clear if you do add now.UnixNano 1 or something. The use of the MD5 leads to the reasource and the result of parsing the template getting cached, which is a good thing and what you want.

I agree. This is going to be really useful. Thanks again!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.