生成器

当你需要 Jekyll 根据你自己的规则创建附加内容时,你可以创建一个生成器。

生成器是 Jekyll::Generator 的子类,它定义了一个 generate 方法,该方法接收 Jekyll::Site 的一个实例。 generate 的返回值将被忽略。

生成器在 Jekyll 清点现有内容后和生成网站之前运行。带有页眉信息的页面存储为 Jekyll::Page 的实例,并可通过 site.pages 获得。静态文件成为 Jekyll::StaticFile 的实例,并可通过 site.static_files 获得。有关详细信息,请参阅 变量文档页面Jekyll::Site

在以下示例中,生成器将在构建时为模板变量注入计算值。名为 reading.html 的模板有两个未定义的变量 ongoingdone,当生成器运行时,这些变量将被定义或分配一个值

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' }

      # get template
      reading = site.pages.find { |page| page.name == 'reading.html'}

      # inject data into template
      reading.data['ongoing'] = ongoing
      reading.data['done'] = done
    end
  end
end

以下示例是一个更复杂的生成器,它生成新页面。

在此示例中,生成器的目的是为 site 中注册的每个类别创建一个页面。这些页面是在运行时创建的,因此它们的正文、页眉信息和其他属性需要由插件本身设计。

  • 这些页面旨在呈现给定类别下的所有文档的列表。因此,呈现的文件的基本名称最好为 index.html
  • 能够通过frontmatter 默认值配置页面将非常棒!因此,为这些页面分配特定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

  # Subclass of `Jekyll::Page` with custom method definitions.
  class CategoryPage < Jekyll::Page
    def initialize(site, category, posts)
      @site = site             # the current site instance.
      @base = site.source      # path to the source directory.
      @dir  = category         # the directory the page will reside in.

      # All pages have the same filename, so define attributes straight away.
      @basename = 'index'      # filename without the extension.
      @ext      = '.html'      # the extension.
      @name     = 'index.html' # basically @basename + @ext.

      # Initialize data hash with a key pointing to all posts under current category.
      # This allows accessing the list in a template via `page.linked_docs`.
      @data = {
        'linked_docs' => posts
      }

      # Look up front matter defaults scoped to type `categories`, if given key
      # doesn't exist in the `data` hash.
      data.default_proc = proc do |_, key|
        site.frontmatter_defaults.find(relative_path, :categories, key)
      end
    end

    # Placeholders that are used in constructing page URL.
    def url_placeholders
      {
        :path       => @dir,
        :category   => @dir,
        :basename   => basename,
        :output_ext => output_ext,
      }
    end
  end
end

现在,可以通过使用 frontmatter 默认值在配置文件中设置特定布局或在目标目录中的特定路径处输出生成的页面。例如

# _config.yml

defaults:
  - scope:
      type: categories  # select all category pages
    values:
      layout: category_page
      permalink: categories/:category/

技术方面

生成器只需要实现一种方法

方法 说明

generate

作为副作用生成内容。

如果生成器包含在单个文件中,则可以根据需要对其命名,但它应该具有.rb扩展名。如果生成器跨多个文件拆分,则应该将其打包为 Rubygem,并在 https://rubygems.org.cn/ 发布。在这种情况下,gem 的名称取决于该网站上名称的可用性,因为没有两个 gem 可以具有相同的名称。

默认情况下,Jekyll 在_plugins目录中查找生成器。但是,可以通过在配置文件中将所需名称分配给键plugins_dir来更改默认目录。