ジェネレーター

独自のルールに基づいてJekyllに追加コンテンツを作成する必要がある場合は、ジェネレーターを作成できます。

ジェネレーターは、Jekyll::Generatorのサブクラスであり、generateメソッドを定義します。このメソッドは、Jekyll::Siteのインスタンスを受け取ります。generateの戻り値は無視されます。

ジェネレーターは、Jekyllが既存のコンテンツのインベントリを作成した後、サイトが生成される前に実行されます。フロントマターを持つページはJekyll::Pageのインスタンスとして保存され、site.pagesを介してアクセスできます。静的ファイルはJekyll::StaticFileのインスタンスになり、site.static_filesを介してアクセスできます。詳細は、変数に関するドキュメントページJekyll::Siteを参照してください。

次の例では、ジェネレーターはビルド時に計算された値をテンプレート変数に挿入します。reading.htmlという名前のテンプレートには、未定義の変数ongoingdoneの2つがあり、ジェネレーターの実行時に定義または値が割り当てられます。

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の方が適切です。
  • フロントマターのデフォルトを介してページを設定できることは素晴らしいことです!そのため、これらのページに特定の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

生成されたページは、特定のレイアウトを使用するように設定したり、フロントマターのデフォルトを使用して設定ファイルから出力先ディレクトリの特定のパスに出力したりできるようになりました。例えば

# _config.yml

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

技術的な側面

ジェネレーターは1つのメソッドのみを実装する必要があります

メソッド 説明

generate

副作用としてコンテンツを生成します。

ジェネレーターが単一のファイルに含まれている場合、任意の名前を付けることができますが、.rb拡張子を持つ必要があります。ジェネレーターが複数のファイルに分割されている場合は、https://rubygems.org/で公開するためにRubygemとしてパッケージ化する必要があります。この場合、2つのgemが同じ名前を持つことはできないため、gemの名前はそのサイトでの名前の可用性に依存します。

デフォルトでは、Jekyllは_pluginsディレクトリでジェネレーターを探します。ただし、設定ファイルのキーplugins_dirに必要な名前を割り当てることで、デフォルトのディレクトリを変更できます。