refactor handlers to use types instead of structs.

This commit is contained in:
spf13 2014-11-20 12:39:09 -05:00
parent 73f203ad86
commit 4a2f16f91e
7 changed files with 227 additions and 129 deletions

61
hugolib/handler_base.go Normal file
View file

@ -0,0 +1,61 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// 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 hugolib
import (
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/tpl"
)
type Handler interface {
FileConvert(*source.File, *Site) HandledResult
PageConvert(*Page, tpl.Template) HandledResult
Read(*source.File, *Site) HandledResult
Extensions() []string
}
type Handle struct {
extensions []string
}
func (h Handle) Extensions() []string {
return h.extensions
}
type HandledResult struct {
page *Page
file *source.File
err error
}
// HandledResult is an error
func (h HandledResult) Error() string {
if h.err != nil {
if h.page != nil {
return "Error:" + h.err.Error() + " for " + h.page.File.LogicalName()
}
if h.file != nil {
return "Error:" + h.err.Error() + " for " + h.file.LogicalName()
}
}
return h.err.Error()
}
func (h HandledResult) String() string {
return h.Error()
}
func (hr HandledResult) Page() *Page {
return hr.page
}

View file

@ -17,19 +17,30 @@ import (
"github.com/dchest/cssmin"
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/tpl"
)
func init() {
RegisterHandler(css)
RegisterHandler(new(cssHandler))
}
var css = Handle{
extensions: []string{"css"},
read: func(f *source.File, s *Site, results HandleResults) {
results <- HandledResult{file: f}
},
fileConvert: func(f *source.File, s *Site, results HandleResults) {
type basicFileHandler Handle
func (h basicFileHandler) Read(f *source.File, s *Site) HandledResult {
return HandledResult{file: f}
}
func (h basicFileHandler) PageConvert(*Page, tpl.Template) HandledResult {
return HandledResult{}
}
type cssHandler struct {
basicFileHandler
}
func (h cssHandler) Extensions() []string { return []string{"css"} }
func (h cssHandler) FileConvert(f *source.File, s *Site) HandledResult {
x := cssmin.Minify(f.Bytes())
s.WriteDestFile(f.Path(), helpers.BytesToReader(x))
},
return HandledResult{file: f}
}

View file

@ -13,63 +13,70 @@
package hugolib
import "github.com/spf13/hugo/source"
import (
"errors"
type Handler interface {
"github.com/spf13/hugo/source"
)
var handlers []Handler
type MetaHandler interface {
// Read the Files in and register
Read(*source.File, *Site, HandleResults)
// Convert Pages to prepare for templatizing
// Convert Files to their final destination
// Generic Convert Function with coordination
Convert(interface{}, *Site, HandleResults)
// Extensions to register the handle for
Extensions() []string
}
type HandledResult struct {
page *Page
file *source.File
err error
Handle() Handler
}
type HandleResults chan<- HandledResult
type ReadFunc func(*source.File, *Site, HandleResults)
type PageConvertFunc func(*Page, *Site, HandleResults)
type FileConvertFunc ReadFunc
type Handle struct {
extensions []string
read ReadFunc
pageConvert PageConvertFunc
fileConvert FileConvertFunc
func NewMetaHandler(in string) *MetaHandle {
x := &MetaHandle{ext: in}
x.Handler()
return x
}
var handlers []Handler
func (h Handle) Extensions() []string {
return h.extensions
type MetaHandle struct {
handler Handler
ext string
}
func (h Handle) Read(f *source.File, s *Site, results HandleResults) {
h.read(f, s, results)
func (mh *MetaHandle) Read(f *source.File, s *Site, results HandleResults) {
if h := mh.Handler(); h != nil {
results <- h.Read(f, s)
return
}
func (h Handle) Convert(i interface{}, s *Site, results HandleResults) {
if h.pageConvert != nil {
h.pageConvert(i.(*Page), s, results)
} else {
h.fileConvert(i.(*source.File), s, results)
results <- HandledResult{err: errors.New("No handler found"), file: f}
}
func (mh *MetaHandle) Convert(i interface{}, s *Site, results HandleResults) {
h := mh.Handler()
if f, ok := i.(*source.File); ok {
results <- h.FileConvert(f, s)
return
}
if p, ok := i.(*Page); ok {
if p == nil {
results <- HandledResult{err: errors.New("file resulted in a nil page")}
return
}
results <- h.PageConvert(p, s.Tmpl)
p.setSummary()
p.analyzePage()
}
}
func RegisterHandler(h Handler) {
handlers = append(handlers, h)
func (mh *MetaHandle) Handler() Handler {
if mh.handler == nil {
mh.handler = FindHandler(mh.ext)
}
func Handlers() []Handler {
return handlers
return mh.handler
}
func FindHandler(ext string) Handler {
@ -89,3 +96,11 @@ func HandlerMatch(h Handler, ext string) bool {
}
return false
}
func RegisterHandler(h Handler) {
handlers = append(handlers, h)
}
func Handlers() []Handler {
return handlers
}

View file

@ -13,65 +13,89 @@
package hugolib
import "github.com/spf13/hugo/source"
import (
"github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/tpl"
jww "github.com/spf13/jwalterweatherman"
)
func init() {
RegisterHandler(markdownHandler)
RegisterHandler(htmlHandler)
RegisterHandler(new(markdownHandler))
RegisterHandler(new(htmlHandler))
RegisterHandler(new(asciidocHandler))
}
var markdownHandler = Handle{
extensions: []string{"mdown", "markdown", "md"},
read: func(f *source.File, s *Site, results HandleResults) {
type basicPageHandler Handle
func (b basicPageHandler) Read(f *source.File, s *Site) HandledResult {
page, err := NewPage(f.Path())
if err != nil {
results <- HandledResult{file: f, err: err}
return HandledResult{file: f, err: err}
}
if err := page.ReadFrom(f.Contents); err != nil {
results <- HandledResult{file: f, err: err}
return HandledResult{file: f, err: err}
}
page.Site = &s.Info
page.Tmpl = s.Tmpl
results <- HandledResult{file: f, page: page, err: err}
},
pageConvert: func(p *Page, s *Site, results HandleResults) {
p.ProcessShortcodes(s.Tmpl)
err := p.Convert()
return HandledResult{file: f, page: page, err: err}
}
func (b basicPageHandler) FileConvert(*source.File, *Site) HandledResult {
return HandledResult{}
}
type markdownHandler struct {
basicPageHandler
}
func (h markdownHandler) Extensions() []string { return []string{"mdown", "markdown", "md"} }
func (h markdownHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
p.ProcessShortcodes(t)
tmpContent, tmpTableOfContents := helpers.ExtractTOC(p.renderContent(helpers.RemoveSummaryDivider(p.rawContent)))
if len(p.contentShortCodes) > 0 {
tmpContentWithTokensReplaced, err := replaceShortcodeTokens(tmpContent, shortcodePlaceholderPrefix, -1, true, p.contentShortCodes)
if err != nil {
results <- HandledResult{err: err}
jww.FATAL.Printf("Fail to replace short code tokens in %s:\n%s", p.BaseFileName(), err.Error())
return HandledResult{err: err}
} else {
tmpContent = tmpContentWithTokensReplaced
}
}
results <- HandledResult{err: err}
},
p.Content = helpers.BytesToHTML(tmpContent)
p.TableOfContents = helpers.BytesToHTML(tmpTableOfContents)
return HandledResult{err: nil}
}
var htmlHandler = Handle{
extensions: []string{"html", "htm"},
read: func(f *source.File, s *Site, results HandleResults) {
page, err := NewPage(f.Path())
if err != nil {
results <- HandledResult{file: f, err: err}
type htmlHandler struct {
basicPageHandler
}
if err := page.ReadFrom(f.Contents); err != nil {
results <- HandledResult{file: f, err: err}
func (h htmlHandler) Extensions() []string { return []string{"html", "htm"} }
func (h htmlHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
p.ProcessShortcodes(t)
p.Content = helpers.BytesToHTML(p.rawContent)
return HandledResult{err: nil}
}
page.Site = &s.Info
page.Tmpl = s.Tmpl
results <- HandledResult{file: f, page: page, err: err}
},
pageConvert: func(p *Page, s *Site, results HandleResults) {
p.ProcessShortcodes(s.Tmpl)
err := p.Convert()
if err != nil {
results <- HandledResult{err: err}
type asciidocHandler struct {
basicPageHandler
}
results <- HandledResult{err: err}
},
func (h asciidocHandler) Extensions() []string { return []string{"asciidoc", "ad"} }
func (h asciidocHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
p.ProcessShortcodes(t)
// TODO(spf13) Add Ascii Doc Logic here
//err := p.Convert()
return HandledResult{page: p, err: nil}
}

View file

@ -640,32 +640,20 @@ func (p *Page) ProcessShortcodes(t tpl.Template) {
}
// TODO(spf13): Remove this entirely
// Here for backwards compatibility & testing. Only works in isolation
func (page *Page) Convert() error {
markupType := page.guessMarkupType()
switch markupType {
case "markdown", "rst":
tmpContent, tmpTableOfContents := helpers.ExtractTOC(page.renderContent(helpers.RemoveSummaryDivider(page.rawContent)))
if len(page.contentShortCodes) > 0 {
tmpContentWithTokensReplaced, err := replaceShortcodeTokens(tmpContent, shortcodePlaceholderPrefix, -1, true, page.contentShortCodes)
if err != nil {
jww.FATAL.Printf("Fail to replace short code tokens in %s:\n%s", page.BaseFileName(), err.Error())
var h Handler
if page.Markup != "" {
h = FindHandler(page.Markup)
} else {
tmpContent = tmpContentWithTokensReplaced
h = FindHandler(page.File.Extension())
}
if h != nil {
h.PageConvert(page, tpl.T())
}
page.Content = helpers.BytesToHTML(tmpContent)
page.TableOfContents = helpers.BytesToHTML(tmpTableOfContents)
case "html":
page.Content = helpers.BytesToHTML(page.rawContent)
default:
return fmt.Errorf("Error converting unsupported file type '%s' for page '%s'", markupType, page.Source.Path())
}
// now we know enough to create a summary of the page and count some words
//// now we know enough to create a summary of the page and count some words
page.setSummary()
//analyze for raw stats
page.analyzePage()

View file

@ -342,7 +342,6 @@ func TestPageWithShortCodeInSummary(t *testing.T) {
if err != nil {
t.Fatalf("Unable to create a page with frontmatter and body content: %s", err)
}
p.ProcessShortcodes(s.Tmpl)
p.Convert()
checkPageTitle(t, p, "Simple")

View file

@ -417,7 +417,7 @@ func (s *Site) CreatePages() error {
func sourceReader(s *Site, files <-chan *source.File, results chan<- HandledResult, wg *sync.WaitGroup) {
defer wg.Done()
for file := range files {
h := FindHandler(file.Extension())
h := NewMetaHandler(file.Extension())
if h != nil {
h.Read(file, s, results)
} else {
@ -429,11 +429,11 @@ func sourceReader(s *Site, files <-chan *source.File, results chan<- HandledResu
func pageConverter(s *Site, pages <-chan *Page, results HandleResults, wg *sync.WaitGroup) {
defer wg.Done()
for page := range pages {
var h Handler
var h *MetaHandle
if page.Markup != "" {
h = FindHandler(page.Markup)
h = NewMetaHandler(page.Markup)
} else {
h = FindHandler(page.File.Extension())
h = NewMetaHandler(page.File.Extension())
}
if h != nil {
h.Convert(page, s, results)
@ -444,7 +444,7 @@ func pageConverter(s *Site, pages <-chan *Page, results HandleResults, wg *sync.
func fileConverter(s *Site, files <-chan *source.File, results HandleResults, wg *sync.WaitGroup) {
defer wg.Done()
for file := range files {
h := FindHandler(file.Extension())
h := NewMetaHandler(file.Extension())
if h != nil {
h.Convert(file, s, results)
}
@ -470,7 +470,7 @@ func readCollator(s *Site, results <-chan HandledResult, errs chan<- error) {
errMsgs := []string{}
for r := range results {
if r.err != nil {
errMsgs = append(errMsgs, r.err.Error())
errMsgs = append(errMsgs, r.Error())
continue
}