summaryrefslogtreecommitdiffstats
path: root/hugolib
diff options
context:
space:
mode:
authorspf13 <steve.francia@gmail.com>2014-11-20 12:32:21 -0500
committerspf13 <steve.francia@gmail.com>2014-11-20 12:36:57 -0500
commit73f203ad86a71136a1d35e0aa1bba574edb91a51 (patch)
tree8e1e336f03df4b583a27e15f4e1bf28182331605 /hugolib
parent92a3372a3fdc0365a06a75e6d97f24e624db879b (diff)
Move template library into it's own package (tpl). No longer dependent on hugolib. Can be used externally.
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/page.go15
-rw-r--r--hugolib/shortcode.go20
-rw-r--r--hugolib/shortcode_test.go32
-rw-r--r--hugolib/site.go5
-rw-r--r--hugolib/site_test.go21
-rw-r--r--hugolib/template.go690
-rw-r--r--hugolib/template_embedded.go97
-rw-r--r--hugolib/template_test.go342
8 files changed, 54 insertions, 1168 deletions
diff --git a/hugolib/page.go b/hugolib/page.go
index 14a290c7e..3cf9843eb 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -17,10 +17,6 @@ import (
"bytes"
"errors"
"fmt"
- "github.com/spf13/hugo/helpers"
- "github.com/spf13/hugo/parser"
- jww "github.com/spf13/jwalterweatherman"
- "github.com/spf13/viper"
"html/template"
"io"
"net/url"
@@ -29,8 +25,13 @@ import (
"time"
"github.com/spf13/cast"
+ "github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/hugofs"
+ "github.com/spf13/hugo/parser"
"github.com/spf13/hugo/source"
+ "github.com/spf13/hugo/tpl"
+ jww "github.com/spf13/jwalterweatherman"
+ "github.com/spf13/viper"
)
type Page struct {
@@ -44,7 +45,7 @@ type Page struct {
Truncated bool
Draft bool
PublishDate time.Time
- Tmpl Template
+ Tmpl tpl.Template
Markup string
extension string
@@ -528,7 +529,7 @@ func (p *Page) Render(layout ...string) template.HTML {
curLayout = layout[0]
}
- return ExecuteTemplateToHTML(p, p.Layout(curLayout)...)
+ return tpl.ExecuteTemplateToHTML(p, p.Layout(curLayout)...)
}
func (page *Page) guessMarkupType() string {
@@ -629,7 +630,7 @@ func (page *Page) SaveSource() error {
return page.SaveSourceAs(page.FullFilePath())
}
-func (p *Page) ProcessShortcodes(t Template) {
+func (p *Page) ProcessShortcodes(t tpl.Template) {
// these short codes aren't used until after Page render,
// but processed here to avoid coupling
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index f90093e7a..7e56c2a4a 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -16,14 +16,16 @@ package hugolib
import (
"bytes"
"fmt"
- "github.com/spf13/hugo/helpers"
- jww "github.com/spf13/jwalterweatherman"
"html/template"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
+
+ "github.com/spf13/hugo/helpers"
+ "github.com/spf13/hugo/tpl"
+ jww "github.com/spf13/jwalterweatherman"
)
type ShortcodeFunc func([]string) string
@@ -117,7 +119,7 @@ func (sc shortcode) String() string {
// all in one go: extract, render and replace
// only used for testing
-func ShortcodesHandle(stringToParse string, page *Page, t Template) string {
+func ShortcodesHandle(stringToParse string, page *Page, t tpl.Template) string {
tmpContent, tmpShortcodes := extractAndRenderShortcodes(stringToParse, page, t)
@@ -154,7 +156,7 @@ func createShortcodePlaceholder(id int) string {
return fmt.Sprintf("<div>%s-%d</div>", shortcodePlaceholderPrefix, id)
}
-func renderShortcodes(sc shortcode, p *Page, t Template) string {
+func renderShortcodes(sc shortcode, p *Page, t tpl.Template) string {
tokenizedRenderedShortcodes := make(map[string](string))
startCount := 0
@@ -169,7 +171,7 @@ func renderShortcodes(sc shortcode, p *Page, t Template) string {
return shortcodes
}
-func renderShortcode(sc shortcode, tokenizedShortcodes map[string](string), cnt int, p *Page, t Template) string {
+func renderShortcode(sc shortcode, tokenizedShortcodes map[string](string), cnt int, p *Page, t tpl.Template) string {
var data = &ShortcodeWithPage{Params: sc.params, Page: p}
tmpl := GetTemplate(sc.name, t)
@@ -209,7 +211,7 @@ func renderShortcode(sc shortcode, tokenizedShortcodes map[string](string), cnt
return ShortcodeRender(tmpl, data)
}
-func extractAndRenderShortcodes(stringToParse string, p *Page, t Template) (string, map[string]string) {
+func extractAndRenderShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]string) {
content, shortcodes, err := extractShortcodes(stringToParse, p, t)
renderedShortcodes := make(map[string]string)
@@ -235,7 +237,7 @@ func extractAndRenderShortcodes(stringToParse string, p *Page, t Template) (stri
// pageTokens state:
// - before: positioned just before the shortcode start
// - after: shortcode(s) consumed (plural when they are nested)
-func extractShortcode(pt *pageTokens, p *Page, t Template) (shortcode, error) {
+func extractShortcode(pt *pageTokens, p *Page, t tpl.Template) (shortcode, error) {
sc := shortcode{}
var isInner = false
@@ -334,7 +336,7 @@ Loop:
return sc, nil
}
-func extractShortcodes(stringToParse string, p *Page, t Template) (string, map[string]shortcode, error) {
+func extractShortcodes(stringToParse string, p *Page, t tpl.Template) (string, map[string]shortcode, error) {
shortCodes := make(map[string]shortcode)
@@ -452,7 +454,7 @@ func replaceShortcodeTokens(source []byte, prefix string, numReplacements int, w
return buff[0:width], nil
}
-func GetTemplate(name string, t Template) *template.Template {
+func GetTemplate(name string, t tpl.Template) *template.Template {
if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
return x
}
diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go
index 91b3dad17..002946bfd 100644
--- a/hugolib/shortcode_test.go
+++ b/hugolib/shortcode_test.go
@@ -2,20 +2,22 @@ package hugolib
import (
"fmt"
- "github.com/spf13/hugo/helpers"
- "github.com/spf13/viper"
"reflect"
"regexp"
"sort"
"strings"
"testing"
+
+ "github.com/spf13/hugo/helpers"
+ "github.com/spf13/hugo/tpl"
+ "github.com/spf13/viper"
)
func pageFromString(in, filename string) (*Page, error) {
return NewPageFrom(strings.NewReader(in), filename)
}
-func CheckShortCodeMatch(t *testing.T, input, expected string, template Template) {
+func CheckShortCodeMatch(t *testing.T, input, expected string, template tpl.Template) {
p, _ := pageFromString(SIMPLE_PAGE, "simple.md")
output := ShortcodesHandle(input, p, template)
@@ -26,13 +28,13 @@ func CheckShortCodeMatch(t *testing.T, input, expected string, template Template
}
func TestNonSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
// notice the syntax diff from 0.12, now comment delims must be added
CheckShortCodeMatch(t, "{{%/* movie 47238zzb */%}}", "{{% movie 47238zzb %}}", tem)
}
func TestPositionalParamSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("video.html", `Playing Video {{ .Get 0 }}`)
CheckShortCodeMatch(t, "{{< video 47238zzb >}}", "Playing Video 47238zzb", tem)
@@ -43,7 +45,7 @@ func TestPositionalParamSC(t *testing.T) {
}
func TestNamedParamSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("img.html", `<img{{ with .Get "src" }} src="{{.}}"{{end}}{{with .Get "class"}} class="{{.}}"{{end}}>`)
CheckShortCodeMatch(t, `{{< img src="one" >}}`, `<img src="one">`, tem)
@@ -55,7 +57,7 @@ func TestNamedParamSC(t *testing.T) {
}
func TestInnerSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
CheckShortCodeMatch(t, `{{< inside class="aspen" >}}`, `<div class="aspen"></div>`, tem)
@@ -64,7 +66,7 @@ func TestInnerSC(t *testing.T) {
}
func TestInnerSCWithMarkdown(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
CheckShortCodeMatch(t, `{{% inside %}}
@@ -76,7 +78,7 @@ func TestInnerSCWithMarkdown(t *testing.T) {
}
func TestInnerSCWithAndWithoutMarkdown(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("inside.html", `<div{{with .Get "class"}} class="{{.}}"{{end}}>{{ .Inner }}</div>`)
CheckShortCodeMatch(t, `{{% inside %}}
@@ -98,14 +100,14 @@ This is **plain** text.
}
func TestEmbeddedSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
CheckShortCodeMatch(t, "{{% test %}}", "This is a simple Test", tem)
CheckShortCodeMatch(t, `{{% figure src="/found/here" class="bananas orange" %}}`, "\n<figure class=\"bananas orange\">\n \n <img src=\"/found/here\" />\n \n \n</figure>\n", tem)
CheckShortCodeMatch(t, `{{% figure src="/found/here" class="bananas orange" caption="This is a caption" %}}`, "\n<figure class=\"bananas orange\">\n \n <img src=\"/found/here\" alt=\"This is a caption\" />\n \n \n <figcaption>\n <p>\n This is a caption\n \n \n \n </p> \n </figcaption>\n \n</figure>\n", tem)
}
func TestNestedSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("scn1.html", `<div>Outer, inner is {{ .Inner }}</div>`)
tem.AddInternalShortcode("scn2.html", `<div>SC2</div>`)
@@ -113,7 +115,7 @@ func TestNestedSC(t *testing.T) {
}
func TestNestedComplexSC(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("row.html", `-row-{{ .Inner}}-rowStop-`)
tem.AddInternalShortcode("column.html", `-col-{{.Inner }}-colStop-`)
tem.AddInternalShortcode("aside.html", `-aside-{{ .Inner }}-asideStop-`)
@@ -127,7 +129,7 @@ func TestNestedComplexSC(t *testing.T) {
}
func TestFigureImgWidth(t *testing.T) {
- tem := NewTemplate()
+ tem := tpl.New()
CheckShortCodeMatch(t, `{{% figure src="/found/here" class="bananas orange" alt="apple" width="100px" %}}`, "\n<figure class=\"bananas orange\">\n \n <img src=\"/found/here\" alt=\"apple\" width=\"100px\" />\n \n \n</figure>\n", tem)
}
@@ -138,7 +140,7 @@ func TestHighlight(t *testing.T) {
defer viper.Set("PygmentsStyle", viper.Get("PygmentsStyle"))
viper.Set("PygmentsStyle", "bw")
- tem := NewTemplate()
+ tem := tpl.New()
code := `
{{< highlight java >}}
@@ -196,7 +198,7 @@ func TestExtractShortcodes(t *testing.T) {
} {
p, _ := pageFromString(SIMPLE_PAGE, "simple.md")
- tem := NewTemplate()
+ tem := tpl.New()
tem.AddInternalShortcode("tag.html", `tag`)
tem.AddInternalShortcode("sc1.html", `sc1`)
tem.AddInternalShortcode("sc2.html", `sc2`)
diff --git a/hugolib/site.go b/hugolib/site.go
index f879c5245..fc3183fa3 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -31,6 +31,7 @@ import (
"github.com/spf13/hugo/hugofs"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/target"
+ "github.com/spf13/hugo/tpl"
"github.com/spf13/hugo/transform"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/nitro"
@@ -61,7 +62,7 @@ var DefaultTimer *nitro.B
type Site struct {
Pages Pages
Files []*source.File
- Tmpl Template
+ Tmpl tpl.Template
Taxonomies TaxonomyList
Source source.Input
Sections Taxonomy
@@ -166,7 +167,7 @@ func (s *Site) Analyze() {
}
func (s *Site) prepTemplates() {
- s.Tmpl = NewTemplate()
+ s.Tmpl = tpl.T()
s.Tmpl.LoadTemplates(s.absLayoutDir())
if s.hasTheme() {
s.Tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
diff --git a/hugolib/site_test.go b/hugolib/site_test.go
index fc93389dd..ce1d3f0ad 100644
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -13,6 +13,7 @@ import (
"github.com/spf13/hugo/hugofs"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/target"
+ "github.com/spf13/hugo/tpl"
"github.com/spf13/viper"
)
@@ -46,6 +47,14 @@ more text
`
)
+func templatePrep(s *Site) {
+ s.Tmpl = tpl.New()
+ s.Tmpl.LoadTemplates(s.absLayoutDir())
+ if s.hasTheme() {
+ s.Tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
+ }
+}
+
func pageMust(p *Page, err error) *Page {
if err != nil {
panic(err)
@@ -57,7 +66,7 @@ func TestDegenerateRenderThingMissingTemplate(t *testing.T) {
p, _ := NewPageFrom(strings.NewReader(PAGE_SIMPLE_TITLE), "content/a/file.md")
p.Convert()
s := new(Site)
- s.prepTemplates()
+ templatePrep(s)
err := s.renderThing(p, "foobar", nil)
if err == nil {
t.Errorf("Expected err to be returned when missing the template.")
@@ -66,7 +75,7 @@ func TestDegenerateRenderThingMissingTemplate(t *testing.T) {
func TestAddInvalidTemplate(t *testing.T) {
s := new(Site)
- s.prepTemplates()
+ templatePrep(s)
err := s.addTemplate("missing", TEMPLATE_MISSING_FUNC)
if err == nil {
t.Fatalf("Expecting the template to return an error")
@@ -108,7 +117,7 @@ func TestRenderThing(t *testing.T) {
}
s := new(Site)
- s.prepTemplates()
+ templatePrep(s)
for i, test := range tests {
p, err := NewPageFrom(strings.NewReader(test.content), "content/a/file.md")
@@ -154,7 +163,7 @@ func TestRenderThingOrDefault(t *testing.T) {
hugofs.DestinationFS = new(afero.MemMapFs)
s := &Site{}
- s.prepTemplates()
+ templatePrep(s)
for i, test := range tests {
p, err := NewPageFrom(strings.NewReader(PAGE_SIMPLE_TITLE), "content/a/file.md")
@@ -306,7 +315,7 @@ func TestSkipRender(t *testing.T) {
}
s.initializeSiteInfo()
- s.prepTemplates()
+ templatePrep(s)
must(s.addTemplate("_default/single.html", "{{.Content}}"))
must(s.addTemplate("head", "<head><script src=\"script.js\"></script></head>"))
@@ -366,7 +375,7 @@ func TestAbsUrlify(t *testing.T) {
}
t.Logf("Rendering with BaseUrl %q and CanonifyUrls set %v", viper.GetString("baseUrl"), canonify)
s.initializeSiteInfo()
- s.prepTemplates()
+ templatePrep(s)
must(s.addTemplate("blue/single.html", TEMPLATE_WITH_URL_ABS))
if err := s.CreatePages(); err != nil {
diff --git a/hugolib/template.go b/hugolib/template.go
deleted file mode 100644
index 59221093f..000000000
--- a/hugolib/template.go
+++ /dev/null
@@ -1,690 +0,0 @@
-package hugolib
-
-import (
- "bytes"
- "errors"
- "html"
- "html/template"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "reflect"
- "strconv"
- "strings"
-
- "github.com/eknkc/amber"
- "github.com/spf13/cast"
- "github.com/spf13/hugo/helpers"
- jww "github.com/spf13/jwalterweatherman"
-)
-
-var localTemplates *template.Template
-
-func Eq(x, y interface{}) bool {
- return reflect.DeepEqual(x, y)
-}
-
-func Ne(x, y interface{}) bool {
- return !Eq(x, y)
-}
-
-func Ge(a, b interface{}) bool {
- left, right := compareGetFloat(a, b)
- return left >= right
-}
-
-func Gt(a, b interface{}) bool {
- left, right := compareGetFloat(a, b)
- return left > right
-}
-
-func Le(a, b interface{}) bool {
- left, right := compareGetFloat(a, b)
- return left <= right
-}
-
-func Lt(a, b interface{}) bool {
- left, right := compareGetFloat(a, b)
- return left < right
-}
-
-func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
- var left, right float64
- av := reflect.ValueOf(a)
-
- switch av.Kind() {
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
- left = float64(av.Len())
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- left = float64(av.Int())
- case reflect.Float32, reflect.Float64:
- left = av.Float()
- case reflect.String:
- left, _ = strconv.ParseFloat(av.String(), 64)
- }
-
- bv := reflect.ValueOf(b)
-
- switch bv.Kind() {
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
- right = float64(bv.Len())
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- right = float64(bv.Int())
- case reflect.Float32, reflect.Float64:
- right = bv.Float()
- case reflect.String:
- right, _ = strconv.ParseFloat(bv.String(), 64)
- }
-
- return left, right
-}
-
-func Intersect(l1, l2 interface{}) (interface{}, error) {
-
- if l1 == nil || l2 == nil {
- return make([]interface{}, 0), nil
- }
-
- l1v := reflect.ValueOf(l1)
- l2v := reflect.ValueOf(l2)
-
- switch l1v.Kind() {
- case reflect.Array, reflect.Slice:
- switch l2v.Kind() {
- case reflect.Array, reflect.Slice:
- r := reflect.MakeSlice(l1v.Type(), 0, 0)
- for i := 0; i < l1v.Len(); i++ {
- l1vv := l1v.Index(i)
- for j := 0; j < l2v.Len(); j++ {
- l2vv := l2v.Index(j)
- switch l1vv.Kind() {
- case reflect.String:
- if l1vv.Type() == l2vv.Type() && l1vv.String() == l2vv.String() && !In(r, l2vv) {
- r = reflect.Append(r, l2vv)
- }
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch l2vv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if l1vv.Int() == l2vv.Int() && !In(r, l2vv) {
- r = reflect.Append(r, l2vv)
- }
- }
- case reflect.Float32, reflect.Float64:
- switch l2vv.Kind() {
- case reflect.Float32, reflect.Float64:
- if l1vv.Float() == l2vv.Float() && !In(r, l2vv) {
- r = reflect.Append(r, l2vv)
- }
- }
- }
- }
- }
- return r.Interface(), nil
- default:
- return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
- }
- default:
- return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
- }
-}
-
-func In(l interface{}, v interface{}) bool {
- lv := reflect.ValueOf(l)
- vv := reflect.ValueOf(v)
-
- switch lv.Kind() {
- case reflect.Array, reflect.Slice:
- for i := 0; i < lv.Len(); i++ {
- lvv := lv.Index(i)
- switch lvv.Kind() {
- case reflect.String:
- if vv.Type() == lvv.Type() && vv.String() == lvv.String() {
- return true
- }
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch vv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if vv.Int() == lvv.Int() {
- return true
- }
- }
- case reflect.Float32, reflect.Float64:
- switch vv.Kind() {
- case reflect.Float32, reflect.Float64:
- if vv.Float() == lvv.Float() {
- return true
- }
- }
- }
- }
- case reflect.String:
- if vv.Type() == lv.Type() && strings.Contains(lv.String(), vv.String()) {
- return true
- }
- }
- return false
-}
-
-// First is exposed to templates, to iterate over the first N items in a
-// rangeable list.
-func First(limit interface{}, seq interface{}) (interface{}, error) {
-
- limitv, err := cast.ToIntE(limit)
-
- if err != nil {
- return nil, err
- }
-
- if limitv < 1 {
- return nil, errors.New("can't return negative/empty count of items from sequence")
- }
-
- seqv := reflect.ValueOf(seq)
- // this is better than my first pass; ripped from text/template/exec.go indirect():
- for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
- if seqv.IsNil() {
- return nil, errors.New("can't iterate over a nil value")
- }
- if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
- break
- }
- }
-
- switch seqv.Kind() {
- case reflect.Array, reflect.Slice, reflect.String:
- // okay
- default:
- return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
- }
- if limitv > seqv.Len() {
- limitv = seqv.Len()
- }
- return seqv.Slice(0, limitv).Interface(), nil
-}
-
-func Where(seq, key, match interface{}) (interface{}, error) {
- seqv := reflect.ValueOf(seq)
- kv := reflect.ValueOf(key)
- mv := reflect.ValueOf(match)
-
- // this is better than my first pass; ripped from text/template/exec.go indirect():
- for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
- if seqv.IsNil() {
- return nil, errors.New("can't iterate over a nil value")
- }
- if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
- break
- }
- }
-
- switch seqv.Kind() {
- case reflect.Array, reflect.Slice:
- r := reflect.MakeSlice(seqv.Type(), 0, 0)
- for i := 0; i < seqv.Len(); i++ {
- var vvv reflect.Value
- vv := seqv.Index(i)
- switch vv.Kind() {
- case reflect.Map:
- if kv.Type() == vv.Type().Key() && vv.MapIndex(kv).IsValid() {
- vvv = vv.MapIndex(kv)
- }
- case reflect.Struct:
- if kv.Kind() == reflect.String {
- method := vv.MethodByName(kv.String())
- if method.IsValid() && method.Type().NumIn() == 0 && method.Type().NumOut() > 0 {
- vvv = method.Call(nil)[0]
- } else if vv.FieldByName(kv.String()).IsValid() {
- vvv = vv.FieldByName(kv.String())
- }
- }
- case reflect.Ptr:
- if !vv.IsNil() {
- ev := vv.Elem()
- switch ev.Kind() {
- case reflect.Map:
- if kv.Type() == ev.Type().Key() && ev.MapIndex(kv).IsValid() {
- vvv = ev.MapIndex(kv)
- }
- case reflect.Struct:
- if kv.Kind() == reflect.String {
- method := vv.MethodByName(kv.String())
- if method.IsValid() && method.Type().NumIn() == 0 && method.Type().NumOut() > 0 {
- vvv = method.Call(nil)[0]
- } else if ev.FieldByName(kv.String()).IsValid() {
- vvv = ev.FieldByName(kv.String())
- }
- }
- }
- }
- }
-
- if vvv.IsValid() && mv.Type() == vvv.Type() {
- switch mv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if mv.Int() == vvv.Int() {
- r = reflect.Append(r, vv)
- }
- case reflect.String:
- if mv.String() == vvv.String() {
- r = reflect.Append(r, vv)
- }
- }
- }
- }
- return r.Interface(), nil
- default:
- return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
- }
-}
-
-func IsSet(a interface{}, key interface{}) bool {
- av := reflect.ValueOf(a)
- kv := reflect.ValueOf(key)
-
- switch av.Kind() {
- case reflect.Array, reflect.Chan, reflect.Slice:
- if int64(av.Len()) > kv.Int() {
- return true
- }
- case reflect.Map:
- if kv.Type() == av.Type().Key() {
- return av.MapIndex(kv).IsValid()
- }
- }
-
- return false
-}
-
-func ReturnWhenSet(a interface{}, index int) interface{} {
- av := reflect.ValueOf(a)
-
- switch av.Kind() {
- case reflect.Array, reflect.Slice:
- if av.Len() > index {
-
- avv := av.Index(index)
- switch avv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return avv.Int()
- case reflect.String:
- return avv.String()
- }
- }
- }
-
- return ""
-}
-
-func Highlight(in interface{}, lang string) template.HTML {
- var str string
- av := reflect.ValueOf(in)
- switch av.Kind() {
- case reflect.String:
- str = av.String()
- }
-
- return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
-}
-
-func SafeHtml(text string) template.HTML {
- return template.HTML(text)
-}
-
-func doArithmetic(a, b interface{}, op rune) (interface{}, error) {
- av := reflect.ValueOf(a)
- bv := reflect.ValueOf(b)
- var ai, bi int64
- var af, bf float64
- var au, bu uint64
- switch av.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- ai = av.Int()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bi = bv.Int()
- case reflect.Float32, reflect.Float64:
- af = float64(ai) // may overflow
- ai = 0
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bu = bv.Uint()
- if ai >= 0 {
- au = uint64(ai)
- ai = 0
- } else {
- bi = int64(bu) // may overflow
- bu = 0
- }
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.Float32, reflect.Float64:
- af = av.Float()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bf = float64(bv.Int()) // may overflow
- case reflect.Float32, reflect.Float64:
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bf = float64(bv.Uint()) // may overflow
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- au = av.Uint()
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bi = bv.Int()
- if bi >= 0 {
- bu = uint64(bi)
- bi = 0
- } else {
- ai = int64(au) // may overflow
- au = 0
- }
- case reflect.Float32, reflect.Float64:
- af = float64(au) // may overflow
- au = 0
- bf = bv.Float()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- bu = bv.Uint()
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
- case reflect.String:
- as := av.String()
- if bv.Kind() == reflect.String && op == '+' {
- bs := bv.String()
- return as + bs, nil
- } else {
- return nil, errors.New("Can't apply the operator to the values")
- }
- default:
- return nil, errors.New("Can't apply the operator to the values")
- }
-
- switch op {
- case '+':
- if ai != 0 || bi != 0 {
- return ai + bi, nil
- } else if af != 0 || bf != 0 {
- return af + bf, nil
- } else if au != 0 || bu != 0 {
- return au + bu, nil
- } else {
- return 0, nil
- }
- case '-':
- if ai != 0 || bi != 0 {
- return ai - bi, nil
- } else if af != 0 || bf != 0 {
- return af - bf, nil
- } else if au != 0 || bu != 0 {
- return au - bu, nil
- } else {
- return 0, nil
- }
- case '*':
- if ai != 0 || bi != 0 {
- return ai * bi, nil
- } else if af != 0 || bf != 0 {
- return af * bf, nil
- } else if au != 0 || bu != 0 {
- return au * bu, nil
- } else {
- return 0, nil
- }
- case '/':
- if bi != 0 {
- return ai / bi, nil
- } else if bf != 0 {
- return af / bf, nil
- } else if bu != 0 {
- return au / bu, nil
- } else {
- return nil, errors.New("Can't divide the value by 0")
- }
- default:
- return nil, errors.New("There is no such an operation")
- }
-}
-
-func Mod(a, b interface{}) (int64, error) {
- av := reflect.ValueOf(a)
- bv := reflect.ValueOf(b)
- var ai, bi int64
-
- switch av.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- ai = av.Int()
- default:
- return 0, errors.New("Modulo operator can't be used with non integer value")
- }
-
- switch bv.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- bi = bv.Int()
- default:
- return 0, errors.New("Modulo operator can't be used with non integer value")
- }
-
- if bi == 0 {
- return 0, errors.New("The number can't be divided by zero at modulo operation")
- }
-
-