Part 010 Adding Global Data To Go Templates

One of the problems that perplexed me at first was how to have a template that worked for my top level index.html and for a file in my ./posts directory. One needed to add in ../ before referencing files. I tried a bunch of things. I tried using template variables and putting the info into the Go program. Nothing worked.

Finally I realized that what I needed was some really simple global data.

This set of functions implemented that for me.

An example (ex10.go):

package main

// (C) Philip Schlump, 2013.
// MIT Licensed, see LICENSE.txt

// Example of calling to set/get global values

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
)

// -----------------------------------------------------------------------------
// Globals for Templates (oooh Ick!)
//	 {{g "name"}}  Access a global and return its value from a "map" of string
//	 {{set "name=Value"}} Set a value to constant Value
//	 {{ bla | set "name"}} Set a value to Value of pipe
// -----------------------------------------------------------------------------
var global_data map[string]string

func global_init() {
	global_data = make(map[string]string)
}
func global_g(b string) string {
	return global_data[b]
}
func global_set(args ...string) string {
	if len(args) == 1 {
		b := args[0]
		var re = regexp.MustCompile("([a-zA-Z_][a-zA-Z_0-9]*)=(.*)")
		x := re.FindAllStringSubmatch(b, -1)
		if len(x) == 0 {
			name := x[0][1]
			value := ""
			global_data[name] = value
		} else {
			name := x[0][1]
			value := x[0][2]
			global_data[name] = value
		}
	} else if len(args) == 2 {
		name := args[0]
		value := args[1]
		global_data[name] = value
	} else {
		name := args[0]
		value := strings.Join(args[1:], "")
		global_data[name] = value
	}
	return ""
}

func readInFile(path string) string {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return ""
	}
	return string(file)
}

func readInJson(path string) map[string]interface{} {
	var jsonData map[string]interface{}
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return jsonData
	}
	json.Unmarshal(file, &jsonData)
	return jsonData
}

func main() {

	global_init()

	if len(os.Args) != 3 {
		fmt.Printf("Usage: ex10 TemplateFileName Data.JSON\n")
		os.Exit(1)
	}

	var tmpl_fn string = os.Args[1]
	var data_fn string = os.Args[2]

	tmpl := readInFile(tmpl_fn)
	person := readInJson(data_fn)

	funcMap := template.FuncMap{
		"g":   global_g,
		"set": global_set,
	}

	t := template.New("file-template").Funcs(funcMap)
	t, err := t.Parse(tmpl)
	if err != nil {
		panic(err)
		os.Exit(1)
	}

	err = t.ExecuteTemplate(os.Stdout, "file-template", person)
	if err != nil {
		panic(err)
		os.Exit(1)
	}
}


In this example the function bob is called from inside the template.

To run this you can

$ go run ex10.go ex10.tmpl ex10.json


To compile it and run it

$ go build ex10.go
$ ./ex10 ex10.tmpl ex10.json

The JSON input is (ex10.json):

{}


The template input is (ex10.tmpl):

{{set "bob=22"}}
bob={{g "bob"}}
{{set "bob=more 22"}}
bob={{g "bob"}}
{{set "jane=23"}}
jane={{g "jane"}}
bob={{g "bob"}}


The output you should expect from running it is (ex10.out):


bob=22

bob=more 22

jane=23
bob=more 22


It makes more sense when you look at (ex10b.tmpl):


Why have a global data at all?

{{define "includeCSS"}}
    <link rel="stylesheet" href="{{g "Top"}}css/bootstrap.css" media="screen">
{{end}}

Now in my top level directory I need:

{{set "Top" ""}}
{{template "includeCSS"}}

Later in a file in ./posts

{{set "Top" "../"}}
{{template "includeCSS"}}




Now the output is (ex10b.out):


Why have a global data at all?



Now in my top level directory I need:



    <link rel="stylesheet" href="css/bootstrap.css" media="screen">


Later in a file in ./posts



    <link rel="stylesheet" href="../css/bootstrap.css" media="screen">





Code tested on: Ubuntu 12.04, Mac 10.8, Windows 7 in go 1.1.2


•       •       •       •       •       •

Summary: # of Words: 301
Author: Philip J. Schlump
Published On: 2013-10-23

Download code from this articles in .tar.gz for Mac/Linux/Unix or .zip with CR/LF for Windows format.

 

Before You Go....

Have you read "Unintend Consinsequences"?

"I laughed so hard it hurt..."
    Rod Brown

"Incredibly funny! Incredibly true!"
    Tad Stevens