mirror of
https://github.com/danog/gojekyll.git
synced 2024-11-26 21:34:45 +01:00
Introduce a VariableMap type
This commit is contained in:
parent
3e68659b3a
commit
089417f1db
@ -10,23 +10,23 @@ import (
|
||||
type Collection struct {
|
||||
Site *Site
|
||||
Name string
|
||||
Data map[interface{}]interface{}
|
||||
Data VariableMap
|
||||
Output bool
|
||||
Pages []*Page
|
||||
}
|
||||
|
||||
func makeCollection(s *Site, name string, d map[interface{}]interface{}) *Collection {
|
||||
func makeCollection(s *Site, name string, d VariableMap) *Collection {
|
||||
return &Collection{
|
||||
Site: s,
|
||||
Name: name,
|
||||
Data: d,
|
||||
Output: getBool(d, "output", false),
|
||||
Output: d.Bool("output", false),
|
||||
}
|
||||
}
|
||||
|
||||
// PageArrayVariableValue returns an array of a page data, for use as the template variable
|
||||
// value of the collection.
|
||||
func (c *Collection) PageArrayVariableValue() (d []interface{}) {
|
||||
func (c *Collection) PageArrayVariableValue() (d []VariableMap) {
|
||||
for _, p := range c.Pages {
|
||||
d = append(d, p.PageVariables())
|
||||
}
|
||||
@ -34,28 +34,27 @@ func (c *Collection) PageArrayVariableValue() (d []interface{}) {
|
||||
}
|
||||
|
||||
// Posts returns true if the collection is the special "posts" collection.
|
||||
func (c *Collection) Posts() bool {
|
||||
func (c *Collection) IsPosts() bool {
|
||||
return c.Name == "posts"
|
||||
}
|
||||
|
||||
// SourceDir returns the source directory for pages in the collection.
|
||||
func (c *Collection) SourceDir() string {
|
||||
// Source returns the source directory for pages in the collection.
|
||||
func (c *Collection) Source() string {
|
||||
return filepath.Join(c.Site.Source, "_"+c.Name)
|
||||
}
|
||||
|
||||
// ReadPages scans the file system for collection pages, and adds them to c.Pages.
|
||||
func (c *Collection) ReadPages() error {
|
||||
basePath := c.Site.Source
|
||||
d := map[interface{}]interface{}{
|
||||
defaults := mergeVariableMaps(c.Data, VariableMap{
|
||||
"collection": c.Name,
|
||||
}
|
||||
d = mergeMaps(c.Data, d)
|
||||
})
|
||||
|
||||
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
// if the issue is simply that the directory doesn't exist, ignore the error
|
||||
// if the issue is simply that the directory doesn't exist, warn instead of error
|
||||
if os.IsNotExist(err) {
|
||||
if !c.Posts() {
|
||||
if !c.IsPosts() {
|
||||
fmt.Println("Missing directory for collection", c.Name)
|
||||
}
|
||||
return nil
|
||||
@ -69,7 +68,7 @@ func (c *Collection) ReadPages() error {
|
||||
case info.IsDir():
|
||||
return nil
|
||||
}
|
||||
p, err := ReadPage(rel, d)
|
||||
p, err := ReadPage(rel, defaults)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
@ -81,5 +80,5 @@ func (c *Collection) ReadPages() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return filepath.Walk(c.SourceDir(), walkFn)
|
||||
return filepath.Walk(c.Source(), walkFn)
|
||||
}
|
||||
|
14
helpers.go
14
helpers.go
@ -28,7 +28,7 @@ func copyFile(dst, src string, perm os.FileMode) error {
|
||||
return outf.Close()
|
||||
}
|
||||
|
||||
func getBool(m map[interface{}]interface{}, k string, defaultValue bool) bool {
|
||||
func (m VariableMap) Bool(k string, defaultValue bool) bool {
|
||||
if val, found := m[k]; found {
|
||||
if v, ok := val.(bool); ok {
|
||||
return v
|
||||
@ -37,7 +37,7 @@ func getBool(m map[interface{}]interface{}, k string, defaultValue bool) bool {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func getString(m map[interface{}]interface{}, k string, defaultValue string) string {
|
||||
func (m VariableMap) String(k string, defaultValue string) string {
|
||||
if val, found := m[k]; found {
|
||||
if v, ok := val.(string); ok {
|
||||
return v
|
||||
@ -58,8 +58,8 @@ func LeftPad(s string, n int) string {
|
||||
return string(ws) + s
|
||||
}
|
||||
|
||||
func mergeMaps(a map[interface{}]interface{}, b map[interface{}]interface{}) map[interface{}]interface{} {
|
||||
result := map[interface{}]interface{}{}
|
||||
func mergeVariableMaps(a VariableMap, b VariableMap) VariableMap {
|
||||
result := VariableMap{}
|
||||
for k, v := range a {
|
||||
result[k] = v
|
||||
}
|
||||
@ -69,10 +69,10 @@ func mergeMaps(a map[interface{}]interface{}, b map[interface{}]interface{}) map
|
||||
return result
|
||||
}
|
||||
|
||||
// stringMap returns a string-indexed map with the same values as its argument.
|
||||
// makeVariableMap returns a string-indexed map with the same values as its argument.
|
||||
// Non-strings keys are converted to strings.
|
||||
func stringMap(m map[interface{}]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
func makeVariableMap(m map[interface{}]interface{}) VariableMap {
|
||||
result := VariableMap{}
|
||||
for k, v := range m {
|
||||
stringer, ok := k.(fmt.Stringer)
|
||||
if ok {
|
||||
|
@ -13,37 +13,37 @@ func TestLeftPad(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetXXX(t *testing.T) {
|
||||
d := map[interface{}]interface{}{
|
||||
d := VariableMap{
|
||||
"t": true,
|
||||
"f": false,
|
||||
"s": "ss",
|
||||
}
|
||||
assert.Equal(t, true, getBool(d, "t", true))
|
||||
assert.Equal(t, true, getBool(d, "t", false))
|
||||
assert.Equal(t, false, getBool(d, "f", true))
|
||||
assert.Equal(t, false, getBool(d, "f", true))
|
||||
assert.Equal(t, true, getBool(d, "-", true))
|
||||
assert.Equal(t, false, getBool(d, "-", false))
|
||||
assert.Equal(t, true, getBool(d, "s", true))
|
||||
assert.Equal(t, false, getBool(d, "s", false))
|
||||
assert.Equal(t, true, d.Bool("t", true))
|
||||
assert.Equal(t, true, d.Bool("t", false))
|
||||
assert.Equal(t, false, d.Bool("f", true))
|
||||
assert.Equal(t, false, d.Bool("f", true))
|
||||
assert.Equal(t, true, d.Bool("-", true))
|
||||
assert.Equal(t, false, d.Bool("-", false))
|
||||
assert.Equal(t, true, d.Bool("s", true))
|
||||
assert.Equal(t, false, d.Bool("s", false))
|
||||
|
||||
assert.Equal(t, "ss", getString(d, "s", "-"))
|
||||
assert.Equal(t, "--", getString(d, "-", "--"))
|
||||
assert.Equal(t, "--", getString(d, "t", "--"))
|
||||
assert.Equal(t, "ss", d.String("s", "-"))
|
||||
assert.Equal(t, "--", d.String("-", "--"))
|
||||
assert.Equal(t, "--", d.String("t", "--"))
|
||||
}
|
||||
|
||||
func TestMergeMaps(t *testing.T) {
|
||||
m1 := map[interface{}]interface{}{"a": 1, "b": 2}
|
||||
m2 := map[interface{}]interface{}{"b": 3, "c": 4}
|
||||
expected := map[interface{}]interface{}{"a": 1, "b": 3, "c": 4}
|
||||
actual := mergeMaps(m1, m2)
|
||||
func TestMakeVariableMap(t *testing.T) {
|
||||
input := map[interface{}]interface{}{"a": 1, 10: 2, false: 3}
|
||||
expected := VariableMap{"a": 1, "10": 2, "false": 3}
|
||||
actual := makeVariableMap(input)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestStringMap(t *testing.T) {
|
||||
input := map[interface{}]interface{}{"a": 1, 10: 2, false: 3}
|
||||
expected := map[string]interface{}{"a": 1, "10": 2, "false": 3}
|
||||
actual := stringMap(input)
|
||||
func TestMergeVariableMaps(t *testing.T) {
|
||||
m1 := VariableMap{"a": 1, "b": 2}
|
||||
m2 := VariableMap{"b": 3, "c": 4}
|
||||
expected := VariableMap{"a": 1, "b": 3, "c": 4}
|
||||
actual := mergeVariableMaps(m1, m2)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
|
4
main.go
4
main.go
@ -160,9 +160,9 @@ func dataCommand(c *cli.Context) error {
|
||||
// Neuter it. This destroys it as Liquid data, but that's okay in this context.
|
||||
data := site.Variables
|
||||
for _, c := range site.Collections {
|
||||
data[c.Name] = fmt.Sprintf("<elided page data for %d items>", len(data[c.Name].([]interface{})))
|
||||
data[c.Name] = fmt.Sprintf("<elided page data for %d items>", len(data[c.Name].([]VariableMap)))
|
||||
}
|
||||
b, _ := yaml.Marshal(stringMap(page.Data()))
|
||||
b, _ := yaml.Marshal(page.Data())
|
||||
fmt.Println(string(b))
|
||||
return nil
|
||||
}
|
||||
|
36
page.go
36
page.go
@ -22,6 +22,8 @@ var (
|
||||
nonAlphanumericSequenceMatcher = regexp.MustCompile(`[^[:alnum:]]+`)
|
||||
)
|
||||
|
||||
type VariableMap map[string]interface{}
|
||||
|
||||
var permalinkStyles = map[string]string{
|
||||
"date": "/:categories/:year/:month/:day/:title.html",
|
||||
"pretty": "/:categories/:year/:month/:day/:title/",
|
||||
@ -35,7 +37,7 @@ type Page struct {
|
||||
Permalink string
|
||||
Static bool
|
||||
Published bool
|
||||
FrontMatter map[interface{}]interface{}
|
||||
FrontMatter VariableMap
|
||||
Content []byte
|
||||
}
|
||||
|
||||
@ -45,11 +47,11 @@ func (p *Page) String() string {
|
||||
}
|
||||
|
||||
// PageVariables returns metadata for use in the representation of the page as a collection item
|
||||
func (p *Page) PageVariables() map[interface{}]interface{} {
|
||||
func (p *Page) PageVariables() VariableMap {
|
||||
if p.Static {
|
||||
return mergeMaps(p.FrontMatter, p.staticFileData())
|
||||
return mergeVariableMaps(p.FrontMatter, p.staticFileData())
|
||||
}
|
||||
data := map[interface{}]interface{}{
|
||||
data := VariableMap{
|
||||
"url": p.Permalink,
|
||||
"path": p.Source(),
|
||||
// TODO content title excerpt date id categories tags next previous
|
||||
@ -68,14 +70,14 @@ func (p *Page) PageVariables() map[interface{}]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
func (p *Page) staticFileData() map[interface{}]interface{} {
|
||||
func (p *Page) staticFileData() VariableMap {
|
||||
var (
|
||||
path = "/" + p.Path
|
||||
base = filepath.Base(path)
|
||||
ext = filepath.Ext(path)
|
||||
)
|
||||
|
||||
return map[interface{}]interface{}{
|
||||
return VariableMap{
|
||||
"path": path,
|
||||
"modified_time": 0, // TODO
|
||||
"name": base,
|
||||
@ -85,17 +87,17 @@ func (p *Page) staticFileData() map[interface{}]interface{} {
|
||||
}
|
||||
|
||||
// Data returns the variable context for Liquid evaluation
|
||||
func (p *Page) Data() map[interface{}]interface{} {
|
||||
return map[interface{}]interface{}{
|
||||
func (p *Page) Data() VariableMap {
|
||||
return VariableMap{
|
||||
"page": p.PageVariables(),
|
||||
"site": site.Variables,
|
||||
}
|
||||
}
|
||||
|
||||
// ReadPage reads a Page from a file, using defaults as the default front matter.
|
||||
func ReadPage(path string, defaults map[interface{}]interface{}) (p *Page, err error) {
|
||||
func ReadPage(path string, defaults VariableMap) (p *Page, err error) {
|
||||
var (
|
||||
frontMatter map[interface{}]interface{}
|
||||
frontMatter VariableMap
|
||||
static = true
|
||||
body []byte
|
||||
)
|
||||
@ -112,14 +114,14 @@ func ReadPage(path string, defaults map[interface{}]interface{}) (p *Page, err e
|
||||
body = append(
|
||||
regexp.MustCompile(`[^\n\r]+`).ReplaceAllLiteral(source[:match[1]], []byte{}),
|
||||
source[match[1]:]...)
|
||||
frontMatter = map[interface{}]interface{}{}
|
||||
frontMatter = VariableMap{}
|
||||
err = yaml.Unmarshal(source[match[2]:match[3]], &frontMatter)
|
||||
if err != nil {
|
||||
err := &os.PathError{Op: "read frontmatter", Path: path, Err: err}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
frontMatter = mergeMaps(defaults, frontMatter)
|
||||
frontMatter = mergeVariableMaps(defaults, frontMatter)
|
||||
} else {
|
||||
frontMatter = defaults
|
||||
body = []byte{}
|
||||
@ -145,7 +147,7 @@ func ReadPage(path string, defaults map[interface{}]interface{}) (p *Page, err e
|
||||
Path: path,
|
||||
Permalink: permalink,
|
||||
Static: static,
|
||||
Published: getBool(data, "published", true),
|
||||
Published: data.Bool("published", true),
|
||||
FrontMatter: data,
|
||||
Content: body,
|
||||
}
|
||||
@ -182,7 +184,7 @@ func (p *Page) Render(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
writer := new(bytes.Buffer)
|
||||
template.Render(writer, stringMap(p.Data()))
|
||||
template.Render(writer, p.Data())
|
||||
body := writer.Bytes()
|
||||
|
||||
if isMarkdown(p.Path) {
|
||||
@ -198,7 +200,7 @@ func isMarkdown(path string) bool {
|
||||
return site.MarkdownExtensions()[strings.TrimLeft(ext, ".")]
|
||||
}
|
||||
|
||||
func permalinkTemplateVariables(path string, data map[interface{}]interface{}) map[string]string {
|
||||
func permalinkTemplateVariables(path string, data VariableMap) map[string]string {
|
||||
var (
|
||||
collectionName string
|
||||
localPath = path
|
||||
@ -206,7 +208,7 @@ func permalinkTemplateVariables(path string, data map[interface{}]interface{}) m
|
||||
root = path[:len(path)-len(ext)]
|
||||
outputExt = ext
|
||||
name = filepath.Base(root)
|
||||
title = getString(data, "title", name)
|
||||
title = data.String("title", name)
|
||||
)
|
||||
|
||||
if isMarkdown(path) {
|
||||
@ -235,7 +237,7 @@ func permalinkTemplateVariables(path string, data map[interface{}]interface{}) m
|
||||
}
|
||||
}
|
||||
|
||||
func expandPermalinkPattern(pattern string, path string, data map[interface{}]interface{}) (s string, err error) {
|
||||
func expandPermalinkPattern(pattern string, path string, data VariableMap) (s string, err error) {
|
||||
if p, found := permalinkStyles[pattern]; found {
|
||||
pattern = p
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestExpandPermalinkPattern(t *testing.T) {
|
||||
var (
|
||||
d = map[interface{}]interface{}{}
|
||||
d = VariableMap{}
|
||||
path = "/a/b/c.d"
|
||||
mdPath = "/a/b/c.md"
|
||||
)
|
||||
|
16
site.go
16
site.go
@ -16,7 +16,7 @@ type Site struct {
|
||||
Dest string
|
||||
|
||||
Collections []*Collection
|
||||
Variables map[interface{}]interface{}
|
||||
Variables VariableMap
|
||||
Paths map[string]*Page // URL path -> *Page
|
||||
|
||||
config SiteConfig
|
||||
@ -31,7 +31,7 @@ type SiteConfig struct {
|
||||
// Where things are:
|
||||
Source string
|
||||
Destination string
|
||||
Collections map[string]interface{}
|
||||
Collections map[string]VariableMap
|
||||
|
||||
// Handling Reading
|
||||
Include []string
|
||||
@ -102,14 +102,14 @@ func (s *Site) ReadConfiguration(source, dest string) error {
|
||||
}
|
||||
|
||||
func (s *Site) readConfigBytes(bytes []byte) error {
|
||||
configVariables := map[interface{}]interface{}{}
|
||||
configVariables := VariableMap{}
|
||||
if err := yaml.Unmarshal(bytes, &s.config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal(bytes, &configVariables); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Variables = mergeMaps(s.Variables, configVariables)
|
||||
s.Variables = mergeVariableMaps(s.Variables, configVariables)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ func (s *Site) Exclude(path string) bool {
|
||||
// ReadFiles scans the source directory and creates pages and collections.
|
||||
func (s *Site) ReadFiles() error {
|
||||
s.Paths = make(map[string]*Page)
|
||||
defaults := map[interface{}]interface{}{}
|
||||
defaults := VariableMap{}
|
||||
|
||||
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
@ -199,11 +199,7 @@ func (s *Site) ReadFiles() error {
|
||||
// pages to the site map, and creates a template site variable for each collection.
|
||||
func (s *Site) readCollections() error {
|
||||
for name, d := range s.config.Collections {
|
||||
data, ok := d.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
panic("expected collection value to be a map")
|
||||
}
|
||||
c := makeCollection(s, name, data)
|
||||
c := makeCollection(s, name, d)
|
||||
s.Collections = append(s.Collections, c)
|
||||
if c.Output { // TODO always read the pages; just don't build them / include them in routes
|
||||
if err := c.ReadPages(); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user