1
0
mirror of https://github.com/danog/gojekyll.git synced 2025-01-23 00:21:15 +01:00
This commit is contained in:
Oliver Steele 2017-06-30 23:10:58 -04:00
parent f86956b5c8
commit 887820d7bd
7 changed files with 62 additions and 44 deletions

View File

@ -118,7 +118,7 @@ Gojekyll uses these libraries:
| [gopkg.in/alecthomas/kingpin.v2](https://github.com/alecthomas/kingpin) | Alec Thomas | command line and flag parser |
| [gopkg.in/yaml.v2](https://github.com/go-yaml) | Canonical | YAML support |
In addition to being totally and obviously inspired by the Jekyll Ruby implementation, Jekyll's solid documentation was indispensible. Many of the filter test cases are taken directly from the Jekyll documentation, and the [Jekyll docs](https://jekyllrb.com/docs/home/) were always open in at least one tab.
In addition to being totally and obviously inspired by the Jekyll, Jekyll's solid documentation was indispensible. Many of the filter test cases are taken directly from the Jekyll documentation, and the [Jekyll docs](https://jekyllrb.com/docs/home/) were always open in at least one tab.
The gopher image in the test directory is from [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Gophercolor.jpg). It is used under the [Creative Commons Attribution-Share Alike 3.0 Unported license](https://creativecommons.org/licenses/by-sa/3.0/deed.en).

View File

@ -134,6 +134,8 @@ func (c *Collection) ReadPages(sitePath string, frontMatterDefaults func(string,
return filepath.Walk(filepath.Join(sitePath, c.PathPrefix()), walkFn)
}
// DateFromFilename returns the date for a filename that uses Jekyll post convention.
// It also returns a bool indicating whether a date was found.
func DateFromFilename(s string) (time.Time, bool) {
layout := "2006-01-02-"
t, err := time.Parse(layout, filepath.Base(s + layout)[:len(layout)])

View File

@ -18,11 +18,12 @@ import (
"github.com/russross/blackfriday"
)
func AddJekyllFilters(engine liquid.Engine, config config.Config) {
// AddJekyllFilters adds the Jekyll filters to the Liquid engine.
func AddJekyllFilters(e liquid.Engine, c config.Config) {
// array filters
engine.DefineFilter("array_to_sentence_string", arrayToSentenceStringFilter)
e.DefineFilter("array_to_sentence_string", arrayToSentenceStringFilter)
// TODO neither Liquid nor Jekyll docs this, but it appears to be present
engine.DefineFilter("filter", func(values []map[string]interface{}, key string) []interface{} {
e.DefineFilter("filter", func(values []map[string]interface{}, key string) []interface{} {
out := []interface{}{}
for _, value := range values {
if _, ok := value[key]; ok {
@ -31,62 +32,62 @@ func AddJekyllFilters(engine liquid.Engine, config config.Config) {
}
return out
})
engine.DefineFilter("group_by", groupByFilter)
engine.DefineFilter("group_by_exp", unimplementedFilter("group_by_exp"))
engine.DefineFilter("sample", func(array []interface{}) interface{} {
e.DefineFilter("group_by", groupByFilter)
e.DefineFilter("group_by_exp", unimplementedFilter("group_by_exp"))
e.DefineFilter("sample", func(array []interface{}) interface{} {
if len(array) == 0 {
return nil
}
return array[rand.Intn(len(array))]
})
// sort overrides the Liquid filter with one that takes parameters
engine.DefineFilter("sort", sortFilter)
engine.DefineFilter("where", whereFilter) // TODO test case
engine.DefineFilter("where_exp", whereExpFilter)
engine.DefineFilter("xml_escape", xml.Marshal)
e.DefineFilter("sort", sortFilter)
e.DefineFilter("where", whereFilter) // TODO test case
e.DefineFilter("where_exp", whereExpFilter)
e.DefineFilter("xml_escape", xml.Marshal)
engine.DefineFilter("push", func(array []interface{}, item interface{}) interface{} {
e.DefineFilter("push", func(array []interface{}, item interface{}) interface{} {
return append(array, generics.MustConvertItem(item, array))
})
engine.DefineFilter("pop", unimplementedFilter("pop"))
engine.DefineFilter("shift", unimplementedFilter("shift"))
engine.DefineFilter("unshift", func(array []interface{}, item interface{}) interface{} {
e.DefineFilter("pop", unimplementedFilter("pop"))
e.DefineFilter("shift", unimplementedFilter("shift"))
e.DefineFilter("unshift", func(array []interface{}, item interface{}) interface{} {
return append([]interface{}{generics.MustConvertItem(item, array)}, array...)
})
// dates
engine.DefineFilter("date_to_rfc822", func(date time.Time) string {
e.DefineFilter("date_to_rfc822", func(date time.Time) string {
return date.Format(time.RFC822)
// Out: Mon, 07 Nov 2008 13:07:54 -0800
})
engine.DefineFilter("date_to_string", func(date time.Time) string {
e.DefineFilter("date_to_string", func(date time.Time) string {
return date.Format("02 Jan 2006")
// Out: 07 Nov 2008
})
engine.DefineFilter("date_to_long_string", func(date time.Time) string {
e.DefineFilter("date_to_long_string", func(date time.Time) string {
return date.Format("02 January 2006")
// Out: 07 November 2008
})
engine.DefineFilter("date_to_xmlschema", func(date time.Time) string {
e.DefineFilter("date_to_xmlschema", func(date time.Time) string {
return date.Format("2006-01-02T15:04:05-07:00")
// Out: 2008-11-07T13:07:54-08:00
})
// strings
engine.DefineFilter("absolute_url", func(s string) string {
return config.AbsoluteURL + config.BaseURL + s
e.DefineFilter("absolute_url", func(s string) string {
return c.AbsoluteURL + c.BaseURL + s
})
engine.DefineFilter("relative_url", func(s string) string {
return config.BaseURL + s
e.DefineFilter("relative_url", func(s string) string {
return c.BaseURL + s
})
engine.DefineFilter("jsonify", json.Marshal)
engine.DefineFilter("markdownify", blackfriday.MarkdownCommon)
engine.DefineFilter("normalize_whitespace", func(s string) string {
e.DefineFilter("jsonify", json.Marshal)
e.DefineFilter("markdownify", blackfriday.MarkdownCommon)
e.DefineFilter("normalize_whitespace", func(s string) string {
// s = strings.Replace(s, "n", "N", -1)
wsPattern := regexp.MustCompile(`(?s:[\s\n]+)`)
return wsPattern.ReplaceAllString(s, " ")
})
engine.DefineFilter("slugify", func(s, mode string) string {
e.DefineFilter("slugify", func(s, mode string) string {
if mode == "" {
mode = "default"
}
@ -100,8 +101,8 @@ func AddJekyllFilters(engine liquid.Engine, config config.Config) {
}
return strings.ToLower(s)
})
engine.DefineFilter("to_integer", func(n int) int { return n })
engine.DefineFilter("number_of_words", func(s string) int {
e.DefineFilter("to_integer", func(n int) int { return n })
e.DefineFilter("number_of_words", func(s string) int {
wordPattern := regexp.MustCompile(`\w+`) // TODO what's the Jekyll spec for a word?
m := wordPattern.FindAllStringIndex(s, -1)
if m == nil {
@ -119,11 +120,11 @@ func AddJekyllFilters(engine liquid.Engine, config config.Config) {
// }
// return strings.Join(parts, "?")
// })
engine.DefineFilter("cgi_escape", unimplementedFilter("cgi_escape"))
engine.DefineFilter("uri_escape", unimplementedFilter("uri_escape"))
engine.DefineFilter("scssify", unimplementedFilter("scssify"))
engine.DefineFilter("smartify", unimplementedFilter("smartify"))
engine.DefineFilter("xml_escape", func(s string) string {
e.DefineFilter("cgi_escape", unimplementedFilter("cgi_escape"))
e.DefineFilter("uri_escape", unimplementedFilter("uri_escape"))
e.DefineFilter("scssify", unimplementedFilter("scssify"))
e.DefineFilter("smartify", unimplementedFilter("smartify"))
e.DefineFilter("xml_escape", func(s string) string {
// TODO can't handle maps
// eval https://github.com/clbanning/mxj
// adapt https://stackoverflow.com/questions/30928770/marshall-map-to-xml-in-go

View File

@ -42,6 +42,8 @@ func NewPipeline(c config.Config, options PipelineOptions) (*Pipeline, error) {
return &p, nil
}
// SourceDir returns the site source directory. Seeing how far we can bend
// the Law of Demeter.
func (p *Pipeline) SourceDir() string {
return p.config.Source
}

View File

@ -1,3 +1,8 @@
// Package plugins holds emulated Jekyll plugins.
//
// Unlike Jekyll, these are baked into the executable -- both because as of 2017.07 package "plugin' currently
// works only on Linux, but also because the gojekyll implementation is immature and any possible interfaces
// are far from baked.
package plugins
import (
@ -9,10 +14,13 @@ import (
"github.com/osteele/liquid/chunks"
)
// PluginContext is the context for plugin initialization.
// Currently, the only thing a plugin can do is add filters and tags.
type PluginContext interface {
TemplateEngine() liquid.Engine
}
// Install installs a plugin from the plugin directory.
func Install(name string, ctx PluginContext) bool {
p, found := plugins[name]
if p != nil {
@ -25,6 +33,7 @@ func Install(name string, ctx PluginContext) bool {
var plugins = map[string]func(PluginContext) error{}
// registerPlugin installs a plugin in the plugin directory.
func registerPlugin(name string, fn func(PluginContext) error) {
plugins[name] = fn
}

View File

@ -29,8 +29,10 @@ type Site struct {
siteVariables map[string]interface{}
}
// SourceDir returns the site source directory.
func (s *Site) SourceDir() string { return s.config.Source }
// DestDir returns the site destination directory.
func (s *Site) DestDir() string {
if filepath.IsAbs(s.config.Destination) {
return s.config.Destination

View File

@ -15,19 +15,20 @@ import (
// A LinkTagHandler given an include tag file name returns a URL.
type LinkTagHandler func(string) (string, bool)
func AddJekyllTags(engine liquid.Engine, config config.Config, linkHandler LinkTagHandler) {
tc := tagContext{config, linkHandler}
engine.DefineTag("link", tc.linkTag)
engine.DefineTag("include", tc.includeTag)
// AddJekyllTags adds the Jekyll tags to the Liquid engine.
func AddJekyllTags(e liquid.Engine, c config.Config, lh LinkTagHandler) {
tc := tagContext{c, lh}
e.DefineTag("link", tc.linkTag)
e.DefineTag("include", tc.includeTag)
// TODO unimplemented
engine.DefineTag("post_url", emptyTag)
engine.DefineStartTag("highlight", highlightTag)
e.DefineTag("post_url", emptyTag)
e.DefineStartTag("highlight", highlightTag)
}
type tagContext struct {
config config.Config
linkHandler LinkTagHandler
config config.Config
lh LinkTagHandler
}
func emptyTag(_ string) (func(io.Writer, chunks.RenderContext) error, error) {
@ -47,11 +48,12 @@ func highlightTag(w io.Writer, ctx chunks.RenderContext) error {
if err != nil {
return err
}
// TODO this is disabled for performance; make it configurable instead.
if true {
_, err = w.Write([]byte(s))
return err
}
cmd := exec.Command("pygmentize", cargs...)
cmd := exec.Command("pygmentize", cargs...) // nolint: gas
cmd.Stdin = strings.NewReader(s)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@ -60,7 +62,7 @@ func highlightTag(w io.Writer, ctx chunks.RenderContext) error {
func (tc tagContext) linkTag(filename string) (func(io.Writer, chunks.RenderContext) error, error) {
return func(w io.Writer, _ chunks.RenderContext) error {
url, found := tc.linkHandler(filename)
url, found := tc.lh(filename)
if !found {
return fmt.Errorf("missing link filename: %s", filename)
}