Difference between text/template.Templates and html/template.Templates - go

Recently, I noticed that Templates() of html/template.Template works differently from the one of text/template.Template.
// go1.12
func main() {
t := template.New( "" )
println( len( t.Templates() ) )
}
The result of this code depends on whether you imported text/template or html/template. You'll notice that the text one prints 0 while the other prints 1. Becuase of this, I looked into the GoDoc and the html one's documentation said that Templates() includes itself -- but no further explanation. And I thought there must be some reason why; why does it have to be different from each other?

Templates returned by text/template.New() and html/template.New() are both incomplete templates without a "body", they cannot yet be used to generate any output. You can verify this if you try to execute them:
t := ttemplate.New("t")
h := htemplate.New("h")
fmt.Println(t.Execute(os.Stdout, nil))
fmt.Println(h.Execute(os.Stdout, nil))
Outputs (try it on the Go Playground):
template: t: "t" is an incomplete or empty template
template: "h" is an incomplete or empty template
Returning incomplete templates in the associated templates has no significance, and is an implementation detail. One package chose to include it, the other chose not to.
Note that if you "complete" the template definitions by actually parsing anything, both will include and return the self template in the associated templates, there is no difference in them:
t := ttemplate.Must(ttemplate.New("t").Parse("t"))
h := htemplate.Must(htemplate.New("h").Parse("h"))
fmt.Println(len(t.Templates()), len(h.Templates()))
fmt.Println(t.Execute(os.Stdout, nil))
fmt.Println(h.Execute(os.Stdout, nil))
This will output (try it on the Go Playground):
1 1
t<nil>
h<nil>

Related

In Go 1.18 strings.Title() is deprecated. What to use now? And how?

As suggested here names of people should be capitalized like John William Smith.
I'm writing a small software in Golang which gets last and first name from user's form inputs.
Until Go 1.18 I was using:
lastname = strings.Title(strings.ToLower(strings.TrimSpace(lastname)))
firstname = strings.Title(strings.ToLower(strings.TrimSpace(firstname)))
It works but now Go 1.18 has deprecated strings.Title().
They suggest to use golang.org/x/text/cases instead.
So I think I should change my code in something like this:
caser := cases.Title(language.Und)
lastname = caser.Title(strings.ToLower(strings.TrimSpace(lastname)))
firstname = caser.Title(strings.ToLower(strings.TrimSpace(firstname)))
It works the same as before.
The difference is for Dutch word like ijsland that should be titled as IJsland and not Ijsland.
The question
In the line caser := cases.Title(language.Und) I'm using Und because I don't know what language Tag to use.
Should I use language.English or language.AmericanEnglish or other?
So far it was like strings.Title() was using Und or English?
As mentioned in documentation strings.Title is deprecated and you should use cases.Title instead.
Deprecated: The rule Title uses for word boundaries does not handle
Unicode punctuation properly. Use golang.org/x/text/cases instead.
Here is an example code of how to use it as from two perspectives:
// Straightforward approach
caser := cases.Title(language.BrazilianPortuguese)
titleStr := caser.String(str)
// Transformer interface aware approach
src := []byte(s)
dest := []byte(s) // dest can also be `dest := src`
caser := cases.Title(language.BrazilianPortuguese)
_, _, err := caser.Transform(dest, src, true)
Make sure to take a look on the transform.Transformer.Transform and cases.Caser in order to understand what each parameter and return values mean, as well as the tool's limitations. For example:
A Caser may be stateful and should therefore not be shared between
goroutines.
Regarding what language to use, you should be aware of their difference in the results, besides that, you should be fine with any choice. Here is a copy from 煎鱼's summary on the differences that cleared it for me:
Go Playground: https://go.dev/play/p/xp59r1BkC9L
func main() {
src := []string{
"hello world!",
"i with dot",
"'n ijsberg",
"here comes O'Brian",
}
for _, c := range []cases.Caser{
cases.Lower(language.Und),
cases.Upper(language.Turkish),
cases.Title(language.Dutch),
cases.Title(language.Und, cases.NoLower),
} {
fmt.Println()
for _, s := range src {
fmt.Println(c.String(s))
}
}
}
With the following output
hello world!
i with dot
'n ijsberg
here comes o'brian
HELLO WORLD!
İ WİTH DOT
'N İJSBERG
HERE COMES O'BRİAN
Hello World!
I With Dot
'n IJsberg
Here Comes O'brian
Hello World!
I With Dot
'N Ijsberg
Here Comes O'Brian
So far it was like strings.Title() was using Und or English?
strings.Title() works based on ASCII, where cases.Title() works based on Unicode, there is no way to get the exact same behavior.
Should I use language.English or language.AmericanEnglish or other?
language.English, language.AmericanEnglish and language.Und all seem to have the same Title rules. Using any of them should get you the closest to the original strings.Title() behavior as you are going to get.
The whole point of using this package with Unicode support is that it is objectively more correct. So pick a tag appropriate for your users.
strings.Title(str) was deprecated, should change to cases.Title(language.Und, cases.NoLower).String(str)
package main
import (
"fmt"
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
func main() {
fmt.Println(strings.Title("abcABC")) // AbcABC
fmt.Println(cases.Title(language.Und, cases.NoLower).String("abcABC")) // AbcABC
}
Playground : https://go.dev/play/p/i0Eqh3QfxTx
Here is a straightforward example of how to capitalize the initial letter of each string value in the variable using the golang.org/x/text package.
package main
import (
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
func main() {
sampleStr := "with value lower, all the letters are lowercase. this is good for poetry perhaps"
caser := cases.Title(language.English)
fmt.Println(caser.String(sampleStr))
}
Output : With Value Lower, All The Letters Are Lowercase. This Is Good For Poetry Perhaps
Playground Example: https://go.dev/play/p/_J8nGVuhYC9

Compare 2 errors in Go for unit test

I got a problem like below: Compare 2 errors when writing unit test
package main
import (
"errors"
"fmt"
"reflect"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func main() {
er1 := errors.New("database name is not exists")
er2 := errors.New("database name is not exists")
result1 := reflect.DeepEqual(er1, er2)
fmt.Println("reflect: ", result1)
result2 := cmp.Equal(er1, er2, cmpopts.EquateErrors())
fmt.Println("compare: ", result2)
result3 := errors.Is(er1, er2)
fmt.Println("errorIs: ", result3)
}
And the output of the above code is:
reflect: true
compare: false
errorIs: false
I want to compare 2 error and reflect.DeepEqual(er1, er2) is the 1st approach I apply and this method produce the output I want, but this approach have a warning from go lint:
avoid using reflect.DeepEqual with errorsdeepequalerrors
After google search, some people tell me some approaches that are:
Use cmp package to compare: cmp.Equal(er1, er2, cmpopts.EquateErrors())
Use errors package to compare: errors.Is(er1, er2)
But both above approaches can not produce same result like the 1st approach (use reflect.DeepEqual).
How I can compare 2 errors without warning from go lint and produce the result like the reflect.DeepEqual
Tks
Depending on how you write your tests, you may depend on reflect.DeepEqual() and ignore the linter warning ;
the drawback is : you start depending on the inner structure of the errors you return.
In the testing code I read, and the testing code we write, we use one of the following patterns :
most of the time, we just compare the error to nil ;
in some cases our functions return predefined error values, and we test for these specific values :
package pkg
var ErrUnboltedGizmo = errors.New("gizmo is unbolted")
// in test functions, depending on the case :
if err == pkg.ErrUnboltedGizmo { ...
// or :
if errors.Is(err, pkg.ErrUnboltedGizmo) { ...
when our production code mandates that a specific error be spotted (a common use case is io.EOF), we write code that dutifully wraps that known error, and we use errors.Is() (both in production code and in testing code),
when the need is, in testing only, to loosely confirm that an error matches something and not something else (e.g : Parse error and not File not found), we simply search for strings in the error message :
if err == nil || !strings.Contains(err.Error(), "database name is not exists") {
t.Errorf("unexpected error : %s", err)
}
What I found useful is to use cmp.Diff with cmpopts.IgnoreFields to ignore the sepecific error fields which cause the issue u detailed and afterward I just run a check on the errors with string.Contains or whatever I find fitting.
So it goes something like this:
if diff := cmp.Diff(expected, got, cmpopts.IgnoreFields(expected, "ErrorField")); diff != "" {
// found diff not including the error
}
Now check only the errors on their own and that's it.
And yeah I know u marked a solution already but maybe it will help someone :)

Why does the compiler complain about an unused variable in this instance (when it is used by fmt.Fprintf)?

I have a simple piece of code where I want to convert elements of a slice into json and then print them out to my http.responseWriter.
for _, element := range customers {
result, _ := json.Marshal(element)
fmt.Fprintf(w, string(result))
}
However when I compile this I get the error "result declared and not used". If I add a simple line:
_ = result
Then everything compiles and works fine. Why does the compiler complain about this usage, and what is the correct way to do this in go?
Any insight is appreciated, my searches so far seem to indicate the call to Fprintf should count as a usage.
The code in question does not result in the error posted, for proof, check it on the Go Playground.
This error usually is (and the op confirmed it is too in this case) caused by having a local variable with same name outside of the block, and when using the short variable declaration, that shadows that variable.
This error can be reproduced with the following code:
var result []byte
customers := []int{}
w := os.Stdout
for _, element := range customers {
result, _ := json.Marshal(element)
fmt.Fprintf(w, string(result))
}
Attempting to compile and run it, we get the error (try it on the Go Playground):
prog.go:10:6: result declared and not used
Solution is to use a simple assignment instead of the short variable declaration if intention is to use the existing variable (in which case no new variable will be created), or use a different name for the variable if intention is not to use the outer, existing variable (but then the outer variable is to be removed or be used of course).

Return all contents within an object

I am very new to Go, so I am sorry for that noob question.
In JavaScript console.log(window) returns all objects inside of window. In PHP var_dump(new DateTime()) returns all objects inside of DateTime().
Is there a function in Go that will return all objects from a given object? For example Println should be returned if fmt is given.
Try executing go doc fmt in a terminal to produce a description of the "fmt" package and a listing of the functions it exports, or referring to the fmt package documentation at https://golang.org. In go, as in most other static/compiled languages, users are expected to refer to documentation (or docs) which describe the programming language and its libraries. Contrast this to some dynamic/scripting languages, which often make it easy to query any object to discover its usable properties.
At runtime, you can get a helpful printout of any arbitrary value by using the %#v formatting verb to produce a go syntax representation of the value, e.g.
xs := []int{1, 2, 3}
fmt.Printf("OK: xs=%#v\n", xs)
// OK: xs=[]int{1, 2, 3}
Note that the package "fmt" is not a value in the go language so it cannot be printed at runtime as such.
In Go is possible does something similar, but don't work for all.
func main() {
//arrays
a := []int{1,2,3,4}
fmt.Printf("%v\r\n", a) //print [1 2 3 4]
//maps
b := map[string]int{
"a":1,
"b":2,
}
fmt.Printf("%v\r\n", b) //print map[a:1 b:2]
//structs
c := struct{
A int
B int
}{1,2}
d := struct{
C struct{
A int
B int
}
D int
}{c,2}
fmt.Printf("%v\r\n", d) //print {{1 2} 2}
}
See in: https://play.golang.org/p/vzlCsOG497h
If you pass fmt occurs error because it is a package. The error is:
Error: use of package fmt without selector
I hope this helps (too)!
GO OOP, & inheritance
Go does not have objects, but we do have custom types and interfaces that we can attach attributes, functions and other types to.
What specifically are you trying to do? If you're looking for a var_dump:
USING fmt.Println
someErr := fmt.Errorf("custom type error")
fmt.Println(someErr)
Println formats using the default formats for its operands and writes to standard output.
USING fmt.Printf
someErr := fmt.Errorf("custom type error")
fmt.Printf("This is an error:%v A num: %v A str", someErr, 19, "Stackoverflow")
Printf formats according to a format specifier and writes to standard output.
USING fmt.Sprintf
someErr := fmt.Errorf("custom type error")
// someStr now contains the string formatted as shown below
someStr := fmt.Sprintf("This is an error:%v A num: %v A str", someErr, 19, "Stackoverflow")
Sprintf formats according to a format specifier and returns the resulting string.
Here is an example of my personal preference when outputting var data:
https://play.golang.org/p/8dpeE-fray_J
I hope this helps!

Go template name

In the html/template (and text/template) packages, template.New has the following signature:
func New(name string) *Template
What exactly is the name used for? I've scanned the docs (and a bit of source), but to no avail. I just instantiate all of my templates with an empty string and it doesn't seem to make a difference. Why should I bother with a name?
Even for naming templates, the two seem equivalent:
template.Must(template.New("").Parse(`{{ define "body" }}Body{{ end }}`))
template.Must(template.New("body").Parse(`Body`))
https://play.golang.org/p/wKzCHdLf2S
The name of the template–unsurprisingly–is to name the template.
What is it good for? As long as you don't want to refer to the template, it doesn't really matter. But if you want to refer to it, then yes, you refer to it by its name.
When would you want to refer to it? When you want to include a template in another e.g. using the {{template}} action, or when you want to execute a specific template using Template.ExecuteTemplate().
So far so good, but there's still a missing key point. This is not unambiguous / trivial: a template.Template value is "the representation of a parsed template". But the wording here is a little "imperfect". A template.Template value may be (and usually is) a collection of multiple, associated templates. template.Template has an unexported field:
tmpl map[string]*Template // Map from name to defined templates.
This tmpl field holds all other associated templates, templates that are visible to the template, and which can be referred to–yes–by their names.
When you parse multiple templates at once, using Template.ParseFiles() or Template.ParseGlob(), then the templates will be named by the file names, and they will be associated automatically (the above mentioned functions return a single template.Template value, which holds all the parsed templates, associated). Doc of Template.ParseFiles() is clear on this:
ParseFiles creates a new Template and parses the template definitions from the named files. The returned template's name will have the base name and parsed contents of the first file. [...]
When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results. For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template named "foo", while "a/foo" is unavailable.
The template name can come from multiple places:
it can come from the file name (as seen above)
it can be specified explicitly (if defined using the {{define "somename"}} or {{block "somename"}} actions),
or it may be defined as an argument passed to template.New() (function) or Template.New() (method).
Let's see some examples:
func main() {
t := template.Must(template.New("one").Parse(t1src))
template.Must(t.New("other").Parse(t2src))
// error checks omitted for brevity
// Executes default, "one":
t.Execute(os.Stdout, nil)
// Executes explicit, "one":
t.ExecuteTemplate(os.Stdout, "one", nil)
// Executes explicit, "other":
t.ExecuteTemplate(os.Stdout, "other", nil)
}
const t1src = `I'm some template.
`
const t2src = `I'm some OTHER template.
`
Output (try it on the Go Playground):
I'm some template.
I'm some template.
I'm some OTHER template.
If you now go ahead, and change the first 2 lines to this:
t := template.Must(template.New("one").Parse(t1src))
t = template.Must(t.New("other").Parse(t2src))
Then what happens here is that we assigned a new template.Template value to t, which was the result of parsing t2src, so that will be the default, but still both templates can be "reached" from it as they are associated. The output changes to this (try it on the Go Playground):
I'm some OTHER template.
I'm some template.
I'm some OTHER template.
Calling template.New() (function) creates a new template, associated to none. When calling Template.New() (method), the returned template will be associated with (all) the template(s) the method is called on.
Now let's see some examples regarding "embedded" templates.
func main() {
t := template.Must(template.New("one").Parse(t1src))
template.Must(t.New("other").Parse(t2src))
template.Must(t.New("third").Parse(t3src))
t.Execute(os.Stdout, nil)
t.ExecuteTemplate(os.Stdout, "one", nil)
t.ExecuteTemplate(os.Stdout, "other", nil)
t.ExecuteTemplate(os.Stdout, "embedded", nil)
t.ExecuteTemplate(os.Stdout, "third", nil)
}
const t1src = `I'm some template. {{block "embedded" .}}I'm embedded in "one".
{{end}}`
const t2src = `I'm some OTHER template.
`
const t3src = `I'm the 3rd, including everything from "one": {{template "one"}}
`
Output (try it on the Go Playground):
I'm some template. I'm embedded in "one".
I'm some template. I'm embedded in "one".
I'm some OTHER template.
I'm embedded in "one".
I'm the 3rd, including everything from "one": I'm some template. I'm embedded in "one".
It should be obvious now what the role of the template name is, and where it comes from.
It is used to render associated templates.
For instance:
tmpl := template.Must(template.New("body").Parse(`
{{ define "body" }}
Body
{{ end }}
`))
tmpl = template.Must(tmpl.New("base").Parse(`
Start of base template
{{ template "body" }}
End of base template
`))
tmpl = template.Must(tmpl.New("baz").Parse(`
Start of baz template
{{ template "body" }}
End of baz template
`))
tmpl.ExecuteTemplate(os.Stdout, "base", nil)
tmpl.ExecuteTemplate(os.Stdout, "baz", nil)
Play Example
Output:
Start of base template
Body
End of base template
Start of baz template
Body
End of baz template
tmpl.ExecuteTemplate(os.Stdout, "base", nil) will render the template using the "base" template
tmpl.ExecuteTemplate(os.Stdout, "baz", nil) will render the template using the "baz" template
If you don't need the name, you can just use the new builtin with
template.Template:
package main
import (
"os"
"text/template"
)
func main() {
t, err := new(template.Template).Parse("hello {{.}}\n")
if err != nil {
panic(err)
}
t.Execute(os.Stdout, "world")
}

Resources