1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-26 22:24:39 +01:00

remove page.RenderContext

This commit is contained in:
Oliver Steele 2017-07-10 13:23:51 -04:00
parent c6f33c91c3
commit 908fc1d897
19 changed files with 91 additions and 95 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/pages"
"github.com/osteele/gojekyll/pipelines"
"github.com/osteele/gojekyll/templates"
)
@ -21,6 +22,7 @@ type Collection struct {
// Site is the interface a site provides to collections it contains.
type Site interface {
Config() *config.Config
RenderingPipeline() pipelines.PipelineInterface
OutputExt(pathname string) string
}
@ -65,9 +67,9 @@ func (c *Collection) Pages() []pages.Page {
}
// SetPageContent sets up the collection's pages' "content".
func (c *Collection) SetPageContent(ctx pages.RenderingContext) error {
func (c *Collection) SetPageContent() error {
for _, p := range c.Pages() {
_, err := p.Content(ctx)
_, err := p.Content()
if err != nil {
return err
}

View File

@ -4,14 +4,15 @@ import (
"testing"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/pipelines"
"github.com/stretchr/testify/require"
)
type siteMock struct{ c config.Config }
func (c siteMock) Config() *config.Config { return &c.c }
func (c siteMock) OutputExt(s string) string { return "" }
func (c siteMock) Site() interface{} { return c }
func (c siteMock) Config() *config.Config { return &c.c }
func (c siteMock) OutputExt(s string) string { return "" }
func (c siteMock) RenderingPipeline() pipelines.PipelineInterface { panic("unimplemented") }
func TestNewCollection(t *testing.T) {
site := siteMock{config.Default()}

View File

@ -69,7 +69,7 @@ func (c *Collection) readFile(abs string, rel string, fm map[string]interface{})
default:
strategy.addDate(rel, fm)
}
f, err := pages.NewFile(abs, c, filepath.ToSlash(rel), fm)
f, err := pages.NewFile(c.site, abs, filepath.ToSlash(rel), fm)
switch {
case err != nil:
return err

View File

@ -10,8 +10,8 @@ import (
)
var (
frontMatterMatcher = regexp.MustCompile(`(?s)^---\n(.+?\n)---\n`)
emptyFontMatterMatcher = regexp.MustCompile(`(?s)^---\n+---\n`)
frontMatterMatcher = regexp.MustCompile(`(?s)^---\n(.+?\n)---\n+`)
emptyFontMatterMatcher = regexp.MustCompile(`(?s)^---\n+---\n+`)
)
// Read reads the frontmatter from a document. It modifies srcPtr to point to the

View File

@ -43,24 +43,13 @@ func (p *page) ToLiquid() interface{} {
root = utils.TrimExt(p.relpath)
base = filepath.Base(root)
content = p.raw
excerpt string
)
if p.content != nil {
content = *p.content
}
content = bytes.TrimSpace(content)
if ei, ok := p.frontMatter["excerpt"]; ok {
excerpt = fmt.Sprint(ei)
} else {
pos := bytes.Index(content, []byte(p.container.Config().ExcerptSeparator))
if pos < 0 {
pos = len(content)
}
excerpt = string(content[:pos])
}
data := map[string]interface{}{
"content": string(content),
"excerpt": excerpt,
"excerpt": p.excerpt(),
"path": relpath,
"url": p.Permalink(),
// TODO output
@ -101,6 +90,21 @@ func (p *page) ToLiquid() interface{} {
return data
}
func (p *page) excerpt() string {
if ei, ok := p.frontMatter["excerpt"]; ok {
return fmt.Sprint(ei)
}
content := p.raw
if p.content != nil {
content = *p.content
}
pos := bytes.Index(content, []byte(p.site.Config().ExcerptSeparator))
if pos >= 0 {
return string(content[:pos])
}
return string(content)
}
// MarshalYAML is part of the yaml.Marshaler interface
// The variables subcommand uses this.
func (f *file) MarshalYAML() (interface{}, error) {

View File

@ -10,7 +10,7 @@ import (
func TestPage_ToLiquid(t *testing.T) {
cfg := config.Default()
page, err := NewFile("testdata/excerpt.md", containerFake{cfg, ""}, "excerpt.md", map[string]interface{}{})
page, err := NewFile(siteFake{t, cfg}, "testdata/excerpt.md", "excerpt.md", map[string]interface{}{})
require.NoError(t, err)
drop := page.(liquid.Drop).ToLiquid()
excerpt := drop.(map[string]interface{})["excerpt"]

View File

@ -3,7 +3,6 @@ package pages
import (
"fmt"
"os"
"reflect"
"time"
"github.com/osteele/gojekyll/frontmatter"
@ -12,7 +11,7 @@ import (
// file is embedded in StaticFile and page
type file struct {
container Container
site Site
filename string // target os filepath
relpath string // slash-separated path relative to site or container source
outputExt string
@ -22,7 +21,7 @@ type file struct {
}
func (f *file) String() string {
return fmt.Sprintf("%s{Path=%v, Permalink=%v}", reflect.TypeOf(f).Name(), f.relpath, f.permalink)
return fmt.Sprintf("%T{Path=%v, Permalink=%v}", f.relpath, f.permalink)
}
func (f *file) OutputExt() string { return f.outputExt }
@ -31,8 +30,10 @@ func (f *file) Permalink() string { return f.permalink }
func (f *file) Published() bool { return templates.VariableMap(f.frontMatter).Bool("published", true) }
func (f *file) SourcePath() string { return f.relpath }
// NewFile creates a Post or StaticFile.
func NewFile(filename string, c Container, relpath string, defaults map[string]interface{}) (Document, error) {
// NewFile creates a Page or StaticFile.
//
// filename is the absolute filename. relpath is the path relative to the site or collection directory.
func NewFile(s Site, filename string, relpath string, defaults map[string]interface{}) (Document, error) {
fm, err := frontmatter.FileHasFrontMatter(filename)
if err != nil {
return nil, err
@ -43,12 +44,12 @@ func NewFile(filename string, c Container, relpath string, defaults map[string]i
}
fields := file{
container: c,
site: s,
filename: filename,
frontMatter: defaults,
fileModTime: info.ModTime(),
relpath: relpath,
outputExt: c.OutputExt(relpath),
outputExt: s.OutputExt(relpath),
}
if fm {
return makePage(filename, fields)

View File

@ -1,25 +1,39 @@
package pages
import (
"io"
"path/filepath"
"testing"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/pipelines"
"github.com/stretchr/testify/require"
)
type containerFake struct {
cfg config.Config
prefix string
type siteFake struct {
t *testing.T
cfg config.Config
}
func (c containerFake) Config() *config.Config { return &c.cfg }
func (c containerFake) PathPrefix() string { return c.prefix }
func (c containerFake) OutputExt(p string) string { return filepath.Ext(p) }
func (s siteFake) Config() *config.Config { return &s.cfg }
func (s siteFake) RenderingPipeline() pipelines.PipelineInterface { return &pipelineFake{s.t} }
func (s siteFake) OutputExt(p string) string { return filepath.Ext(p) }
func TestPageCategories(t *testing.T) {
c := containerFake{config.Default(), ""}
type pipelineFake struct{ t *testing.T }
func (p pipelineFake) OutputExt(string) string { return ".html" }
func (p pipelineFake) ApplyLayout(layout string, src []byte, vars map[string]interface{}) ([]byte, error) {
require.Equal(p.t, "layout1", layout)
return nil, nil
}
func (p pipelineFake) Render(w io.Writer, src []byte, filename string, lineNo int, vars map[string]interface{}) ([]byte, error) {
require.Equal(p.t, "testdata/page_with_layout.md", filename)
return nil, nil
}
func TestFile_Categories(t *testing.T) {
s := siteFake{t, config.Default()}
fm := map[string]interface{}{"categories": "b a"}
f := file{container: c, frontMatter: fm}
f := file{site: s, frontMatter: fm}
require.Equal(t, []string{"a", "b"}, f.Categories())
}

View File

@ -17,23 +17,15 @@ type Document interface {
// Output
Published() bool
Static() bool
Write(io.Writer, RenderingContext) error
Write(io.Writer) error
Categories() []string
Tags() []string
}
// RenderingContext provides context information for rendering.
type RenderingContext interface {
RenderingPipeline() pipelines.PipelineInterface
// Site is the value of the "site" template variable.
Site() interface{} // used as a drop in the rendering context
}
// Container is the document container.
// It's either the Site or Collection that immediately contains the document.
type Container interface {
// Site is the interface that the site provides to a page.
type Site interface {
Config() *config.Config
RenderingPipeline() pipelines.PipelineInterface
OutputExt(pathname string) string
PathPrefix() string // PathPrefix is the relative prefix, "" for the site and "_coll/" for a collection
}

View File

@ -17,7 +17,7 @@ type Page interface {
Document
// Content asks a page to compute its content.
// This has the side effect of causing the content to subsequently appear in the drop.
Content(rc RenderingContext) ([]byte, error)
Content() ([]byte, error)
SetContent(content []byte)
FrontMatter() map[string]interface{}
// PostDate returns the date computed from the filename or frontmatter.
@ -59,10 +59,10 @@ func makePage(filename string, f file) (*page, error) {
}
// TemplateContext returns the local variables for template evaluation
func (p *page) TemplateContext(rc RenderingContext) map[string]interface{} {
func (p *page) TemplateContext() map[string]interface{} {
return map[string]interface{}{
"page": p,
"site": rc.Site(),
"site": p.site,
}
}
@ -87,15 +87,15 @@ func (p *page) PostDate() time.Time {
}
// Write applies Liquid and Markdown, as appropriate.
func (p *page) Write(w io.Writer, rc RenderingContext) error {
content, err := p.Content(rc)
func (p *page) Write(w io.Writer) error {
content, err := p.Content()
if err != nil {
return err
}
layout, ok := p.frontMatter["layout"].(string)
if ok && layout != "" {
rp := rc.RenderingPipeline()
content, err = rp.ApplyLayout(layout, content, p.TemplateContext(rc))
rp := p.site.RenderingPipeline()
content, err = rp.ApplyLayout(layout, content, p.TemplateContext())
if err != nil {
return err
}
@ -105,13 +105,13 @@ func (p *page) Write(w io.Writer, rc RenderingContext) error {
}
// Content computes the page content.
func (p *page) Content(rc RenderingContext) ([]byte, error) {
func (p *page) Content() ([]byte, error) {
if p.content != nil {
return *p.content, nil
}
rp := rc.RenderingPipeline()
pipe := p.site.RenderingPipeline()
buf := new(bytes.Buffer)
b, err := rp.Render(buf, p.raw, p.filename, p.firstLine, p.TemplateContext(rc))
b, err := pipe.Render(buf, p.raw, p.filename, p.firstLine, p.TemplateContext())
if err != nil {
return nil, err
}

View File

@ -2,38 +2,22 @@ package pages
import (
"bytes"
"io"
"testing"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/pipelines"
"github.com/stretchr/testify/require"
)
type renderingContextFake struct {
t *testing.T
cfg config.Config
}
func (c renderingContextFake) RenderingPipeline() pipelines.PipelineInterface { return c }
func (c renderingContextFake) Config() config.Config { return c.cfg }
func (c renderingContextFake) PathPrefix() string { return "." }
func (c renderingContextFake) OutputExt(string) string { return ".html" }
func (c renderingContextFake) Site() interface{} { return nil }
func (c renderingContextFake) ApplyLayout(layout string, src []byte, vars map[string]interface{}) ([]byte, error) {
require.Equal(c.t, "layout1", layout)
return nil, nil
}
func (c renderingContextFake) Render(w io.Writer, src []byte, filename string, lineNo int, vars map[string]interface{}) ([]byte, error) {
require.Equal(c.t, "testdata/page_with_layout.md", filename)
return nil, nil
}
// func (c pipelineFake) RenderingPipeline() pipelines.PipelineInterface { return c }
// func (c pipelineFake) Config() config.Config { return c.cfg }
// func (c pipelineFake) PathPrefix() string { return "." }
// func (c pipelineFake) Site() interface{} { return nil }
func TestPageWrite(t *testing.T) {
cfg := config.Default()
p, err := NewFile("testdata/page_with_layout.md", containerFake{cfg, ""}, "page_with_layout.md", map[string]interface{}{})
p, err := NewFile(siteFake{t, cfg}, "testdata/page_with_layout.md", "page_with_layout.md", map[string]interface{}{})
require.NoError(t, err)
require.NotNil(t, p)
buf := new(bytes.Buffer)
require.NoError(t, p.Write(buf, renderingContextFake{t, cfg}))
require.NoError(t, p.Write(buf))
}

View File

@ -41,7 +41,7 @@ var templateVariableMatcher = regexp.MustCompile(`:\w+\b`)
// See https://jekyllrb.com/docs/permalinks/#template-variables
func (f *file) permalinkVariables() map[string]string {
var (
relpath = strings.TrimPrefix(f.relpath, f.container.PathPrefix())
relpath = f.relpath
root = utils.TrimExt(relpath)
name = filepath.Base(root)
fm = f.frontMatter

View File

@ -30,13 +30,13 @@ var tests = []pathTest{
}
var collectionTests = []pathTest{
{"_c/a/b/c.d", "/prefix/:collection/post", "/prefix/c/post"},
{"_c/a/b/c.d", "/prefix:path/post", "/prefix/a/b/c/post"},
{"/a/b/c.d", "/prefix/:collection/post", "/prefix/c/post"},
{"/a/b/c.d", "/prefix:path/post", "/prefix/a/b/c/post"},
}
func TestExpandPermalinkPattern(t *testing.T) {
var (
c = containerFake{config.Default(), ""}
s = siteFake{t, config.Default()}
d = map[string]interface{}{
"categories": "b a",
}
@ -49,7 +49,7 @@ func TestExpandPermalinkPattern(t *testing.T) {
case ".md", ".markdown":
ext = ".html"
}
p := file{container: c, relpath: path, frontMatter: fm, outputExt: ext}
p := file{site: s, relpath: path, frontMatter: fm, outputExt: ext}
t0, err := time.Parse(time.RFC3339, "2006-02-03T15:04:05Z")
require.NoError(t, err)
p.fileModTime = t0
@ -68,7 +68,7 @@ func TestExpandPermalinkPattern(t *testing.T) {
runTests(tests)
c = containerFake{config.Default(), "_c/"}
s = siteFake{t, config.Default()}
d["collection"] = "c"
runTests(collectionTests)

View File

@ -13,8 +13,7 @@ type StaticFile struct {
// Static is in the File interface.
func (p *StaticFile) Static() bool { return true }
// Write returns a bool indicating that the page is a static page.
func (p *StaticFile) Write(w io.Writer, _ RenderingContext) error {
func (p *StaticFile) Write(w io.Writer) error {
in, err := os.Open(p.filename)
if err != nil {
return err

View File

@ -5,7 +5,6 @@ import (
"html"
"io"
"github.com/osteele/gojekyll/pages"
"github.com/osteele/liquid"
"github.com/osteele/liquid/render"
)
@ -79,7 +78,7 @@ func (d *feedDoc) Content() []byte {
return b
}
func (d *feedDoc) Write(w io.Writer, c pages.RenderingContext) error {
func (d *feedDoc) Write(w io.Writer) error {
_, err := w.Write(d.Content())
return err
}

View File

@ -76,7 +76,7 @@ func (d *redirectionDoc) Content() []byte {
return buf.Bytes()
}
func (d *redirectionDoc) Write(w io.Writer, c pages.RenderingContext) error {
func (d *redirectionDoc) Write(w io.Writer) error {
return redirectTemplate.Execute(w, d)
}

View File

@ -51,7 +51,7 @@ func (s *Site) initializeDrop() {
func (s *Site) setPageContent() error {
for _, c := range s.Collections {
if err := c.SetPageContent(s); err != nil {
if err := c.SetPageContent(); err != nil {
return err
}
}

View File

@ -74,7 +74,7 @@ func (s *Site) readFiles() error {
return nil
}
defaultFrontmatter := s.config.GetFrontMatterDefaults("", relname)
p, err := pages.NewFile(filename, s, filepath.ToSlash(relname), defaultFrontmatter)
p, err := pages.NewFile(s, filename, filepath.ToSlash(relname), defaultFrontmatter)
if err != nil {
return utils.PathError(err, "read", filename)
}

View File

@ -31,7 +31,7 @@ func (s *Site) WriteDocument(w io.Writer, p pages.Document) error {
return err
}
buf := new(bytes.Buffer)
if err := p.Write(buf, s); err != nil {
if err := p.Write(buf); err != nil {
return err
}
c := buf.Bytes()