From 4a2f16f91e213b02f008405938fe289c58820e88 Mon Sep 17 00:00:00 2001 From: spf13 Date: Thu, 20 Nov 2014 12:39:09 -0500 Subject: [PATCH] refactor handlers to use types instead of structs. --- hugolib/handler_base.go | 61 +++++++++++ hugolib/handler_file.go | 31 ++++-- hugolib/{handlers.go => handler_meta.go} | 91 +++++++++------- hugolib/handler_page.go | 126 ++++++++++++++--------- hugolib/page.go | 34 ++---- hugolib/page_test.go | 1 - hugolib/site.go | 12 +-- 7 files changed, 227 insertions(+), 129 deletions(-) create mode 100644 hugolib/handler_base.go rename hugolib/{handlers.go => handler_meta.go} (54%) diff --git a/hugolib/handler_base.go b/hugolib/handler_base.go new file mode 100644 index 000000000..7f02973c5 --- /dev/null +++ b/hugolib/handler_base.go @@ -0,0 +1,61 @@ +// Copyright © 2014 Steve Francia . +// +// 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 +} diff --git a/hugolib/handler_file.go b/hugolib/handler_file.go index 39a905770..4e692ed9a 100644 --- a/hugolib/handler_file.go +++ b/hugolib/handler_file.go @@ -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) { - x := cssmin.Minify(f.Bytes()) - s.WriteDestFile(f.Path(), helpers.BytesToReader(x)) - }, +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} } diff --git a/hugolib/handlers.go b/hugolib/handler_meta.go similarity index 54% rename from hugolib/handlers.go rename to hugolib/handler_meta.go index 173cdfa5d..1f65f9a60 100644 --- a/hugolib/handlers.go +++ b/hugolib/handler_meta.go @@ -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 + } + + results <- HandledResult{err: errors.New("No handler found"), file: f} } -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) +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 Handlers() []Handler { - return handlers +func (mh *MetaHandle) Handler() Handler { + if mh.handler == nil { + mh.handler = FindHandler(mh.ext) + } + 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 +} diff --git a/hugolib/handler_page.go b/hugolib/handler_page.go index c897b6ae8..1b6dd2378 100644 --- a/hugolib/handler_page.go +++ b/hugolib/handler_page.go @@ -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) { - page, err := NewPage(f.Path()) - if err != nil { - results <- HandledResult{file: f, err: err} - } +type basicPageHandler Handle - if err := page.ReadFrom(f.Contents); err != nil { - results <- HandledResult{file: f, err: err} - } +func (b basicPageHandler) Read(f *source.File, s *Site) HandledResult { + page, err := NewPage(f.Path()) + if err != nil { + return HandledResult{file: f, err: err} + } - page.Site = &s.Info - page.Tmpl = s.Tmpl + if err := page.ReadFrom(f.Contents); err != nil { + return HandledResult{file: f, err: err} + } - 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} - } + page.Site = &s.Info + page.Tmpl = s.Tmpl - results <- HandledResult{err: err} - }, + return HandledResult{file: f, page: page, err: err} } -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} - } - - if err := page.ReadFrom(f.Contents); err != nil { - results <- 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() - if err != nil { - results <- HandledResult{err: err} - } - - results <- HandledResult{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 { + jww.FATAL.Printf("Fail to replace short code tokens in %s:\n%s", p.BaseFileName(), err.Error()) + return HandledResult{err: err} + } else { + tmpContent = tmpContentWithTokensReplaced + } + } + + p.Content = helpers.BytesToHTML(tmpContent) + p.TableOfContents = helpers.BytesToHTML(tmpTableOfContents) + + return HandledResult{err: nil} +} + +type htmlHandler struct { + basicPageHandler +} + +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} +} + +type asciidocHandler struct { + basicPageHandler +} + +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} } diff --git a/hugolib/page.go b/hugolib/page.go index 3cf9843eb..add8fdbaa 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -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()) - } else { - tmpContent = tmpContentWithTokensReplaced - } - } - - 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()) + var h Handler + if page.Markup != "" { + h = FindHandler(page.Markup) + } else { + h = FindHandler(page.File.Extension()) + } + if h != nil { + h.PageConvert(page, tpl.T()) } - // 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() diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 3af1d1971..42e12a3a4 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -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") diff --git a/hugolib/site.go b/hugolib/site.go index fc3183fa3..dd02d79f5 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -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 }