shithub: hugo

Download patch

ref: cbd9506c296dba99c59fef310a16b21be12b7b63
parent: 58f8b43feed9a487e63b61352226d934743ebafe
author: spf13 <[email protected]>
date: Thu May 1 09:19:51 EDT 2014

moving front matter parsing (and creation) to parse package

--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -24,7 +24,6 @@
 	"strings"
 	"time"
 
-	"github.com/BurntSushi/toml"
 	"github.com/spf13/cast"
 	"github.com/spf13/hugo/helpers"
 	"github.com/spf13/hugo/parser"
@@ -31,28 +30,29 @@
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
 	"github.com/theplant/blackfriday"
-	"launchpad.net/goyaml"
-	json "launchpad.net/rjson"
 )
 
 type Page struct {
-	Status          string
-	Images          []string
-	rawContent      []byte
-	Content         template.HTML
-	Summary         template.HTML
-	TableOfContents template.HTML
-	Truncated       bool
-	plain           string // TODO should be []byte
-	Params          map[string]interface{}
-	contentType     string
-	Draft           bool
-	Aliases         []string
-	Tmpl            Template
-	Markup          string
-	renderable      bool
-	layout          string
-	linkTitle       string
+	Status            string
+	Images            []string
+	rawContent        []byte
+	Content           template.HTML
+	Summary           template.HTML
+	TableOfContents   template.HTML
+	Truncated         bool
+	plain             string // TODO should be []byte
+	Params            map[string]interface{}
+	contentType       string
+	Draft             bool
+	Aliases           []string
+	Tmpl              Template
+	Markup            string
+	renderable        bool
+	layout            string
+	linkTitle         string
+	frontmatter       []byte
+	sourceFrontmatter []byte
+	sourceContent     []byte
 	PageMeta
 	File
 	Position
@@ -293,35 +293,6 @@
 	return link.String(), nil
 }
 
-func (page *Page) handleTomlMetaData(datum []byte) (interface{}, error) {
-	m := map[string]interface{}{}
-	datum = removeTomlIdentifier(datum)
-	if _, err := toml.Decode(string(datum), &m); err != nil {
-		return m, fmt.Errorf("Invalid TOML in %s \nError parsing page meta data: %s", page.FileName, err)
-	}
-	return m, nil
-}
-
-func removeTomlIdentifier(datum []byte) []byte {
-	return bytes.Replace(datum, []byte("+++"), []byte(""), -1)
-}
-
-func (page *Page) handleYamlMetaData(datum []byte) (interface{}, error) {
-	m := map[string]interface{}{}
-	if err := goyaml.Unmarshal(datum, &m); err != nil {
-		return m, fmt.Errorf("Invalid YAML in %s \nError parsing page meta data: %s", page.FileName, err)
-	}
-	return m, nil
-}
-
-func (page *Page) handleJsonMetaData(datum []byte) (interface{}, error) {
-	var f interface{}
-	if err := json.Unmarshal(datum, &f); err != nil {
-		return f, fmt.Errorf("Invalid JSON in %v \nError parsing page meta data: %s", page.FileName, err)
-	}
-	return f, nil
-}
-
 func (page *Page) update(f interface{}) error {
 	m := f.(map[string]interface{})
 
@@ -499,28 +470,6 @@
 	return nil
 }
 
-type frontmatterType struct {
-	markstart, markend []byte
-	parse              func([]byte) (interface{}, error)
-	includeMark        bool
-}
-
-const YAML_DELIM = "---"
-const TOML_DELIM = "+++"
-
-func (page *Page) detectFrontMatter(mark rune) (f *frontmatterType) {
-	switch mark {
-	case '-':
-		return &frontmatterType{[]byte(YAML_DELIM), []byte(YAML_DELIM), page.handleYamlMetaData, false}
-	case '+':
-		return &frontmatterType{[]byte(TOML_DELIM), []byte(TOML_DELIM), page.handleTomlMetaData, false}
-	case '{':
-		return &frontmatterType{[]byte{'{'}, []byte{'}'}, page.handleJsonMetaData, true}
-	default:
-		return nil
-	}
-}
-
 func (p *Page) Render(layout ...string) template.HTML {
 	curLayout := ""
 
@@ -573,30 +522,45 @@
 	return "unknown"
 }
 
+func (page *Page) detectFrontMatter() (f *parser.FrontmatterType) {
+	return parser.DetectFrontMatter(rune(page.frontmatter[0]))
+}
+
 func (page *Page) parse(reader io.Reader) error {
-	p, err := parser.ReadFrom(reader)
+	psr, err := parser.ReadFrom(reader)
 	if err != nil {
 		return err
 	}
 
-	page.renderable = p.IsRenderable()
+	page.renderable = psr.IsRenderable()
+	page.frontmatter = psr.FrontMatter()
+	meta, err := psr.Metadata()
+	if err != nil {
+		jww.ERROR.Printf("Error parsing page meta data for %s", page.FileName)
+		jww.ERROR.Println(err)
+		return err
+	}
+	if err = page.update(meta); err != nil {
+		return err
+	}
 
-	front := p.FrontMatter()
+	page.rawContent = psr.Content()
+	page.setSummary()
 
-	if len(front) != 0 {
-		fm := page.detectFrontMatter(rune(front[0]))
-		meta, err := fm.parse(front)
-		if err != nil {
-			return err
-		}
+	return nil
+}
 
-		if err = page.update(meta); err != nil {
-			return err
-		}
+func (page *Page) SetSourceContent(content []byte) {
+	page.sourceContent = content
+}
 
+func (page *Page) SetSourceMetaData(in interface{}, mark rune) (err error) {
+	by, err := parser.InterfaceToFrontMatter(in, mark)
+	if err != nil {
+		return err
 	}
-	page.rawContent = p.Content()
-	page.setSummary()
+
+	page.sourceFrontmatter = by
 
 	return nil
 }
--- /dev/null
+++ b/parser/frontmatter.go
@@ -1,0 +1,129 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package parser
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+
+	"github.com/BurntSushi/toml"
+	"launchpad.net/goyaml"
+)
+
+type FrontmatterType struct {
+	markstart, markend []byte
+	Parse              func([]byte) (interface{}, error)
+	includeMark        bool
+}
+
+func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
+	if in == nil {
+		return []byte{}, fmt.Errorf("input was nil")
+	}
+
+	b := new(bytes.Buffer)
+
+	switch mark {
+	case rune(YAML_LEAD[0]):
+		_, err := b.Write([]byte(YAML_DELIM_UNIX))
+		if err != nil {
+			return nil, err
+		}
+		by, err := goyaml.Marshal(in)
+		if err != nil {
+			return nil, err
+		}
+		b.Write(by)
+		_, err = b.Write([]byte(YAML_DELIM_UNIX))
+		if err != nil {
+			return nil, err
+		}
+		return b.Bytes(), nil
+	case rune(TOML_LEAD[0]):
+		_, err := b.Write([]byte(TOML_DELIM_UNIX))
+		if err != nil {
+			return nil, err
+		}
+
+		err = toml.NewEncoder(b).Encode(in)
+		if err != nil {
+			fmt.Println("toml encoder failed", in)
+			fmt.Println(err)
+			return nil, err
+		}
+		_, err = b.Write([]byte("\n" + TOML_DELIM_UNIX))
+		if err != nil {
+			return nil, err
+		}
+		return b.Bytes(), nil
+	case rune(JSON_LEAD[0]):
+		by, err := json.MarshalIndent(in, "", "   ")
+		if err != nil {
+			fmt.Println("json encoder failed", in)
+			fmt.Println(err)
+			return nil, err
+		}
+		b.Write(by)
+		_, err = b.Write([]byte("\n"))
+		if err != nil {
+			return nil, err
+		}
+		return b.Bytes(), nil
+	default:
+		return nil, fmt.Errorf("Unsupported Format provided")
+	}
+}
+
+func DetectFrontMatter(mark rune) (f *FrontmatterType) {
+	switch mark {
+	case '-':
+		return &FrontmatterType{[]byte(YAML_DELIM), []byte(YAML_DELIM), HandleYamlMetaData, false}
+	case '+':
+		return &FrontmatterType{[]byte(TOML_DELIM), []byte(TOML_DELIM), HandleTomlMetaData, false}
+	case '{':
+		return &FrontmatterType{[]byte{'{'}, []byte{'}'}, HandleJsonMetaData, true}
+	default:
+		return nil
+	}
+}
+
+func HandleTomlMetaData(datum []byte) (interface{}, error) {
+	m := map[string]interface{}{}
+	datum = removeTomlIdentifier(datum)
+	if _, err := toml.Decode(string(datum), &m); err != nil {
+		return m, err
+	}
+	return m, nil
+}
+
+func removeTomlIdentifier(datum []byte) []byte {
+	return bytes.Replace(datum, []byte(TOML_DELIM), []byte(""), -1)
+}
+
+func HandleYamlMetaData(datum []byte) (interface{}, error) {
+	m := map[string]interface{}{}
+	if err := goyaml.Unmarshal(datum, &m); err != nil {
+		return m, err
+	}
+	return m, nil
+}
+
+func HandleJsonMetaData(datum []byte) (interface{}, error) {
+	var f interface{}
+	if err := json.Unmarshal(datum, &f); err != nil {
+		return f, err
+	}
+	return f, nil
+}
--- a/parser/page.go
+++ b/parser/page.go
@@ -13,9 +13,11 @@
 	YAML_LEAD       = "-"
 	YAML_DELIM_UNIX = "---\n"
 	YAML_DELIM_DOS  = "---\r\n"
+	YAML_DELIM      = "---"
 	TOML_LEAD       = "+"
 	TOML_DELIM_UNIX = "+++\n"
 	TOML_DELIM_DOS  = "+++\r\n"
+	TOML_DELIM      = "+++"
 	JSON_LEAD       = "{"
 )
 
@@ -39,6 +41,7 @@
 	FrontMatter() FrontMatter
 	Content() Content
 	IsRenderable() bool
+	Metadata() (interface{}, error)
 }
 
 type page struct {
@@ -57,6 +60,19 @@
 
 func (p *page) IsRenderable() bool {
 	return p.render
+}
+
+func (p *page) Metadata() (meta interface{}, err error) {
+	frontmatter := p.FrontMatter()
+
+	if len(frontmatter) != 0 {
+		fm := DetectFrontMatter(rune(frontmatter[0]))
+		meta, err = fm.Parse(frontmatter)
+		if err != nil {
+			return
+		}
+	}
+	return
 }
 
 // ReadFrom reads the content from an io.Reader and constructs a page.