96 lines
2.0 KiB
Go
96 lines
2.0 KiB
Go
|
package raymond
|
||
|
|
||
|
import "reflect"
|
||
|
|
||
|
// DataFrame represents a private data frame.
|
||
|
//
|
||
|
// Cf. private variables documentation at: http://handlebarsjs.com/block_helpers.html
|
||
|
type DataFrame struct {
|
||
|
parent *DataFrame
|
||
|
data map[string]interface{}
|
||
|
}
|
||
|
|
||
|
// NewDataFrame instanciates a new private data frame.
|
||
|
func NewDataFrame() *DataFrame {
|
||
|
return &DataFrame{
|
||
|
data: make(map[string]interface{}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy instanciates a new private data frame with receiver as parent.
|
||
|
func (p *DataFrame) Copy() *DataFrame {
|
||
|
result := NewDataFrame()
|
||
|
|
||
|
for k, v := range p.data {
|
||
|
result.data[k] = v
|
||
|
}
|
||
|
|
||
|
result.parent = p
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// newIterDataFrame instanciates a new private data frame with receiver as parent and with iteration data set (@index, @key, @first, @last)
|
||
|
func (p *DataFrame) newIterDataFrame(length int, i int, key interface{}) *DataFrame {
|
||
|
result := p.Copy()
|
||
|
|
||
|
result.Set("index", i)
|
||
|
result.Set("key", key)
|
||
|
result.Set("first", i == 0)
|
||
|
result.Set("last", i == length-1)
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Set sets a data value.
|
||
|
func (p *DataFrame) Set(key string, val interface{}) {
|
||
|
p.data[key] = val
|
||
|
}
|
||
|
|
||
|
// Get gets a data value.
|
||
|
func (p *DataFrame) Get(key string) interface{} {
|
||
|
return p.find([]string{key})
|
||
|
}
|
||
|
|
||
|
// find gets a deep data value
|
||
|
//
|
||
|
// @todo This is NOT consistent with the way we resolve data in template (cf. `evalDataPathExpression()`) ! FIX THAT !
|
||
|
func (p *DataFrame) find(parts []string) interface{} {
|
||
|
data := p.data
|
||
|
|
||
|
for i, part := range parts {
|
||
|
val := data[part]
|
||
|
if val == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if i == len(parts)-1 {
|
||
|
// found
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
valValue := reflect.ValueOf(val)
|
||
|
if valValue.Kind() != reflect.Map {
|
||
|
// not found
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// continue
|
||
|
data = mapStringInterface(valValue)
|
||
|
}
|
||
|
|
||
|
// not found
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// mapStringInterface converts any `map` to `map[string]interface{}`
|
||
|
func mapStringInterface(value reflect.Value) map[string]interface{} {
|
||
|
result := make(map[string]interface{})
|
||
|
|
||
|
for _, key := range value.MapKeys() {
|
||
|
result[strValue(key)] = value.MapIndex(key).Interface()
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|