shithub: hugo

Download patch

ref: 4bed69629e55f7292505a74e8437a5a05ddf9a22
parent: 8d28686edcf19b5dd067482b72fdc1b93c99ef7f
author: Marek Janda <[email protected]>
date: Sun Aug 2 03:00:43 EDT 2015

Add map support to scratch

--- a/docs/content/extras/scratch.md
+++ b/docs/content/extras/scratch.md
@@ -14,9 +14,13 @@
 `Scratch` -- a "scratchpad" for your node- or page-scoped variables. In most cases you can do well without `Scratch`, but there are some use cases that aren't solvable with Go's templates without `Scratch`'s help, due to scoping issues.
 
 
-`Scratch` is added to both `Node` and `Page` -- with the three methods `Set`, `Get` and `Add`. `Set` and `Add` takes a `key` and the `value` to add. Get returns the `value` for the `key` given.
+`Scratch` is added to both `Node` and `Page` -- with following methods:
+* `Set` and `Add` takes a `key` and the `value` to add.
+* `Get` returns the `value` for the `key` given.
+* `SetInMap` takes a `key`, `mapKey` and `value`
+* `GetSortedMapValues` returns array of values from `key` sorted by `mapKey`
 
-`Set` can store values of any type. `Add` accepts values that support Go's `+` operator.
+`Set` and `SetInMap` can store values of any type. `Add` accepts values that support Go's `+` operator.
 
 The scope of the backing data is global for the given `Node` or `Page`, and spans partial and shortcode includes.
 
@@ -37,6 +41,12 @@
 
 {{ $.Scratch.Set "v1" 123 }}
 {{ $.Scratch.Get "v1" }}  {{/* => 123 */}}
+
+{{ $.Scratch.SetInMap "a3" "b" "XX" }}
+{{ $.Scratch.SetInMap "a3" "a" "AA" }}
+{{ $.Scratch.SetInMap "a3" "c" "CC" }}
+{{ $.Scratch.SetInMap "a3" "b" "BB" }}
+{{ $.Scratch.GetSortedMapValues "a3" }} {{/* => []interface {}{"AA", "BB", "CC"} */}}
 ```
 
 **Note:** The examples above uses the special `$` variable, which refers to the top-level node. This is the behavior you most likely want, and will help remove some confusion when using `Scratch` inside page range loops -- and you start inadvertently calling the wrong `Scratch`. But there may be use cases for `{{ .Scratch.Add "key" "some value" }}`.
--- a/hugolib/scratch.go
+++ b/hugolib/scratch.go
@@ -15,6 +15,7 @@
 
 import (
 	"github.com/spf13/hugo/helpers"
+	"sort"
 )
 
 // Scratch is a writable context used for stateful operations in Page/Node rendering.
@@ -50,6 +51,41 @@
 // Get returns a value previously set by Add or Set
 func (c *Scratch) Get(key string) interface{} {
 	return c.values[key]
+}
+
+// SetInMap stores a value to a map with the given key in the Node context.
+// This map can later be retrieved with GetSortedMapValues.
+func (c *Scratch) SetInMap(key string, mapKey string, value interface{}) string {
+	_, found := c.values[key]
+	if !found {
+		c.values[key] = make(map[string]interface{})
+	}
+
+	c.values[key].(map[string]interface{})[mapKey] = value
+	return ""
+}
+
+// GetSortedMapValues returns a sorted map previously filled with SetInMap
+func (c *Scratch) GetSortedMapValues(key string) interface{} {
+	if c.values[key] == nil {
+		return nil
+	}
+
+	unsortedMap := c.values[key].(map[string]interface{})
+
+	var keys []string
+	for mapKey, _ := range unsortedMap {
+		keys = append(keys, mapKey)
+	}
+
+	sort.Strings(keys)
+
+	sortedArray := make([]interface{}, len(unsortedMap))
+	for i, mapKey := range keys {
+		sortedArray[i] = unsortedMap[mapKey]
+	}
+
+	return sortedArray
 }
 
 func newScratch() *Scratch {
--- a/hugolib/scratch_test.go
+++ b/hugolib/scratch_test.go
@@ -47,3 +47,21 @@
 		t.Errorf("Should not return anything, but got %v", nothing)
 	}
 }
+
+func TestScratchSetInMap(t *testing.T) {
+	scratch := newScratch()
+	scratch.SetInMap("key", "lux", "Lux")
+	scratch.SetInMap("key", "abc", "Abc")
+	scratch.SetInMap("key", "zyx", "Zyx")
+	scratch.SetInMap("key", "abc", "Abc (updated)")
+	scratch.SetInMap("key", "def", "Def")
+	assert.Equal(t, []interface{}{0: "Abc (updated)", 1: "Def", 2: "Lux", 3: "Zyx"}, scratch.GetSortedMapValues("key"))
+}
+
+func TestScratchGetSortedMapValues(t *testing.T) {
+	scratch := newScratch()
+	nothing := scratch.GetSortedMapValues("nothing")
+	if nothing != nil {
+		t.Errorf("Should not return anything, but got %v", nothing)
+	}
+}