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/dchest/cssmin"
"github.com/spf13/hugo/helpers" "github.com/spf13/hugo/helpers"
"github.com/spf13/hugo/source" "github.com/spf13/hugo/source"
"github.com/spf13/hugo/tpl"
) )
func init() { func init() {
RegisterHandler(css) RegisterHandler(new(cssHandler))
} }
var css = Handle{ type basicFileHandler Handle
extensions: []string{"css"},
read: func(f *source.File, s *Site, results HandleResults) { func (h basicFileHandler) Read(f *source.File, s *Site) HandledResult {
results <- HandledResult{file: f} return HandledResult{file: f}
}, }
fileConvert: func(f *source.File, s *Site, results HandleResults) {
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()) x := cssmin.Minify(f.Bytes())
s.WriteDestFile(f.Path(), helpers.BytesToReader(x)) s.WriteDestFile(f.Path(), helpers.BytesToReader(x))
}, return HandledResult{file: f}
} }

View file

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

View file

@ -13,65 +13,89 @@
package hugolib 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() { func init() {
RegisterHandler(markdownHandler) RegisterHandler(new(markdownHandler))
RegisterHandler(htmlHandler) RegisterHandler(new(htmlHandler))
RegisterHandler(new(asciidocHandler))
} }
var markdownHandler = Handle{ type basicPageHandler Handle
extensions: []string{"mdown", "markdown", "md"},
read: func(f *source.File, s *Site, results HandleResults) { func (b basicPageHandler) Read(f *source.File, s *Site) HandledResult {
page, err := NewPage(f.Path()) page, err := NewPage(f.Path())
if err != nil { if err != nil {
results <- HandledResult{file: f, err: err} return HandledResult{file: f, err: err}
} }
if err := page.ReadFrom(f.Contents); err != nil { 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.Site = &s.Info
page.Tmpl = s.Tmpl page.Tmpl = s.Tmpl
results <- HandledResult{file: f, page: page, err: err} return HandledResult{file: f, page: page, err: err}
}, }
pageConvert: func(p *Page, s *Site, results HandleResults) {
p.ProcessShortcodes(s.Tmpl) func (b basicPageHandler) FileConvert(*source.File, *Site) HandledResult {
err := p.Convert() 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 { 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{ type htmlHandler struct {
extensions: []string{"html", "htm"}, basicPageHandler
read: func(f *source.File, s *Site, results HandleResults) {
page, err := NewPage(f.Path())
if err != nil {
results <- HandledResult{file: f, err: err}
} }
if err := page.ReadFrom(f.Contents); err != nil { func (h htmlHandler) Extensions() []string { return []string{"html", "htm"} }
results <- HandledResult{file: f, err: err} 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 type asciidocHandler struct {
page.Tmpl = s.Tmpl basicPageHandler
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}
} }
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 { func (page *Page) Convert() error {
markupType := page.guessMarkupType() var h Handler
switch markupType { if page.Markup != "" {
case "markdown", "rst": h = FindHandler(page.Markup)
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())
} else { } else {
tmpContent = tmpContentWithTokensReplaced h = FindHandler(page.File.Extension())
} }
if h != nil {
h.PageConvert(page, tpl.T())
} }
page.Content = helpers.BytesToHTML(tmpContent) //// now we know enough to create a summary of the page and count some words
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
page.setSummary() page.setSummary()
//analyze for raw stats //analyze for raw stats
page.analyzePage() page.analyzePage()

View file

@ -342,7 +342,6 @@ func TestPageWithShortCodeInSummary(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Unable to create a page with frontmatter and body content: %s", err) t.Fatalf("Unable to create a page with frontmatter and body content: %s", err)
} }
p.ProcessShortcodes(s.Tmpl)
p.Convert() p.Convert()
checkPageTitle(t, p, "Simple") 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) { func sourceReader(s *Site, files <-chan *source.File, results chan<- HandledResult, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
for file := range files { for file := range files {
h := FindHandler(file.Extension()) h := NewMetaHandler(file.Extension())
if h != nil { if h != nil {
h.Read(file, s, results) h.Read(file, s, results)
} else { } 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) { func pageConverter(s *Site, pages <-chan *Page, results HandleResults, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
for page := range pages { for page := range pages {
var h Handler var h *MetaHandle
if page.Markup != "" { if page.Markup != "" {
h = FindHandler(page.Markup) h = NewMetaHandler(page.Markup)
} else { } else {
h = FindHandler(page.File.Extension()) h = NewMetaHandler(page.File.Extension())
} }
if h != nil { if h != nil {
h.Convert(page, s, results) 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) { func fileConverter(s *Site, files <-chan *source.File, results HandleResults, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
for file := range files { for file := range files {
h := FindHandler(file.Extension()) h := NewMetaHandler(file.Extension())
if h != nil { if h != nil {
h.Convert(file, s, results) h.Convert(file, s, results)
} }
@ -470,7 +470,7 @@ func readCollator(s *Site, results <-chan HandledResult, errs chan<- error) {
errMsgs := []string{} errMsgs := []string{}
for r := range results { for r := range results {
if r.err != nil { if r.err != nil {
errMsgs = append(errMsgs, r.err.Error()) errMsgs = append(errMsgs, r.Error())
continue continue
} }