Jekyll生成器(Generators)
当你需要 Jekyll 根据你自己的规则生成额外内容时,可以创建一个生成器(generator)。
生成器是 Jekyll::Generator 的子类,它定义一个 generate 方法,该方法接收一个 Jekyll::Site 实例作为参数。generate 方法的返回值会被忽略。
生成器会在 Jekyll 完成现有内容的整理之后、生成网站之前运行。带有 front matter 的页面会被存储为 Jekyll::Page 的实例,并可以通过 site.pages 访问。静态文件会变成 Jekyll::StaticFile 的实例,并可以通过 site.static_files 访问。详情请参阅 Variables 文档页面 和 Jekyll::Site。
在下面的示例中,生成器会在构建时为模板变量注入计算好的值。名为 reading.html 的模板有两个未定义变量 ongoing 和 done,它们会在生成器运行时被定义或赋值:
module Reading
class Generator < Jekyll::Generator
def generate(site)
book_data = site.data['books']
ongoing = book_data.select { |book| book['status'] == 'ongoing' }
done = book_data.select { |book| book['status'] == 'finished' }
# 获取模板
reading = site.pages.find { |page| page.name == 'reading.html'}
# 将数据注入模板
reading.data['ongoing'] = ongoing
reading.data['done'] = done
end
end
end
下面是一个更复杂的生成器示例,它用于生成新的页面。
在这个例子中,生成器的目标是为 site 中注册的每个分类(category)创建一个页面。这些页面是在运行时创建的,因此它们的内容、front matter 以及其他属性都需要由插件自行设计。
- 这些页面的作用是渲染某个分类下的所有文档列表。因此,生成文件的 basename 最好是
index.html。 - 如果能够通过 front matter 默认值 来配置这些页面会非常棒!因此,为这些页面分配一个特定的
type会更有利于实现这一点。
module SamplePlugin
class CategoryPageGenerator < Jekyll::Generator
safe true
def generate(site)
site.categories.each do |category, posts|
site.pages << CategoryPage.new(site, category, posts)
end
end
end
# `Jekyll::Page` 的子类,包含自定义方法定义。
class CategoryPage < Jekyll::Page
def initialize(site, category, posts)
@site = site # 当前 site 实例。
@base = site.source # 源目录路径。
@dir = category # 页面将所在的目录。
# 所有页面使用相同的文件名,因此直接定义属性。
@basename = 'index' # 不包含扩展名的文件名。
@ext = '.html' # 扩展名。
@name = 'index.html' # 基本上等于 @basename + @ext。
# 初始化 data 哈希,其中包含指向当前分类下所有文章的键。
# 这样可以在模板中通过 `page.linked_docs` 访问该列表。
@data = {
'linked_docs' => posts
}
# 如果 `data` 哈希中不存在指定 key,则查找作用域为 `categories` 的 front matter 默认值。
data.default_proc = proc do |_, key|
site.frontmatter_defaults.find(relative_path, :categories, key)
end
end
# 用于构建页面 URL 的占位符。
def url_placeholders
{
:path => @dir,
:category => @dir,
:basename => basename,
:output_ext => output_ext,
}
end
end
end
现在生成的页面可以通过配置文件中的 front matter defaults 来设置使用特定布局或在目标目录的特定路径下输出。例如:
# _config.yml
defaults:
- scope:
type: categories # 选择所有分类页面
values:
layout: category_page
permalink: categories/:category/
技术方面
生成器只需要实现一个方法:
| 方法 | 描述 |
|---|---|
|
|
以副作用的方式生成内容。 |
如果你的生成器只包含在一个文件中,可以随意命名,但必须使用 .rb 扩展名。如果你的生成器分布在多个文件中,则应将其打包为 Rubygem 并发布到 https://rubygems.org/。在这种情况下,gem 的名称取决于该网站上名称是否可用,因为不能有两个 gem 使用相同名称。
默认情况下,Jekyll 会在 _plugins 目录中查找生成器。不过,你可以在配置文件中将 plugins_dir 键设置为指定名称,从而更改默认目录。