A single type to wrap text/template.Template and html/template.Template

65 views
Skip to first unread message

Renee Jylkka

unread,
Dec 31, 2018, 3:51:34 PM12/31/18
to golang-nuts
Hello,

The project that I am working on is a web app written on a custom web server using Go and Go templates.  I store all of the templates in a map[string]Template, where the string is the page name.  When someone visits a page, the server checks whether that page is in the map, then if so calls a function to fill in a data structure, then executes the appropriate template, passing it the data structure.  All was rosy until I was asked to create csv downloads for some of the more complex pages.  I cannot use a html/template.Template for those pages, I have to use a text/template.Template for those pages, otherwise the character escaping implemented by html/template creates extra columns in some of the rows.  My immediate thought was that since text/template.Template and html/template.Template have identical function lists, I should of course create an interface which would be implemented by both types.  However, I have no idea how to create an interface to include arguments and return types of that interface type, such as:
func Must(t *Template, err error) *Template
func (t *Template) Funcs(funcMap FuncMap) *Template

If I try to use *Template, the compiler gives an error that Template is undefined.  If I use my interface name in place of *Template, the compiler gives the error that neither text/template.Template nor html/template.Template implements my interface.  Both of these are expected behavior, but of course if I use text/template.Template or html/template.Template in place of *Template, only one of the two packages would implement my interface.

Is there a correct way to wrap these two data types (using an interface or otherwise) so that I can deal with either one in the same data structures and functions, or am I stuck with a lot of duplicate code and data structures, with only slight differences beyond which package I'm using?

Thanks!
Renee Jylkka
Message has been deleted
Message has been deleted

K Davidson

unread,
Dec 31, 2018, 8:58:07 PM12/31/18
to golang-nuts

Greetings,

One way to accomplish this may be to use embedding to wrap both Templates into a new type:
 
package main

import (
    txt 
"text/template"
    
"html/template"
)

// CsvTemplate wraps a html/template.Template and add text/template.Template field for CSV output.
type 
CsvTemplate struct {
    
template.Template
    t txt
.Template
}


-K
- show quoted text -

Renee Jylkka

unread,
Jan 1, 2019, 12:24:09 PM1/1/19
to golan...@googlegroups.com
Hi K,

Thanks for your response.  It looks to me like this would give me both an HTML template and a text template.  In my case, it's an either-or thing, which is what is so frustrating.  If the page is an html page, it stores an html/template in the map.  If it's a csv page, it stores a text/template in the map (although currently this has to be a different map).  I have to have two sets of functions to interact with those maps and their templates, where the primary differences are, for example, whether it calls htmlTemplate.Must() or textTemplate.Must(), or whether the function accepts as an argument a *htmlTemplate.Template or a *textTemplate.Template.

I suppose that I could make my own package to wrap the two packages,  let's call it bothTemplates for the purpose of example:

package bothTemplates

import (
    text "text/template"
    html "html/template"
)

type BothTemplates struct {
    isHTML bool
    t *text.Template
    h *html.Template
}

And then wrap every single one of the functions, or at least the functions that I use (although that's most of the functions, so for completeness' sake I really may as well just go ahead and wrap all of them) to choose whether to use t and text/template or h and html/template based on the value of isHTML, and to allow me to pass that bool to the functions which create a new Template.  At least then all of the redundancy would be decently out of sight, and I would only have to maintain it if the template packages change.

But is that really necessary?  Isn't this the purpose of interfaces -- so that you can take two or more types with identical functions and plug in whichever one you need to use in that case?  Are interfaces really, truly incompatible with chaining?  I think that's what this comes down to -- the text/template and html/template packages are designed for function chaining, so nearly every function returns a pointer to its own type.

Thanks,
Renee Jylkka


On 12/31/2018 8:53 PM, K Davidson wrote:
One way to accomplish this may be to use embedding to wrap both Templates into a new type:
 
package main

import (
    txt
"text/template"
   
"html/template"
)

// CsvTemplate wraps a html/template.Template and adds a text/template.Template // field for CSV output.

type
CsvTemplate struct {
   
template.Template
    t txt
.Template
}
On Monday, December 31, 2018 at 1:51:34 PM UTC-7, Renee Jylkka wrote:
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4p3-Q4pUJv8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

-- 
Renee Jylkka
Ormandy, Inc.
re...@ormandy.com

Please direct all support requests to sup...@ormandysoftware.com

NOTICE:  This communication, including attachments, is for the exclusive use of addressee and may contain proprietary, confidential and/or privileged information.  If the reader of this communication is not the intended recipient, or an employee or agent responsible for delivering this message to the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication or any attachments is strictly prohibited. If you are not the intended recipient, please notify the sender immediately by return e-mail, delete this communication and destroy all copies.
Reply all
Reply to author
Forward
0 new messages