Skip to content

Commit cecdefe

Browse files
committed
Merge pull request #28 from jekyll/api
Merge pull request 28
2 parents acc6063 + af85461 commit cecdefe

File tree

7 files changed

+296
-13
lines changed

7 files changed

+296
-13
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ You may optionally specify a `filename` after the `gist_id`:
4747

4848
This will produce the correct URL to show just the specified file in your post rather than the entire Gist.
4949

50+
**Pro-tip**: If you provide a personal access token with Gist scope, as the environmental variable `JEKYLL_GITHUB_TOKEN`, Jekyll Gist will use the Gist API to speed up site generation.
51+
5052
## Disabling `noscript` support
5153

5254
By default, Jekyll Gist will make an HTTP call per Gist to retrieve the raw content of the Gist. This information is used to propagate `noscript` tags for search engines and browsers without Javascript support. If you'd like to disable this feature, for example, to speed up builds locally, simply add the following to your site's `_config.yml`:

jekyll-gist.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
1919
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
2020
spec.require_paths = ["lib"]
2121

22+
spec.add_dependency "octokit", "~> 4.2"
2223
spec.add_development_dependency "bundler", "~> 1.6"
2324
spec.add_development_dependency "rake"
2425
spec.add_development_dependency "rspec"

lib/jekyll-gist/gist_tag.rb

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'cgi'
22
require 'net/http'
3+
require 'octokit'
34

45
Net::OpenTimeout = Class.new(RuntimeError) unless Net.const_defined?(:OpenTimeout)
56
Net::ReadTimeout = Class.new(RuntimeError) unless Net.const_defined?(:ReadTimeout)
@@ -55,7 +56,13 @@ def gist_noscript_tag(gist_id, filename = nil)
5556
code = fetch_raw_code(gist_id, filename)
5657
if !code.nil?
5758
code = code.force_encoding(@encoding)
58-
"<noscript><pre>#{CGI.escapeHTML(code)}</pre></noscript>"
59+
code = CGI.escapeHTML(code)
60+
61+
# CGI.escapeHTML behavior differs in Ruby < 2.0
62+
# See https://github.com/jekyll/jekyll-gist/pull/28
63+
code = code.gsub("'", "&#39;") if RUBY_VERSION < "2.0"
64+
65+
"<noscript><pre>#{code}</pre></noscript>"
5966
else
6067
Jekyll.logger.warn "Warning:", "The <noscript> tag for your gist #{gist_id} could not"
6168
Jekyll.logger.warn "", "be generated. This will affect users who do not have"
@@ -64,20 +71,43 @@ def gist_noscript_tag(gist_id, filename = nil)
6471
end
6572

6673
def fetch_raw_code(gist_id, filename = nil)
74+
return code_from_api(gist_id, filename) if ENV["JEKYLL_GITHUB_TOKEN"]
75+
6776
url = "https://gist.githubusercontent.com/#{gist_id}/raw"
6877
url = "#{url}/#{filename}" unless filename.empty?
69-
begin
70-
uri = URI(url)
71-
Net::HTTP.start(uri.host, uri.port,
72-
use_ssl: uri.scheme == 'https',
73-
read_timeout: 3, open_timeout: 3) do |http|
74-
request = Net::HTTP::Get.new uri.to_s
75-
response = http.request(request)
76-
response.body
77-
end
78-
rescue SocketError, Net::HTTPError, Net::OpenTimeout, Net::ReadTimeout, TimeoutError
79-
nil
78+
uri = URI(url)
79+
Net::HTTP.start(uri.host, uri.port,
80+
use_ssl: uri.scheme == 'https',
81+
read_timeout: 3, open_timeout: 3) do |http|
82+
request = Net::HTTP::Get.new uri.to_s
83+
response = http.request(request)
84+
response.body
85+
end
86+
rescue SocketError, Net::HTTPError, Net::OpenTimeout, Net::ReadTimeout, TimeoutError
87+
nil
88+
end
89+
90+
private
91+
92+
def code_from_api(gist_id, filename = nil)
93+
gist = GistTag.client.gist gist_id
94+
95+
file = if filename.to_s.empty?
96+
# No file specified, return the value of the first key/value pair
97+
gist.files.first[1]
98+
else
99+
# .files is a hash of :"filename.extension" => data pairs
100+
# Rather than using to_sym on arbitrary user input,
101+
# Find our file by calling to_s on the keys
102+
match = gist.files.find { |name, data| name.to_s == filename }
103+
match[1] if match
80104
end
105+
106+
file[:content] if file
107+
end
108+
109+
def self.client
110+
@client ||= Octokit::Client.new :access_token => ENV["JEKYLL_GITHUB_TOKEN"]
81111
end
82112
end
83113
end

spec/fixtures/multiple-files.json

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"url": "https://api.github.com/gists/aa5a315d61ae9438b18d",
3+
"forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks",
4+
"commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits",
5+
"id": "aa5a315d61ae9438b18d",
6+
"description": "description of gist",
7+
"public": true,
8+
"owner": {
9+
"login": "octocat",
10+
"id": 1,
11+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
12+
"gravatar_id": "",
13+
"url": "https://api.github.com/users/octocat",
14+
"html_url": "https://github.com/octocat",
15+
"followers_url": "https://api.github.com/users/octocat/followers",
16+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
17+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
18+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
19+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
20+
"organizations_url": "https://api.github.com/users/octocat/orgs",
21+
"repos_url": "https://api.github.com/users/octocat/repos",
22+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
23+
"received_events_url": "https://api.github.com/users/octocat/received_events",
24+
"type": "User",
25+
"site_admin": false
26+
},
27+
"user": null,
28+
"files": {
29+
"ring.erl": {
30+
"size": 932,
31+
"raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl",
32+
"type": "text/plain",
33+
"language": "Erlang",
34+
"truncated": false,
35+
"content": "contents of gist"
36+
},
37+
"hello-world.rb": {
38+
"size": 932,
39+
"raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl",
40+
"type": "text/plain",
41+
"language": "Ruby",
42+
"truncated": false,
43+
"content": "puts 'hello world'"
44+
}
45+
},
46+
"comments": 0,
47+
"comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/",
48+
"html_url": "https://gist.github.com/aa5a315d61ae9438b18d",
49+
"git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
50+
"git_push_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
51+
"created_at": "2010-04-14T02:15:15Z",
52+
"updated_at": "2011-06-20T11:34:15Z",
53+
"forks": [
54+
{
55+
"user": {
56+
"login": "octocat",
57+
"id": 1,
58+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
59+
"gravatar_id": "",
60+
"url": "https://api.github.com/users/octocat",
61+
"html_url": "https://github.com/octocat",
62+
"followers_url": "https://api.github.com/users/octocat/followers",
63+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
64+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
65+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
66+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
67+
"organizations_url": "https://api.github.com/users/octocat/orgs",
68+
"repos_url": "https://api.github.com/users/octocat/repos",
69+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
70+
"received_events_url": "https://api.github.com/users/octocat/received_events",
71+
"type": "User",
72+
"site_admin": false
73+
},
74+
"url": "https://api.github.com/gists/dee9c42e4998ce2ea439",
75+
"id": "dee9c42e4998ce2ea439",
76+
"created_at": "2011-04-14T16:00:49Z",
77+
"updated_at": "2011-04-14T16:00:49Z"
78+
}
79+
],
80+
"history": [
81+
{
82+
"url": "https://api.github.com/gists/aa5a315d61ae9438b18d/57a7f021a713b1c5a6a199b54cc514735d2d462f",
83+
"version": "57a7f021a713b1c5a6a199b54cc514735d2d462f",
84+
"user": {
85+
"login": "octocat",
86+
"id": 1,
87+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
88+
"gravatar_id": "",
89+
"url": "https://api.github.com/users/octocat",
90+
"html_url": "https://github.com/octocat",
91+
"followers_url": "https://api.github.com/users/octocat/followers",
92+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
93+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
94+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
95+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
96+
"organizations_url": "https://api.github.com/users/octocat/orgs",
97+
"repos_url": "https://api.github.com/users/octocat/repos",
98+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
99+
"received_events_url": "https://api.github.com/users/octocat/received_events",
100+
"type": "User",
101+
"site_admin": false
102+
},
103+
"change_status": {
104+
"deletions": 0,
105+
"additions": 180,
106+
"total": 180
107+
},
108+
"committed_at": "2010-04-14T02:15:15Z"
109+
}
110+
]
111+
}

spec/fixtures/single-file.json

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
{
2+
"url": "https://api.github.com/gists/aa5a315d61ae9438b18d",
3+
"forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks",
4+
"commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits",
5+
"id": "aa5a315d61ae9438b18d",
6+
"description": "description of gist",
7+
"public": true,
8+
"owner": {
9+
"login": "octocat",
10+
"id": 1,
11+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
12+
"gravatar_id": "",
13+
"url": "https://api.github.com/users/octocat",
14+
"html_url": "https://github.com/octocat",
15+
"followers_url": "https://api.github.com/users/octocat/followers",
16+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
17+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
18+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
19+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
20+
"organizations_url": "https://api.github.com/users/octocat/orgs",
21+
"repos_url": "https://api.github.com/users/octocat/repos",
22+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
23+
"received_events_url": "https://api.github.com/users/octocat/received_events",
24+
"type": "User",
25+
"site_admin": false
26+
},
27+
"user": null,
28+
"files": {
29+
"ring.erl": {
30+
"size": 932,
31+
"raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl",
32+
"type": "text/plain",
33+
"language": "Erlang",
34+
"truncated": false,
35+
"content": "contents of gist"
36+
}
37+
},
38+
"comments": 0,
39+
"comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/",
40+
"html_url": "https://gist.github.com/aa5a315d61ae9438b18d",
41+
"git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
42+
"git_push_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
43+
"created_at": "2010-04-14T02:15:15Z",
44+
"updated_at": "2011-06-20T11:34:15Z",
45+
"forks": [
46+
{
47+
"user": {
48+
"login": "octocat",
49+
"id": 1,
50+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
51+
"gravatar_id": "",
52+
"url": "https://api.github.com/users/octocat",
53+
"html_url": "https://github.com/octocat",
54+
"followers_url": "https://api.github.com/users/octocat/followers",
55+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
56+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
57+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
58+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
59+
"organizations_url": "https://api.github.com/users/octocat/orgs",
60+
"repos_url": "https://api.github.com/users/octocat/repos",
61+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
62+
"received_events_url": "https://api.github.com/users/octocat/received_events",
63+
"type": "User",
64+
"site_admin": false
65+
},
66+
"url": "https://api.github.com/gists/dee9c42e4998ce2ea439",
67+
"id": "dee9c42e4998ce2ea439",
68+
"created_at": "2011-04-14T16:00:49Z",
69+
"updated_at": "2011-04-14T16:00:49Z"
70+
}
71+
],
72+
"history": [
73+
{
74+
"url": "https://api.github.com/gists/aa5a315d61ae9438b18d/57a7f021a713b1c5a6a199b54cc514735d2d462f",
75+
"version": "57a7f021a713b1c5a6a199b54cc514735d2d462f",
76+
"user": {
77+
"login": "octocat",
78+
"id": 1,
79+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
80+
"gravatar_id": "",
81+
"url": "https://api.github.com/users/octocat",
82+
"html_url": "https://github.com/octocat",
83+
"followers_url": "https://api.github.com/users/octocat/followers",
84+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
85+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
86+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
87+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
88+
"organizations_url": "https://api.github.com/users/octocat/orgs",
89+
"repos_url": "https://api.github.com/users/octocat/repos",
90+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
91+
"received_events_url": "https://api.github.com/users/octocat/received_events",
92+
"type": "User",
93+
"site_admin": false
94+
},
95+
"change_status": {
96+
"deletions": 0,
97+
"additions": 180,
98+
"total": 180
99+
},
100+
"committed_at": "2010-04-14T02:15:15Z"
101+
}
102+
]
103+
}

spec/gist_tag_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
doc.output = Jekyll::Renderer.new(doc.site, doc).run
1010
end
1111

12+
before(:each) { ENV["JEKYLL_GITHUB_TOKEN"] = nil }
1213

1314
context "valid gist" do
1415
context "with user prefix" do
@@ -118,6 +119,37 @@
118119

119120
end
120121

122+
context "with token" do
123+
before { ENV["JEKYLL_GITHUB_TOKEN"] = "1234" }
124+
before {
125+
stub_request(:get, "https://api.github.com/gists/1342013").
126+
to_return(:status => 200, :body => fixture("single-file"), :headers => {"Content-Type" => "application/json"})
127+
}
128+
let(:gist_id) { "1342013" }
129+
let(:gist) { "page.gist_id" }
130+
let(:output) do
131+
doc.data['gist_id'] = gist_id
132+
doc.content = content
133+
doc.output = Jekyll::Renderer.new(doc.site, doc).run
134+
end
135+
136+
it "produces the noscript tag" do
137+
expect(output).to match(/<noscript><pre>contents of gist<\/pre><\/noscript>/)
138+
end
139+
140+
context "with a filename" do
141+
before {
142+
stub_request(:get, "https://api.github.com/gists/1342013").
143+
to_return(:status => 200, :body => fixture("multiple-files"), :headers => {"Content-Type" => "application/json"})
144+
}
145+
let(:content) { "{% gist 1342013 hello-world.rb %}" }
146+
147+
it "produces the noscript tag" do
148+
expect(output).to match(/<noscript><pre>puts &#39;hello world&#39;<\/pre><\/noscript>/)
149+
end
150+
end
151+
end
152+
121153
context "with noscript disabled" do
122154
let(:doc) { doc_with_content(content, { "gist" => { "noscript" => false } }) }
123155
let(:output) do

spec/spec_helper.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
require File.expand_path("../lib/jekyll-gist.rb", TEST_DIR)
88

99
Jekyll.logger.log_level = :error
10-
STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:')
1110

1211
RSpec.configure do |config|
1312
config.run_all_when_everything_filtered = true
@@ -42,4 +41,9 @@ def site(opts = {})
4241
}))
4342
Jekyll::Site.new(conf)
4443
end
44+
45+
def fixture(name)
46+
path = File.expand_path "./fixtures/#{name}.json", File.dirname(__FILE__)
47+
File.open(path).read
48+
end
4549
end

0 commit comments

Comments
 (0)