Refine hook implementation
- hooks are registered to symbol owners rather than classes directly - during registration, add the ability to specify owner as an array to register the same hook to multiple owners - add optional priority during registration as a symbol (:low, :normal, :high) - implement hooks for collections as they are in octopress-hooks, aside from post_init
This commit is contained in:
parent
6ca9633354
commit
245d9677d7
|
@ -6,7 +6,7 @@ Feature: Hooks
|
|||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Site, :reset do |site|
|
||||
Jekyll::Hooks.register :site, :reset do |site|
|
||||
pageklass = Class.new(Jekyll::Page) do
|
||||
def initialize(site, base)
|
||||
@site = site
|
||||
|
@ -32,7 +32,7 @@ Feature: Hooks
|
|||
And I have a "index.html" page that contains "{{ site.injected }}!"
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Site, :pre_render do |site, payload|
|
||||
Jekyll::Hooks.register :site, :pre_render do |site, payload|
|
||||
payload['site']['injected'] = 'myparam'
|
||||
end
|
||||
"""
|
||||
|
@ -46,7 +46,7 @@ Feature: Hooks
|
|||
And I have a "page2.html" page that contains "page2"
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Site, :post_read do |site|
|
||||
Jekyll::Hooks.register :site, :post_read do |site|
|
||||
site.pages.delete_if { |p| p.name == 'page1.html' }
|
||||
end
|
||||
"""
|
||||
|
@ -59,7 +59,7 @@ Feature: Hooks
|
|||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Site, :post_write do |site|
|
||||
Jekyll::Hooks.register :site, :post_write do |site|
|
||||
firstpage = site.pages.first
|
||||
content = File.read firstpage.destination(site.dest)
|
||||
File.write(File.join(site.dest, 'firstpage.html'), content)
|
||||
|
@ -74,7 +74,7 @@ Feature: Hooks
|
|||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Page, :post_init do |page|
|
||||
Jekyll::Hooks.register :page, :post_init do |page|
|
||||
page.name = 'renamed.html'
|
||||
page.process(page.name)
|
||||
end
|
||||
|
@ -88,7 +88,7 @@ Feature: Hooks
|
|||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Page, :pre_render do |page, payload|
|
||||
Jekyll::Hooks.register :page, :pre_render do |page, payload|
|
||||
payload['myparam'] = 'special' if page.name == 'page1.html'
|
||||
end
|
||||
"""
|
||||
|
@ -103,7 +103,7 @@ Feature: Hooks
|
|||
And I have a "index.html" page that contains "WRAP ME"
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Page, :post_render do |page|
|
||||
Jekyll::Hooks.register :page, :post_render do |page|
|
||||
page.output = "{{{{{ #{page.output.chomp} }}}}}"
|
||||
end
|
||||
"""
|
||||
|
@ -115,7 +115,7 @@ Feature: Hooks
|
|||
And I have a "index.html" page that contains "HELLO FROM A PAGE"
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register Jekyll::Page, :post_write do |page|
|
||||
Jekyll::Hooks.register :page, :post_write do |page|
|
||||
require 'fileutils'
|
||||
filename = page.destination(page.site.dest)
|
||||
FileUtils.mv(filename, "#{filename}.moved")
|
||||
|
@ -129,7 +129,7 @@ Feature: Hooks
|
|||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
# rot13 translate
|
||||
Jekyll::Hooks.register Jekyll::Post, :post_init do |post|
|
||||
Jekyll::Hooks.register :post, :post_init do |post|
|
||||
post.content.tr!('abcdefghijklmnopqrstuvwxyz',
|
||||
'nopqrstuvwxyzabcdefghijklm')
|
||||
end
|
||||
|
@ -148,7 +148,7 @@ Feature: Hooks
|
|||
"""
|
||||
# Add myvar = 'old' to posts before 2015-03-15, and myvar = 'new' for
|
||||
# others
|
||||
Jekyll::Hooks.register Jekyll::Post, :pre_render do |post, payload|
|
||||
Jekyll::Hooks.register :post, :pre_render do |post, payload|
|
||||
if post.date < Time.new(2015, 3, 15)
|
||||
payload['myvar'] = 'old'
|
||||
else
|
||||
|
@ -170,7 +170,7 @@ Feature: Hooks
|
|||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
# Replace content after rendering
|
||||
Jekyll::Hooks.register Jekyll::Post, :post_render do |post|
|
||||
Jekyll::Hooks.register :post, :post_render do |post|
|
||||
post.output.gsub! /42/, 'the answer to life, the universe and everything'
|
||||
end
|
||||
"""
|
||||
|
@ -188,7 +188,7 @@ Feature: Hooks
|
|||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
# Log all post filesystem writes
|
||||
Jekyll::Hooks.register Jekyll::Post, :post_write do |post|
|
||||
Jekyll::Hooks.register :post, :post_write do |post|
|
||||
filename = post.destination(post.site.dest)
|
||||
open('_site/post-build.log', 'a') do |f|
|
||||
f.puts "Wrote #{filename} at #{Time.now}"
|
||||
|
@ -203,3 +203,125 @@ Feature: Hooks
|
|||
When I run jekyll build
|
||||
Then I should see "_site/2015/03/14/entry1.html at" in "_site/post-build.log"
|
||||
Then I should see "_site/2015/03/15/entry2.html at" in "_site/post-build.log"
|
||||
|
||||
Scenario: Register a hook on multiple owners at the same time
|
||||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register [:page, :post], :post_render do |owner|
|
||||
owner.output = "{{{{{ #{owner.output.chomp} }}}}}"
|
||||
end
|
||||
"""
|
||||
And I have a "index.html" page that contains "WRAP ME"
|
||||
And I have a _posts directory
|
||||
And I have the following posts:
|
||||
| title | date | layout | content |
|
||||
| entry1 | 2015-03-14 | nil | entry one |
|
||||
When I run jekyll build
|
||||
Then I should see "{{{{{ WRAP ME }}}}}" in "_site/index.html"
|
||||
And I should see "{{{{{ <p>entry one</p> }}}}}" in "_site/2015/03/14/entry1.html"
|
||||
|
||||
Scenario: Allow hooks to have a named priority
|
||||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register :page, :post_render, priority: :normal do |owner|
|
||||
# first normal runs second
|
||||
owner.output = "1 #{owner.output.chomp}"
|
||||
end
|
||||
Jekyll::Hooks.register :page, :post_render, priority: :high do |owner|
|
||||
# high runs last
|
||||
owner.output = "2 #{owner.output.chomp}"
|
||||
end
|
||||
Jekyll::Hooks.register :page, :post_render do |owner|
|
||||
# second normal runs third (normal is default)
|
||||
owner.output = "3 #{owner.output.chomp}"
|
||||
end
|
||||
Jekyll::Hooks.register :page, :post_render, priority: :low do |owner|
|
||||
# low runs first
|
||||
owner.output = "4 #{owner.output.chomp}"
|
||||
end
|
||||
"""
|
||||
And I have a "index.html" page that contains "WRAP ME"
|
||||
When I run jekyll build
|
||||
Then I should see "2 3 1 4 WRAP ME" in "_site/index.html"
|
||||
|
||||
Scenario: Alter a document right after it is initialized
|
||||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register :document, :pre_render do |doc, payload|
|
||||
doc.data['text'] = doc.data['text'] << ' are belong to us'
|
||||
end
|
||||
"""
|
||||
And I have a "_config.yml" file that contains "collections: [ memes ]"
|
||||
And I have a _memes directory
|
||||
And I have a "_memes/doc1.md" file with content:
|
||||
"""
|
||||
---
|
||||
text: all your base
|
||||
---
|
||||
"""
|
||||
And I have an "index.md" file with content:
|
||||
"""
|
||||
---
|
||||
---
|
||||
{{ site.memes.first.text }}
|
||||
"""
|
||||
When I run jekyll build
|
||||
Then the _site directory should exist
|
||||
And I should see "all your base are belong to us" in "_site/index.html"
|
||||
|
||||
Scenario: Update a document after rendering it, but before writing it to disk
|
||||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register :document, :post_render do |doc|
|
||||
doc.output.gsub! /<p>/, '<p class="meme">'
|
||||
end
|
||||
"""
|
||||
And I have a "_config.yml" file with content:
|
||||
"""
|
||||
collections:
|
||||
memes:
|
||||
output: true
|
||||
"""
|
||||
And I have a _memes directory
|
||||
And I have a "_memes/doc1.md" file with content:
|
||||
"""
|
||||
---
|
||||
text: all your base are belong to us
|
||||
---
|
||||
{{ page.text }}
|
||||
"""
|
||||
When I run jekyll build
|
||||
Then the _site directory should exist
|
||||
And I should see "<p class=\"meme\">all your base are belong to us" in "_site/memes/doc1.html"
|
||||
|
||||
Scenario: Perform an action after every document is written
|
||||
Given I have a _plugins directory
|
||||
And I have a "_plugins/ext.rb" file with content:
|
||||
"""
|
||||
Jekyll::Hooks.register :document, :post_write do |doc|
|
||||
open('_site/document-build.log', 'a') do |f|
|
||||
f.puts "Wrote document #{doc.collection.docs.index doc} at #{Time.now}"
|
||||
end
|
||||
end
|
||||
"""
|
||||
And I have a "_config.yml" file with content:
|
||||
"""
|
||||
collections:
|
||||
memes:
|
||||
output: true
|
||||
"""
|
||||
And I have a _memes directory
|
||||
And I have a "_memes/doc1.md" file with content:
|
||||
"""
|
||||
---
|
||||
text: all your base are belong to us
|
||||
---
|
||||
{{ page.text }}
|
||||
"""
|
||||
When I run jekyll build
|
||||
Then the _site directory should exist
|
||||
And I should see "Wrote document 0" in "_site/document-build.log"
|
||||
|
|
|
@ -175,11 +175,15 @@ module Jekyll
|
|||
#
|
||||
# Returns nothing.
|
||||
def write(dest)
|
||||
Jekyll::Hooks.trigger self, :post_render
|
||||
|
||||
path = destination(dest)
|
||||
FileUtils.mkdir_p(File.dirname(path))
|
||||
File.open(path, 'wb') do |f|
|
||||
f.write(output)
|
||||
end
|
||||
|
||||
Jekyll::Hooks.trigger self, :post_write
|
||||
end
|
||||
|
||||
# Returns merged option hash for File.read of self.site (if exists)
|
||||
|
|
|
@ -1,51 +1,101 @@
|
|||
module Jekyll
|
||||
module Hooks
|
||||
# Helps look up hooks from the registry by owner's class
|
||||
OWNER_MAP = {
|
||||
Jekyll::Site => :site,
|
||||
Jekyll::Page => :page,
|
||||
Jekyll::Post => :post,
|
||||
Jekyll::Document => :document,
|
||||
}.freeze
|
||||
|
||||
DEFAULT_PRIORITY = 20
|
||||
|
||||
# compatibility layer for octopress-hooks users
|
||||
PRIORITY_MAP = {
|
||||
low: 10,
|
||||
normal: 20,
|
||||
high: 30,
|
||||
}.freeze
|
||||
|
||||
# initial empty hooks
|
||||
@registry = {
|
||||
Jekyll::Site => {
|
||||
:site => {
|
||||
reset: [],
|
||||
post_read: [],
|
||||
pre_render: [],
|
||||
post_write: [],
|
||||
},
|
||||
Jekyll::Page => {
|
||||
:page => {
|
||||
post_init: [],
|
||||
pre_render: [],
|
||||
post_render: [],
|
||||
post_write: [],
|
||||
},
|
||||
Jekyll::Post => {
|
||||
:post => {
|
||||
post_init: [],
|
||||
pre_render: [],
|
||||
post_render: [],
|
||||
post_write: [],
|
||||
},
|
||||
:document => {
|
||||
pre_render: [],
|
||||
post_render: [],
|
||||
post_write: [],
|
||||
},
|
||||
}
|
||||
|
||||
# map of all hooks and their priorities
|
||||
@hook_priority = {}
|
||||
|
||||
NotAvailable = Class.new(RuntimeError)
|
||||
|
||||
# register a hook to be called later
|
||||
def self.register(klass, event, &block)
|
||||
unless @registry[klass]
|
||||
# register hook(s) to be called later
|
||||
def self.register(owners, event, priority: nil, &block)
|
||||
Array(owners).each do |owner|
|
||||
register_one(owner, event, priority: priority_value(priority), &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure the priority is a Fixnum
|
||||
def self.priority_value(priority=nil)
|
||||
return DEFAULT_PRIORITY unless priority
|
||||
return priority if priority.is_a?(Fixnum)
|
||||
PRIORITY_MAP[priority] || DEFAULT_PRIORITY
|
||||
end
|
||||
|
||||
# register a single hook to be called later
|
||||
def self.register_one(owner, event, priority: nil, &block)
|
||||
unless @registry[owner]
|
||||
raise NotAvailable, "Hooks are only available for the following " <<
|
||||
"classes: #{@registry.keys.inspect}"
|
||||
end
|
||||
|
||||
unless @registry[klass][event]
|
||||
raise NotAvailable, "Invalid hook. #{klass} supports only the " <<
|
||||
"following hooks #{@registry[klass].keys.inspect}"
|
||||
unless @registry[owner][event]
|
||||
raise NotAvailable, "Invalid hook. #{owner} supports only the " <<
|
||||
"following hooks #{@registry[owner].keys.inspect}"
|
||||
end
|
||||
|
||||
@registry[klass][event] << block
|
||||
insert_hook owner, event, priority, &block
|
||||
end
|
||||
|
||||
def self.insert_hook(owner, event, priority, &block)
|
||||
@hook_priority[block] = "#{priority}.#{@hook_priority.size}".to_f
|
||||
@registry[owner][event] << block
|
||||
end
|
||||
|
||||
# interface for Jekyll core components to trigger hooks
|
||||
def self.trigger(instance, event, *args)
|
||||
# proceed only if there are hooks to call
|
||||
return unless @registry[instance.class]
|
||||
return unless @registry[instance.class][event]
|
||||
owner_symbol = OWNER_MAP[instance.class]
|
||||
|
||||
@registry[instance.class][event].each do |hook|
|
||||
# proceed only if there are hooks to call
|
||||
return unless @registry[owner_symbol]
|
||||
return unless @registry[owner_symbol][event]
|
||||
|
||||
# hooks to call for this owner and event
|
||||
hooks = @registry[owner_symbol][event]
|
||||
|
||||
# sort and call hooks according to priority and load order
|
||||
hooks.sort_by { |h| @hook_priority[h] }.each do |hook|
|
||||
hook.call(instance, *args)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -491,16 +491,16 @@ custom functionality every time Jekyll renders a post, you could register a
|
|||
hook like this:
|
||||
|
||||
{% highlight ruby %}
|
||||
Jekyll::Hooks.register Jekyll::Post, :post_render do |post|
|
||||
Jekyll::Hooks.register :post, :post_render do |post|
|
||||
# code to call after Jekyll renders a post
|
||||
end
|
||||
{% endhighlight %}
|
||||
|
||||
Jekyll provides hooks for <code>Jekyll::Site</code>, <code>Jekyll::Page</code>
|
||||
and <code>Jekyll::Post</code>. In all cases, Jekyll calls your hooks with the
|
||||
container object as the first callback parameter. But in the case of
|
||||
<code>:pre_render</code>, your hook will also receive a payload hash as a
|
||||
second parameter which allows you full control over the variables that are
|
||||
Jekyll provides hooks for <code>:site</code>, <code>:page</code>,
|
||||
<code>:post</code>, and <code>:document</code>. In all cases, Jekyll calls your
|
||||
hooks with the container object as the first callback parameter. But in the
|
||||
case of <code>:pre_render</code>, your hook will also receive a payload hash as
|
||||
a second parameter which allows you full control over the variables that are
|
||||
available while rendering.
|
||||
|
||||
The complete list of available hooks is below:
|
||||
|
@ -517,7 +517,7 @@ The complete list of available hooks is below:
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Site</code></p>
|
||||
<p><code>:site</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:reset</code></p>
|
||||
|
@ -528,7 +528,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Site</code></p>
|
||||
<p><code>:site</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:pre_render</code></p>
|
||||
|
@ -539,7 +539,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Site</code></p>
|
||||
<p><code>:site</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_render</code></p>
|
||||
|
@ -550,7 +550,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Site</code></p>
|
||||
<p><code>:site</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_write</code></p>
|
||||
|
@ -561,7 +561,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Page</code></p>
|
||||
<p><code>:page</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_init</code></p>
|
||||
|
@ -572,7 +572,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Page</code></p>
|
||||
<p><code>:page</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:pre_render</code></p>
|
||||
|
@ -583,7 +583,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Page</code></p>
|
||||
<p><code>:page</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_render</code></p>
|
||||
|
@ -594,7 +594,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Page</code></p>
|
||||
<p><code>:page</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_write</code></p>
|
||||
|
@ -605,7 +605,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Post</code></p>
|
||||
<p><code>:post</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_init</code></p>
|
||||
|
@ -616,7 +616,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Post</code></p>
|
||||
<p><code>:post</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:pre_render</code></p>
|
||||
|
@ -627,7 +627,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Post</code></p>
|
||||
<p><code>:post</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_render</code></p>
|
||||
|
@ -638,7 +638,7 @@ The complete list of available hooks is below:
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>Jekyll::Post</code></p>
|
||||
<p><code>:post</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_write</code></p>
|
||||
|
@ -647,6 +647,39 @@ The complete list of available hooks is below:
|
|||
<p>After writing a post to disk</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>:document</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:pre_render</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p>Just before rendering a document</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>:document</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_render</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p>After rendering a document, but before writing it to disk</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code>:document</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p><code>:post_write</code></p>
|
||||
</td>
|
||||
<td>
|
||||
<p>After writing a document to disk</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue