Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
require 'json'
require 'net/http'
# JSON parser tag, creating map for use in jekyll markdown
# Alex.Heneveld @ Cloudsoft Corp (remove spaces and add the .com)
# Released under APL 2.0
# usage: {% jsonball varname from TYPE PARAM %}
#
# where TYPE is one of {data,var,file,page}, described below
# drop this into your _plugins/ folder, then you can write, e.g.
#
# {% jsonball foo from data { "a": "b" } %}
#
# and then later refer to {{ foo.a }} to get b inserted
# more usefully, you can load it from a variable x, e.g.
# {% capture x %}{% include toc.json %}{% endcapture %}
#
# {% jsonball foo from var x %}
# even better, to read from a file, say toc.json
# (absolute, or relative to the page being jekylled):
#
# {% jsonball foo from file toc.json %}
#
# then e.g. {% for record in jsonball %} {{ record.name }} {% endfor %}
# to print out all the name entries (or build a fancy TOC sidebar)
# or even better yet, to read from a URL
#
# {% jsonball feed from url http://www.foo.com/bar.json %}
#
# then e.g. {% for record in feed %} {{ record.key }} {% endfor %}
# and finally, if that json file might itself contain liquid tags,
# or need jekylling, treat it as a page and it will get jekylled
# (we use this for toc.json reading from subdirs' toc.json files):
#
# {% jsonball foo from page toc.json %}
module JekyllJsonball
class JsonballTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
@text = text
end
def render(context)
if /(.+) from var (.+)/.match(@text)
context[$1] = JSON context[$2]
return ''
end
if /(.+) from data (.+)/.match(@text)
context[$1] = JSON $2
return ''
end
if /(.+) from file (.+)/.match(@text)
context[$1] = JSON page_relative_file_contents(context, $2.strip)
return ''
end
if /(.+) from page (.+)/.match(@text)
context[$1] = JSON jekylled_page_relative_file_contents(context, $2.strip)
return ''
end
if /(.+) from url (.+)/.match(@text)
base_url = $2
resp = Net::HTTP.get_response(URI.parse(base_url))
data = resp.body
context[$1] = JSON data
return ''
end
# syntax error
return 'ERROR:bad_jsonball_syntax'
end
def page_relative_file_contents(context, filename)
jekyllSite = context.registers[:site]
dir = jekyllSite.source+'/'+File.dirname(context['page']['url'])
if !filename.match(/\/.*/)
filename = dir + '/' + filename
end
file = File.open(filename, "rb")
return file.read
end
def jekylled_page_relative_file_contents(context, filename)
jekyllSite = context.registers[:site]
targetPage = Jekyll::Page.new(jekyllSite, jekyllSite.source, File.dirname(context['page']['url']), filename)
targetPage.render(jekyllSite.layouts, jekyllSite.site_payload)
targetPage.output
end
end
end
Liquid::Template.register_tag('jsonball', JekyllJsonball::JsonballTag)
@equivalentideas

This comment has been minimized.

Copy link

@equivalentideas equivalentideas commented Nov 10, 2014

Thanks for this @StevenBlack . Is there a way to combine the variable option with the url option, to use a url in a variable?

When I run:

          {% if text.openlibrary.id %}
            {% assign text_data_url = text.openlibrary.id | prepend: 'https://openlibrary.org/books/' | append: '.json' %}

            {% if text_data_url %}
              {% jsonball text_data from url text_data_url %}
              {{ text_data }}
            {% endif %}
          {% endif %}

I get Liquid Exception: no implicit conversion of nil into String in library.html.

And:

{% if text.openlibrary.id %}
            {% assign text_data_url = text.openlibrary.id | prepend: 'https://openlibrary.org/books/' | append: '.json' %}

            {% if text_data_url %}
              {% jsonball text_data from var text_data_url %}
              {{ text_data }}
            {% endif %}
          {% endif %}

gives me Liquid Exception: 757: unexpected token at 'https://openlibrary.org/books/OL25047097M.json' in library.html. If I write the url straight in instead of the variable it works perfectly, but I need it to be dynamic. Thanks for the useful plugin and your help :)

@combs

This comment has been minimized.

Copy link

@combs combs commented May 24, 2017

@equivalentideas 2.5 years later... I was able to get this working by changing line 69 to:

    		base_url = context[$2]

and passing in the name of the variable:

	{% jsonball feed from url theurl %}

(where theurl is my variable)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment