How can I use division in a golang template? - go

How can I use division in a golang template. I need to divide Id by 2.
For example
{{if .Id/2}}
HEY, I CAN DO IT!
{{else}}
WHY???
{{end}}

The package text/template (and subsequently html/template) can provide the functionality by defining division as a function using Template.Funcs:
func (t *Template) Funcs(funcMap FuncMap) *Template
In your case, a FuncMap with a divide function could look something like this:
fm := template.FuncMap{"divide": func(a, b int) int {
return a / b
}}
Full example (but without me trying to understand what you mean with if a/2):
package main
import (
"os"
"text/template"
)
func main() {
fm := template.FuncMap{"divide": func(a, b int) int {
return a / b
}}
tmplTxt := `{{divide . 2}}`
// Create a template, add the function map, and parse the text.
tmpl, err := template.New("foo").Funcs(fm).Parse(tmplTxt)
if err != nil {
panic(err)
}
// Run the template to verify the output.
err = tmpl.Execute(os.Stdout, 10)
if err != nil {
panic(err)
}
}
Output:
5
Playground: http://play.golang.org/p/VOhTYbdj6P

Related

How to compare Map for common keys and print the output?

I have the following code which generates the following output
code:
package main
import (
"html/template"
"os"
)
type EntetiesClass struct {
Name string
Value int32
}
// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var htmlTemplate = `{{range $index, $element := .}}
{{range $element}}{{.Name}}={{.Value}}
{{- end}}
{{- end}}`
func main() {
data := map[string][]EntetiesClass{
"Container1": {{"Test", 15}},
"Container2": {{"Test", 15}},
}
t := template.New("t")
t, err := t.Parse(htmlTemplate)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}
link: https://play.golang.org/p/yM9_wWmyLY
Output:
Test=15
Test=15
I want to compare the Container1 with Container2 and if they have common key, i just want to print output only once.
Output:
Test=15
How can i achieve this? Any help is appreciated?
I can think of two ways to do this:
Dedup your data before passing to the template execution
This means you can pre-process the data before passing to t.Execute to eliminate duplicates. You can do this using something like:
m := map[EntitiesClass]bool{}
for _, ... {
m[ec] = true
// Or maybe you want to aggregate "Container 1"
// and "Container 2" in some way
}
Then you can just pass the processed data and the template itself remains virtually unchanged
Add a custom function for your template
This means you can add a normal go function that receives as many EntitiesClass as you like and returns them deduplicated (perhaps with the mechanism from option 1).
You can even do something like:
{{if not customHaveSeenThisValueBefore }}
...
{{ endif }}
For your simple example I would choose option 1, it seems easiest to leave templates very simple.
This applies some filtering logic. I'm using text/template because this code isn't using a server. It will work the same with html/template. When appending to slices of structs pointers have to be used. If you don't know why see here. func isInSlice() bool needs to be modded to your needs. This serves as an example.
package main
import (
"os"
"text/template"
)
type Entitie struct {
Results []*Data
}
type Data struct {
Name string
Value int32
}
// Change this function to mod how to filter
func (e *Entitie) isInSlice(name string) bool {
for _, item := range e.Results {
if item.Name == name {
return true
}
}
return false
}
func (e *Entitie) AddData(name string, value int32) {
if !e.isInSlice(name) {
e.Results = append(e.Results, &Data{Name: name, Value: value})
}
}
// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var template = `
{{range $i, $e := .Data.Results}}
{{$e.Name}} = {{$e.Value}}
{{end}}
`
func main() {
data := make(map[string]Entitie)
var entities Entitie
entities.AddData("test", 15)
entities.AddData("test", 15)
entities.AddData("test2", 15)
t := template.New("t")
t, err := t.Parse(template)
if err != nil {
panic(err)
}
data["Data"] = entities
err = t.Execute(os.Stdout, data)
if err != nil {
panic(err)
}
}

How to create a writer for a String in Go

I need to use the *template.Execute method but I want the result as a string or byte[] so that I can pass it to another *template.Execute but the method writes its results to a writer. Is there a way to create a writer that will write to a variable I define?
Use an instance of bytes.Buffer, which implements io.Writer:
var buff bytes.Buffer
if err := tpl.Execute(&buff, data); err != nil {
panic(err)
}
You can then get a string result using buff.String(), or a []byte result using buff.Bytes().
You can also use strings.Builder for this purpose:
package main
import (
"html/template"
"strings"
)
func main() {
t, e := template.New("date").Parse("<p>{{ .month }} - {{ .day }}</p>")
if e != nil {
panic(e)
}
b := new(strings.Builder)
t.Execute(b, map[string]int{"month": 12, "day": 31})
println(b.String())
}
https://golang.org/pkg/strings#Builder

How To Call Method of another package from string method name in Go

Suppose I have two package like
-a
-b
a have some methods like this
func TestOne() { //something }
func TestTwo() { //something }
I need to call package a's methods from package b but by only string method name. Like i get the string "TestOne" and calls for the method TestOne(). How can i get that done.
Edit :
I have Read about reflect. but reflect needs an struct and functions be a member of that struct. What if My functions are not member of a struct? just plain methods in a package. and the calling methods and called methods are in different package. Then?
NB. There could be some methods that have parameters as well.
Like LightWeight said in his answer, you can use reflection.
You use the reflect.ValueOf method to get the value of the type. Then you can use the MethodByName method to get the function value. Once you have the function value you can call the Call method to execute it.
Code Sample
package main
import (
"fmt"
"reflect"
)
type TypeOne struct {
}
func (t *TypeOne) FuncOne() {
fmt.Println("FuncOne")
}
func (t *TypeOne) FuncTwo(name string) {
fmt.Println("Hello", name)
}
func CallFuncByName(myClass interface{}, funcName string, params ...interface{}) (out []reflect.Value, err error) {
myClassValue := reflect.ValueOf(myClass)
m := myClassValue.MethodByName(funcName)
if !m.IsValid() {
return make([]reflect.Value, 0), fmt.Errorf("Method not found \"%s\"", funcName)
}
in := make([]reflect.Value, len(params))
for i, param := range params {
in[i] = reflect.ValueOf(param)
}
out = m.Call(in)
return
}
func main() {
t1 := &TypeOne{}
out, err := CallFuncByName(t1, "FuncOne")
if err != nil {
panic(err)
}
//Return value
_ = out
out, err = CallFuncByName(t1, "FuncTwo", "monkey")
if err != nil {
panic(err)
}
//Return value
_ = out
}
You can try to use reflect in go. This link may be help you
https://golang.org/pkg/reflect/
and http://mikespook.com/2012/07/function-call-by-name-in-golang/
func foo() {
// bla...bla...bla...
}
func bar(a, b, c int) {
// bla...bla...bla...
}
funcs := map[string]interface{}{"foo":foo, "bar":bar}

Variable modification in golang [Mutability]

The below code opens up a .txt file and counts the word frequencies. I am following a book and I got confused:
My question is here:
filename := os.Args[1]
frequencyForWord := map[string]int{}
updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
I create a variable called frequencyForWord and pass it into a function that does not return anything called func updateFrequencies
This function modifies the variable and that's why when I do fmt.Println(frequencyForWord) it shows me a map that has words as keys and their counts as values.
My question is:
why don't I have to do something like this
frequencyForWord = updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
// And then change func updateFrequencies to something to returns a map
I thought in order for a function to modify a variable I need to pass in the variable as a reference like this updateFrequencies(filename, &frequencyForWord)
Original Code:
package main
import(
"fmt"
"path/filepath"
"os"
"log"
"bufio"
"strings"
"unicode"
)
func main() {
if len(os.Args) == 1 || os.Args[1] == "-h" {
fmt.Printf("usage: %s <file>\n", filepath.Base(os.Args[0]))
os.Exit(1)
}
filename := os.Args[1]
frequencyForWord := map[string]int{}
updateFrequencies(filename, frequencyForWord)
fmt.Println(frequencyForWord)
}
func updateFrequencies(filename string, frequencyForWord map[string]int) string {
file, err := os.Open(filename)
if err != nil {
log.Printf("Failed to open the file: %s.", filename)
}
defer file.Close()
readAndUpdateFrequencies(bufio.NewScanner(file), frequencyForWord)
}
func readAndUpdateFrequencies(scanner *bufio.Scanner, frequencyForWord map[string]int) {
for scanner.Scan() {
for _, word := range SplitOnNonLetter(strings.TrimSpace(scanner.Text())) {
frequencyForWord[strings.ToLower(word)] += 1
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
func SplitOnNonLetter(line string) []string {
nonLetter := func(char rune) bool { return !unicode.IsLetter(char) }
return strings.FieldsFunc(line, nonLetter)
}
Because the map structure doesn't contain the values itself but points to the structures holding the values.
As written in the documentation :
Like slices, maps hold references to an underlying data structure. If
you pass a map to a function that changes the contents of the map, the
changes will be visible in the caller.
That's just like when you pass a pointer to a function : it lets the function change your value.
Here's another example of the same phenomenon :
type A struct {
b *B
}
type B struct {
c int
}
func incr(a A) {
a.b.c++
}
func main() {
a := A{}
a.b = new(B)
fmt.Println(a.b.c) // prints 0
incr(a)
fmt.Println(a.b.c) // prints 1
}
The function is not modifying the variable, but the value bound to the variable. That's possible because a map is a mutable data structure and passing it to a function does not copy the structure. (A map is implicitly a reference to a hash table and the reference is passed around.)

Differing behaviors for ParseFiles functions in html/template

I don't understand why the behaviors of func (t *Template) Parsefiles(... differs from func ParseFiles(.... Both functions are from the "html/template" package.
package example
import (
"html/template"
"io/ioutil"
"testing"
)
func MakeTemplate1(path string) *template.Template {
return template.Must(template.ParseFiles(path))
}
func MakeTemplate2(path string) *template.Template {
return template.Must(template.New("test").ParseFiles(path))
}
func TestExecute1(t *testing.T) {
tmpl := MakeTemplate1("template.html")
err := tmpl.Execute(ioutil.Discard, "content")
if err != nil {
t.Error(err)
}
}
func TestExecute2(t *testing.T) {
tmpl := MakeTemplate2("template.html")
err := tmpl.Execute(ioutil.Discard, "content")
if err != nil {
t.Error(err)
}
}
This exits with the error:
--- FAIL: TestExecute2 (0.00 seconds)
parse_test.go:34: html/template:test: "test" is an incomplete or empty template
FAIL
exit status 1
Note that TestExecute1 passed fine so this not a problem with template.html.
What's going on here?
What am I missing in MakeTemplate2?
It's because of the template names. Template objects can hold multiple teplates, each has a name. When using template.New("test"), and then Executing it, it will try to execute a template called "test" inside that template. However, tmpl.ParseFiles stores the template to the name of the file. That explains the error message.
How to fix it:
a) Give the template the correct name:
Use
return template.Must(template.New("template.html").ParseFiles(path))
instead of
return template.Must(template.New("test").ParseFiles(path))
b) Specify, which template you want to execute in you Template object:
Use
err := tmpl.ExecuteTemplate(ioutil.Discard, "template.html", "content")
instead of
err := tmpl.Execute(ioutil.Discard, "content")
Read more about this in http://golang.org/pkg/text/template/

Resources