Add ability to render drops as JSON
Previously you could do, e.g. {{ site | jsonify }}, but with the introduction of Liquid Drops, this didn't work anymore. This PR adds the ability to render drops as JSON. You can safely run drop.to_json and it should Do the Right Thing.
This commit is contained in:
parent
e02049727b
commit
17d8c96a63
|
@ -5,10 +5,12 @@ module Jekyll
|
|||
class DocumentDrop < Drop
|
||||
extend Forwardable
|
||||
|
||||
NESTED_OBJECT_FIELD_BLACKLIST = %w{
|
||||
content output excerpt next previous
|
||||
}.freeze
|
||||
|
||||
mutable false
|
||||
|
||||
def_delegator :@obj, :next_doc, :next
|
||||
def_delegator :@obj, :previous_doc, :previous
|
||||
def_delegator :@obj, :relative_path, :path
|
||||
def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url
|
||||
|
||||
|
@ -27,6 +29,37 @@ module Jekyll
|
|||
cmp
|
||||
end
|
||||
|
||||
def previous
|
||||
@obj.previous_doc.to_liquid
|
||||
end
|
||||
|
||||
def next
|
||||
@obj.next_doc.to_liquid
|
||||
end
|
||||
|
||||
# Generate a Hash for use in generating JSON.
|
||||
# This is useful if fields need to be cleared before the JSON can generate.
|
||||
#
|
||||
# Returns a Hash ready for JSON generation.
|
||||
def hash_for_json(state = nil)
|
||||
to_h.tap do |hash|
|
||||
if state && state.depth >= 2
|
||||
hash["previous"] = collapse_document(hash["previous"]) if hash["previous"]
|
||||
hash["next"] = collapse_document(hash["next"]) if hash["next"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Generate a Hash which breaks the recursive chain.
|
||||
# Certain fields which are normally available are omitted.
|
||||
#
|
||||
# Returns a Hash with only non-recursive fields present.
|
||||
def collapse_document(doc)
|
||||
doc.keys.each_with_object({}) do |(key, _), result|
|
||||
result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def_delegator :@obj, :data, :fallback_data
|
||||
end
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
module Jekyll
|
||||
module Drops
|
||||
class Drop < Liquid::Drop
|
||||
NON_CONTENT_METHODS = [:[], :[]=, :inspect, :to_h, :fallback_data].freeze
|
||||
include Enumerable
|
||||
|
||||
NON_CONTENT_METHODS = [:[], :[]=, :inspect, :to_h, :fallback_data, :collapse_document].freeze
|
||||
|
||||
# Get or set whether the drop class is mutable.
|
||||
# Mutability determines whether or not pre-defined fields may be
|
||||
|
@ -138,6 +140,22 @@ module Jekyll
|
|||
JSON.pretty_generate to_h
|
||||
end
|
||||
|
||||
# Generate a Hash for use in generating JSON.
|
||||
# This is useful if fields need to be cleared before the JSON can generate.
|
||||
#
|
||||
# Returns a Hash ready for JSON generation.
|
||||
def hash_for_json(state = nil)
|
||||
to_h
|
||||
end
|
||||
|
||||
# Generate a JSON representation of the Drop.
|
||||
#
|
||||
# Returns a JSON representation of the Drop in a String.
|
||||
def to_json(state = nil)
|
||||
require 'json'
|
||||
JSON.generate(hash_for_json(state), state)
|
||||
end
|
||||
|
||||
# Collects all the keys and passes each to the block in turn.
|
||||
#
|
||||
# block - a block which accepts one argument, the key
|
||||
|
|
|
@ -16,6 +16,18 @@ module Jekyll
|
|||
def environment
|
||||
Jekyll.env
|
||||
end
|
||||
|
||||
def to_h
|
||||
@to_h ||= {
|
||||
"version" => version,
|
||||
"environment" => environment
|
||||
}
|
||||
end
|
||||
|
||||
def to_json(state = nil)
|
||||
require 'json'
|
||||
JSON.generate(to_h, state)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -279,6 +279,7 @@ module Jekyll
|
|||
def site_payload
|
||||
Drops::UnifiedPayloadDrop.new self
|
||||
end
|
||||
alias_method :to_liquid, :site_payload
|
||||
|
||||
# Get the implementation class for the given Converter.
|
||||
# Returns the Converter instance implementing the given Converter.
|
||||
|
|
|
@ -44,6 +44,46 @@ class TestDocument < JekyllUnitTest
|
|||
assert_equal "foo.bar", @document.data["whatever"]
|
||||
end
|
||||
|
||||
should "be jsonify-able" do
|
||||
page_json = @document.to_liquid.to_json
|
||||
parsed = JSON.parse(page_json)
|
||||
|
||||
assert_equal "Jekyll.configuration", parsed["title"]
|
||||
assert_equal "foo.bar", parsed["whatever"]
|
||||
assert_equal nil, parsed["previous"]
|
||||
|
||||
next_doc = parsed["next"]
|
||||
assert_equal "_methods/escape-+ #%20[].md", next_doc["path"]
|
||||
assert_equal "Jekyll.escape", next_doc["title"]
|
||||
|
||||
next_prev_doc = next_doc["previous"]
|
||||
assert_equal "Jekyll.configuration", next_prev_doc["title"]
|
||||
assert_equal "_methods/configuration.md", next_prev_doc["path"]
|
||||
assert_equal "_methods/escape-+ #%20[].md", next_prev_doc["next"]["path"]
|
||||
assert_nil next_prev_doc["previous"] # nothing before Jekyll.configuration
|
||||
assert_nil next_prev_doc["next"]["next"]
|
||||
assert_nil next_prev_doc["next"]["previous"]
|
||||
assert_nil next_prev_doc["next"]["content"]
|
||||
assert_nil next_prev_doc["next"]["excerpt"]
|
||||
assert_nil next_prev_doc["next"]["output"]
|
||||
|
||||
next_next_doc = next_doc["next"]
|
||||
assert_equal "Jekyll.sanitized_path", next_next_doc["title"]
|
||||
assert_equal "_methods/sanitized_path.md", next_next_doc["path"]
|
||||
assert_equal "_methods/escape-+ #%20[].md", next_next_doc["previous"]["path"]
|
||||
assert_equal "_methods/site/generate.md", next_next_doc["next"]["path"]
|
||||
assert_nil next_next_doc["next"]["next"]
|
||||
assert_nil next_next_doc["next"]["previous"]
|
||||
assert_nil next_next_doc["next"]["content"]
|
||||
assert_nil next_next_doc["next"]["excerpt"]
|
||||
assert_nil next_next_doc["next"]["output"]
|
||||
assert_nil next_next_doc["previous"]["next"]
|
||||
assert_nil next_next_doc["previous"]["previous"]
|
||||
assert_nil next_next_doc["previous"]["content"]
|
||||
assert_nil next_next_doc["previous"]["excerpt"]
|
||||
assert_nil next_next_doc["previous"]["output"]
|
||||
end
|
||||
|
||||
context "with YAML ending in three dots" do
|
||||
|
||||
setup do
|
||||
|
|
|
@ -198,6 +198,44 @@ class TestFilters < JekyllUnitTest
|
|||
assert_equal "[{\"name\":\"Jack\"},{\"name\":\"Smith\"}]", @filter.jsonify([{:name => 'Jack'}, {:name => 'Smith'}])
|
||||
end
|
||||
|
||||
should "convert drop to json" do
|
||||
@filter.site.read
|
||||
expected = {
|
||||
"next" => "Categories _should_ work",
|
||||
"path" => "_posts/2008-02-02-published.markdown",
|
||||
"output" => nil,
|
||||
"previous" => nil,
|
||||
"content" => "This should be published.\n",
|
||||
"id" => "/publish_test/2008/02/02/published",
|
||||
"url" => "/publish_test/2008/02/02/published.html",
|
||||
"relative_path" => "_posts/2008-02-02-published.markdown",
|
||||
"collection" => "posts",
|
||||
"excerpt" => "<p>This should be published.</p>\n",
|
||||
"draft" => false,
|
||||
"categories" => [
|
||||
"publish_test"
|
||||
],
|
||||
"layout" => "default",
|
||||
"title" => "Publish",
|
||||
"category" => "publish_test",
|
||||
"date" => "2008-02-02 00:00:00 +0000",
|
||||
"slug" => "published",
|
||||
"ext" => ".markdown",
|
||||
"tags" => []
|
||||
}
|
||||
actual = @filter.jsonify(@filter.site.docs_to_write.first.to_liquid)
|
||||
assert_equal expected, JSON.parse(actual)
|
||||
end
|
||||
|
||||
should "convert drop with drops to json" do
|
||||
@filter.site.read
|
||||
actual = @filter.jsonify(@filter.site.to_liquid)
|
||||
assert_equal JSON.parse(actual)["jekyll"], {
|
||||
"environment" => "development",
|
||||
"version" => Jekyll::VERSION
|
||||
}
|
||||
end
|
||||
|
||||
class M < Struct.new(:message)
|
||||
def to_liquid
|
||||
[message]
|
||||
|
|
Loading…
Reference in New Issue