-
Notifications
You must be signed in to change notification settings - Fork 39
/
gist_tag.rb
126 lines (105 loc) · 4.08 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
121
122
123
124
125
126
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, filename = tag_contents[0], tag_contents[1]
if context_contains_key?(context, gist_id)
gist_id = context[gist_id]
end
if context_contains_key?(context, filename)
filename = context[filename]
end
noscript_tag = gist_noscript_tag(gist_id, filename)
script_tag = gist_script_tag(gist_id, filename)
"#{noscript_tag}#{script_tag}"
else
raise ArgumentError.new <<-eos
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 %}
eos
end
end
private
def determine_arguments(input)
matched = input.match(/\A([\S]+|.*(?=\/).+)\s?(\S*)\Z/)
[matched[1].strip, matched[2].strip] if matched && matched.length >= 3
end
private
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} could not"
Jekyll.logger.warn "", "be generated. This will affect users who do not have"
Jekyll.logger.warn "", "JavaScript available or 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
private
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)