Skip to content

Instantly share code, notes, and snippets.

@aarongustafson
Forked from BinaryMuse/gist_tag.rb
Last active January 2, 2017 14:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aarongustafson/b98add8f3580f6707cf5 to your computer and use it in GitHub Desktop.
Save aarongustafson/b98add8f3580f6707cf5 to your computer and use it in GitHub Desktop.
A Liquid tag for Jekyll sites that allows embedding Gists and showing code for non-JavaScript enabled browsers and readers.
# A Liquid tag for Jekyll sites that allows embedding Gists and showing code for non-JavaScript enabled browsers and readers.
# by: Brandon Tilly
# Source URL: https://gist.github.com/1027674
# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html
#
# Example usage: {% gist 1027674 gist_tag.rb embed %} //embeds a gist for this plugin
require 'cgi'
require 'digest/md5'
require 'net/https'
require 'uri'
module Jekyll
class GistTag < Liquid::Tag
def initialize(tag_name, text, token)
super
@text = text
@cache_disabled = false
@embed_code = false
@config = Jekyll.configuration({ 'quiet' => true })
@cache_folder = @config['gist_tag']['cache'] || File.expand_path( "../.gist-cache", File.dirname(__FILE__) )
@encoding = @config['encoding'] || 'UTF-8'
FileUtils.mkdir_p @cache_folder
end
def render(context)
if @text.match(/^[a-zA-Z\d]*\s.*?$/)
string = @text.gsub(/\s+/, ' ').strip
gist, file, @embed_code = string.split(' ')
else
gist, file = @text.strip, ""
end
if gist.empty?
""
else
script_url = script_url_for(gist, file)
if @embed_code
code = get_cached_gist(gist, file) || get_gist_from_web(gist, file, script_url)
html_embed code
else
gist_url = get_gist_url_for(gist, file)
code = get_cached_gist(gist, file) || get_gist_from_web(gist, file, gist_url)
javascript_embed script_url, code
end
end
end
def html_embed(code)
"<div>#{code}</div>"
end
def javascript_embed(script_url, code)
code = CGI.escapeHTML code
<<-HTML
<div><script src="#{script_url}"></script>
<noscript><pre><code>#{code}</code></pre></noscript></div>
HTML
end
def script_url_for(gist_id, filename)
url = "https://gist.github.com/#{gist_id}.js"
url = "#{url}?file=#{filename}" unless filename.nil? or filename.empty?
url
end
def get_gist_url_for(gist, file)
"https://gist.githubusercontent.com/raw/#{gist}/#{file}"
end
def cache(gist, file, data)
cache_file = get_cache_file_for gist, file
File.open(cache_file, "w") do |io|
io.write data
end
end
def get_cached_gist(gist, file)
return nil if @cache_disabled
cache_file = get_cache_file_for gist, file
File.read cache_file if File.exist? cache_file
end
def get_cache_file_for(gist, file)
bad_chars = /[^a-zA-Z0-9\-_.]/
gist = gist.gsub bad_chars, ''
file = file.gsub bad_chars, ''
md5 = Digest::MD5.hexdigest "#{gist}-#{file}"
File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache"
end
def get_gist_from_web(gist, file, gist_url)
data = get_web_content(gist_url)
locations = Array.new
while (data.code.to_i == 301 || data.code.to_i == 302)
data = handle_gist_redirecting(data)
break if locations.include? data.header['Location']
locations << data.header['Location']
end
if data.code.to_i != 200
raise RuntimeError, "Gist replied with #{data.code} for #{gist_url}"
end
# Cleanup embed version
code = data.body.force_encoding("UTF-8").encode(@encoding)
code = code.gsub( /document\.write\('/, '' ).gsub( /'\)/, '' ) # JS
code = code.gsub( /\\"/, '"' ).gsub( /\\\//, '/' ) # escaped stuff
code = code.gsub( /\\n/, "\n" ) # returns
code = code.encode(@encoding) # encode
cache(gist, file, code) unless @cache_disabled
code
end
def handle_gist_redirecting(data)
redirected_url = data.header['Location']
if redirected_url.nil? || redirected_url.empty?
raise ArgumentError, "GitHub replied with a 302 but didn't provide a location in the response headers."
end
get_web_content(redirected_url)
end
def get_web_content(url)
raw_uri = URI.parse url
proxy = ENV['http_proxy']
if proxy
proxy_uri = URI.parse(proxy)
https = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port).new raw_uri.host, raw_uri.port
else
https = Net::HTTP.new raw_uri.host, raw_uri.port
end
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new raw_uri.request_uri
data = https.request request
end
end
class GistTagNoCache < GistTag
def initialize(tag_name, text, token)
super
@cache_disabled = true
end
end
end
Liquid::Template.register_tag('gist', Jekyll::GistTag)
Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment