-
Notifications
You must be signed in to change notification settings - Fork 39
/
gist_tag.rb
120 lines (101 loc) · 4.21 KB
/
gist_tag.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# frozen_string_literal: true
require "cgi"
require "net/http"
require "octokit"
Net::OpenTimeout = Class.new(RuntimeError) unless Net.const_defined?(:OpenTimeout)
Net::ReadTimeout = Class.new(RuntimeError) unless Net.const_defined?(:ReadTimeout)
module Jekyll
module Gist
class GistTag < Liquid::Tag
def render(context)
@encoding = context.registers[:site].config["encoding"] || "utf-8"
@settings = context.registers[:site].config["gist"]
if (tag_contents = determine_arguments(@markup.strip))
gist_id = tag_contents[0]
filename = tag_contents[1]
gist_id = context[gist_id] if context_contains_key?(context, gist_id)
filename = context[filename] if context_contains_key?(context, filename)
noscript_tag = gist_noscript_tag(gist_id, filename)
script_tag = gist_script_tag(gist_id, filename)
"#{noscript_tag}#{script_tag}"
else
raise ArgumentError, <<~ERROR
Syntax error in tag 'gist' while parsing the following markup:
#{@markup}
Valid syntax:
{% gist user/1234567 %}
{% gist user/1234567 foo.js %}
{% gist 28949e1d5ee2273f9fd3 %}
{% gist 28949e1d5ee2273f9fd3 best.md %}
ERROR
end
end
private
def determine_arguments(input)
matched = input.match(%r!\A([\S]+|.*(?=\/).+)\s?(\S*)\Z!)
[matched[1].strip, matched[2].strip] if matched && matched.length >= 3
end
def context_contains_key?(context, key)
if context.respond_to?(:has_key?)
context.has_key?(key)
else
context.key?(key)
end
end
def gist_script_tag(gist_id, filename = nil)
url = "https://gist.github.com/#{gist_id}.js"
url = "#{url}?file=#{filename}" unless filename.to_s.empty?
"<script src=\"#{url}\"> </script>"
end
def gist_noscript_tag(gist_id, filename = nil)
return if @settings && @settings["noscript"] == false
code = fetch_raw_code(gist_id, filename)
if !code.nil?
code = code.force_encoding(@encoding)
code = CGI.escapeHTML(code)
# CGI.escapeHTML behavior differs in Ruby < 2.0
# See https://github.com/jekyll/jekyll-gist/pull/28
code = code.gsub("'", "'") if RUBY_VERSION < "2.0"
"<noscript><pre>#{code}</pre></noscript>"
else
Jekyll.logger.warn "Warning:", "The <noscript> tag for your gist #{gist_id} "
Jekyll.logger.warn "", "could not be generated. This will affect users who do "
Jekyll.logger.warn "", "not have JavaScript enabled in their browsers."
end
end
def fetch_raw_code(gist_id, filename = nil)
return code_from_api(gist_id, filename) if ENV["JEKYLL_GITHUB_TOKEN"]
url = "https://gist.githubusercontent.com/#{gist_id}/raw"
url = "#{url}/#{filename}" unless filename.to_s.empty?
uri = URI(url)
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == "https",
:read_timeout => 3, :open_timeout => 3) do |http|
request = Net::HTTP::Get.new uri.to_s
response = http.request(request)
response.body
end
rescue SocketError, Net::HTTPError, Net::OpenTimeout, Net::ReadTimeout, TimeoutError
nil
end
def code_from_api(gist_id, filename = nil)
gist = GistTag.client.gist gist_id
file = if filename.to_s.empty?
# No file specified, return the value of the first key/value pair
gist.files.first[1]
else
# .files is a hash of :"filename.extension" => data pairs
# Rather than using to_sym on arbitrary user input,
# Find our file by calling to_s on the keys
match = gist.files.find { |name, _data| name.to_s == filename }
match[1] if match
end
file[:content] if file
end
def self.client
@client ||= Octokit::Client.new :access_token => ENV["JEKYLL_GITHUB_TOKEN"]
end
end
end
end
Liquid::Template.register_tag("gist", Jekyll::Gist::GistTag)