require 'hpricot' require 'rest-client' module Rack class Gist def initialize(app, options = {}) @app = app @gist_path = @options = { :jquery => true }.merge(options) end def call(env) if path(env).match(%r{^/gist\.github\.com}) serve_gist(env) else status, headers, body = @app.call(env) rewrite(status, headers, body) end end private def rewrite(status, headers, body) if 'text/html' == headers['Content-Type'] body = [body].flatten body.map! do |part| Hpricot(part.to_s).tap do |doc| extras = false doc.search('script[@src*="gist.github.com"]').each do |tag| extras = true tag['src'].match(regex).tap do |match| id, file = match[1, 2] suffix, extra = file ? ["#file_#{file}", "rack-gist-file='#{file}'"] : ['', ''] tag.swap("
Can't see this Gist? View it on Github!
") end end if extras doc.search('head').append(css_html) doc.search('body').tap do |node| node.append(jquery_link) if @options[:jquery] node.append(jquery_helper) end end end.to_s end headers['Content-Length'] = body.map { |part| Rack::Utils.bytesize(part) }.inject(0) { |sum, size| sum + size }.to_s end [status, headers, body] end def serve_gist(env) gist_id, file = path(env).match(%r{gist\.github\.com/(\d+)(?:/(.*))?\.js})[1,2] cache = @options[:cache] gist = (cache ? cache.fetch(cache_key(gist_id, file), :expires_in => 3600) { get_gist(gist_id, file) } : get_gist(gist_id, file)).to_s [ 200, { 'Content-Type' => 'application/javascript', 'Content-Length' => Rack::Utils.bytesize(gist).to_s }, [gist] ] end def get_gist(gist_id, file) gist = RestClient.get(gist_url(gist_id, file)) gist = gist.split("\n").reject do |part| part.empty? end.last selector = "#rack-gist-#{gist_id}" selector << %Q{[rack-gist-file="#{file}"]} if file gist.sub(/document\.write/, %Q{$('#{selector}').replaceWith}) end def cache_key(gist_id, file) key = "rack-gist:#{gist_id}" key << ":#{file.gsub(/\s/, '')}" unless file.nil? key end def gist_url(gist_id, file) url = "http://gist.github.com/#{gist_id}.js" url << "?file=#{file}" unless file.nil? url end def path(env) Rack::Utils.unescape(env['PATH_INFO']) end def regex @regex ||= %r{gist\.github\.com/(\d+)\.js(?:\?file=(.*))?} end def css_html "\n" end def jquery_link "\n" end def jquery_helper <<-EOJQ EOJQ end end end