fagiani-jekyll 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +284 -0
- data/LICENSE +21 -0
- data/README.textile +41 -0
- data/Rakefile +159 -0
- data/bin/jekyll +192 -0
- data/cucumber.yml +1 -0
- data/features/create_sites.feature +94 -0
- data/features/embed_filters.feature +60 -0
- data/features/markdown.feature +30 -0
- data/features/pagination.feature +27 -0
- data/features/permalinks.feature +65 -0
- data/features/post_data.feature +153 -0
- data/features/site_configuration.feature +126 -0
- data/features/site_data.feature +82 -0
- data/features/step_definitions/jekyll_steps.rb +145 -0
- data/features/support/env.rb +16 -0
- data/jekyll.gemspec +140 -0
- data/lib/jekyll.rb +125 -0
- data/lib/jekyll/albino.rb +120 -0
- data/lib/jekyll/converter.rb +50 -0
- data/lib/jekyll/converters/identity.rb +22 -0
- data/lib/jekyll/converters/markdown.rb +113 -0
- data/lib/jekyll/converters/textile.rb +33 -0
- data/lib/jekyll/convertible.rb +98 -0
- data/lib/jekyll/core_ext.rb +52 -0
- data/lib/jekyll/errors.rb +6 -0
- data/lib/jekyll/filters.rb +53 -0
- data/lib/jekyll/generator.rb +7 -0
- data/lib/jekyll/generators/pagination.rb +87 -0
- data/lib/jekyll/layout.rb +36 -0
- data/lib/jekyll/migrators/csv.rb +26 -0
- data/lib/jekyll/migrators/drupal.rb +86 -0
- data/lib/jekyll/migrators/marley.rb +53 -0
- data/lib/jekyll/migrators/mephisto.rb +79 -0
- data/lib/jekyll/migrators/mt.rb +77 -0
- data/lib/jekyll/migrators/textpattern.rb +50 -0
- data/lib/jekyll/migrators/typo.rb +49 -0
- data/lib/jekyll/migrators/wordpress.com.rb +38 -0
- data/lib/jekyll/migrators/wordpress.rb +56 -0
- data/lib/jekyll/page.rb +134 -0
- data/lib/jekyll/plugin.rb +76 -0
- data/lib/jekyll/post.rb +244 -0
- data/lib/jekyll/site.rb +273 -0
- data/lib/jekyll/static_file.rb +75 -0
- data/lib/jekyll/tags/highlight.rb +73 -0
- data/lib/jekyll/tags/include.rb +37 -0
- data/test/helper.rb +34 -0
- data/test/source/.htaccess +8 -0
- data/test/source/_includes/sig.markdown +3 -0
- data/test/source/_layouts/default.html +27 -0
- data/test/source/_layouts/simple.html +1 -0
- data/test/source/_posts/2008-02-02-not-published.textile +8 -0
- data/test/source/_posts/2008-02-02-published.textile +8 -0
- data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
- data/test/source/_posts/2008-11-21-complex.textile +8 -0
- data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
- data/test/source/_posts/2008-12-13-include.markdown +8 -0
- data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
- data/test/source/_posts/2009-01-27-categories.textile +7 -0
- data/test/source/_posts/2009-01-27-category.textile +7 -0
- data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
- data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
- data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
- data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
- data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
- data/test/source/_posts/2009-05-18-tag.textile +6 -0
- data/test/source/_posts/2009-05-18-tags.textile +9 -0
- data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
- data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
- data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
- data/test/source/_posts/2010-01-09-date-override.textile +7 -0
- data/test/source/_posts/2010-01-09-time-override.textile +7 -0
- data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
- data/test/source/_posts/2010-01-16-override-data.textile +4 -0
- data/test/source/about.html +6 -0
- data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
- data/test/source/contacts.html +5 -0
- data/test/source/css/screen.css +76 -0
- data/test/source/deal.with.dots.html +7 -0
- data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
- data/test/source/index.html +22 -0
- data/test/source/sitemap.xml +32 -0
- data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
- data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
- data/test/suite.rb +9 -0
- data/test/test_configuration.rb +29 -0
- data/test/test_core_ext.rb +66 -0
- data/test/test_filters.rb +53 -0
- data/test/test_generated_site.rb +72 -0
- data/test/test_kramdown.rb +23 -0
- data/test/test_page.rb +117 -0
- data/test/test_pager.rb +113 -0
- data/test/test_post.rb +396 -0
- data/test/test_rdiscount.rb +18 -0
- data/test/test_site.rb +186 -0
- data/test/test_tags.rb +127 -0
- metadata +332 -0
data/lib/jekyll/site.rb
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
|
|
3
|
+
class Site
|
|
4
|
+
attr_accessor :config, :layouts, :posts, :pages, :static_files,
|
|
5
|
+
:categories, :exclude, :source, :dest, :lsi, :pygments,
|
|
6
|
+
:permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts
|
|
7
|
+
|
|
8
|
+
attr_accessor :converters, :generators
|
|
9
|
+
|
|
10
|
+
# Initialize the site
|
|
11
|
+
# +config+ is a Hash containing site configurations details
|
|
12
|
+
#
|
|
13
|
+
# Returns <Site>
|
|
14
|
+
def initialize(config)
|
|
15
|
+
self.config = config.clone
|
|
16
|
+
|
|
17
|
+
self.safe = config['safe']
|
|
18
|
+
self.source = File.expand_path(config['source'])
|
|
19
|
+
self.dest = File.expand_path(config['destination'])
|
|
20
|
+
self.plugins = File.expand_path(config['plugins'])
|
|
21
|
+
self.lsi = config['lsi']
|
|
22
|
+
self.pygments = config['pygments']
|
|
23
|
+
self.permalink_style = config['permalink'].to_sym
|
|
24
|
+
self.exclude = config['exclude'] || []
|
|
25
|
+
self.future = config['future']
|
|
26
|
+
self.limit_posts = config['limit_posts'] || nil
|
|
27
|
+
|
|
28
|
+
self.reset
|
|
29
|
+
self.setup
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reset
|
|
33
|
+
self.time = if self.config['time']
|
|
34
|
+
Time.parse(self.config['time'].to_s)
|
|
35
|
+
else
|
|
36
|
+
Time.now
|
|
37
|
+
end
|
|
38
|
+
self.layouts = {}
|
|
39
|
+
self.posts = []
|
|
40
|
+
self.pages = []
|
|
41
|
+
self.static_files = []
|
|
42
|
+
self.categories = Hash.new { |hash, key| hash[key] = [] }
|
|
43
|
+
self.tags = Hash.new { |hash, key| hash[key] = [] }
|
|
44
|
+
|
|
45
|
+
raise ArgumentError, "Limit posts must be nil or >= 1" if !self.limit_posts.nil? && self.limit_posts < 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def setup
|
|
49
|
+
require 'classifier' if self.lsi
|
|
50
|
+
|
|
51
|
+
# If safe mode is off, load in any ruby files under the plugins
|
|
52
|
+
# directory.
|
|
53
|
+
unless self.safe
|
|
54
|
+
Dir[File.join(self.plugins, "**/*.rb")].each do |f|
|
|
55
|
+
require f
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
self.converters = Jekyll::Converter.subclasses.select do |c|
|
|
60
|
+
!self.safe || c.safe
|
|
61
|
+
end.map do |c|
|
|
62
|
+
c.new(self.config)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
self.generators = Jekyll::Generator.subclasses.select do |c|
|
|
66
|
+
!self.safe || c.safe
|
|
67
|
+
end.map do |c|
|
|
68
|
+
c.new(self.config)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Do the actual work of processing the site and generating the
|
|
73
|
+
# real deal. 5 phases; reset, read, generate, render, write. This allows
|
|
74
|
+
# rendering to have full site payload available.
|
|
75
|
+
#
|
|
76
|
+
# Returns nothing
|
|
77
|
+
def process
|
|
78
|
+
self.reset
|
|
79
|
+
self.read
|
|
80
|
+
self.generate
|
|
81
|
+
self.render
|
|
82
|
+
self.cleanup
|
|
83
|
+
self.write
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def read
|
|
87
|
+
self.read_layouts # existing implementation did this at top level only so preserved that
|
|
88
|
+
self.read_directories
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Read all the files in <source>/<dir>/_layouts and create a new Layout
|
|
92
|
+
# object with each one.
|
|
93
|
+
#
|
|
94
|
+
# Returns nothing
|
|
95
|
+
def read_layouts(dir = '')
|
|
96
|
+
base = File.join(self.source, dir, "_layouts")
|
|
97
|
+
return unless File.exists?(base)
|
|
98
|
+
entries = []
|
|
99
|
+
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
|
|
100
|
+
|
|
101
|
+
entries.each do |f|
|
|
102
|
+
name = f.split(".")[0..-2].join(".")
|
|
103
|
+
self.layouts[name] = Layout.new(self, base, f)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Read all the files in <source>/<dir>/_posts and create a new Post
|
|
108
|
+
# object with each one.
|
|
109
|
+
#
|
|
110
|
+
# Returns nothing
|
|
111
|
+
def read_posts(dir)
|
|
112
|
+
base = File.join(self.source, dir, '_posts')
|
|
113
|
+
return unless File.exists?(base)
|
|
114
|
+
entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
|
|
115
|
+
|
|
116
|
+
# first pass processes, but does not yet render post content
|
|
117
|
+
entries.each do |f|
|
|
118
|
+
if Post.valid?(f)
|
|
119
|
+
post = Post.new(self, self.source, dir, f)
|
|
120
|
+
|
|
121
|
+
if post.published && (self.future || post.date <= self.time)
|
|
122
|
+
self.posts << post
|
|
123
|
+
post.categories.each { |c| self.categories[c] << post }
|
|
124
|
+
post.tags.each { |c| self.tags[c] << post }
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
self.posts.sort!
|
|
130
|
+
|
|
131
|
+
# limit the posts if :limit_posts option is set
|
|
132
|
+
self.posts = self.posts[-limit_posts, limit_posts] if limit_posts
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def generate
|
|
136
|
+
self.generators.each do |generator|
|
|
137
|
+
generator.generate(self)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def render
|
|
142
|
+
self.posts.each do |post|
|
|
143
|
+
post.render(self.layouts, site_payload)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
self.pages.each do |page|
|
|
147
|
+
page.render(self.layouts, site_payload)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
|
151
|
+
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
|
152
|
+
rescue Errno::ENOENT => e
|
|
153
|
+
# ignore missing layout dir
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Remove orphaned files and empty directories in destination
|
|
157
|
+
#
|
|
158
|
+
# Returns nothing
|
|
159
|
+
def cleanup
|
|
160
|
+
# all files and directories in destination, including hidden ones
|
|
161
|
+
dest_files = []
|
|
162
|
+
Dir.glob(File.join(self.dest, "**", "*"), File::FNM_DOTMATCH) do |file|
|
|
163
|
+
dest_files << file unless file =~ /\/\.{1,2}$/
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# files to be written
|
|
167
|
+
files = []
|
|
168
|
+
self.posts.each do |post|
|
|
169
|
+
files << post.destination(self.dest)
|
|
170
|
+
end
|
|
171
|
+
self.pages.each do |page|
|
|
172
|
+
files << page.destination(self.dest)
|
|
173
|
+
end
|
|
174
|
+
self.static_files.each do |sf|
|
|
175
|
+
files << sf.destination(self.dest)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# adding files' parent directories
|
|
179
|
+
files.each { |file| files << File.dirname(file) unless files.include? File.dirname(file) }
|
|
180
|
+
|
|
181
|
+
obsolete_files = dest_files - files
|
|
182
|
+
|
|
183
|
+
FileUtils.rm_rf(obsolete_files)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Write static files, pages and posts
|
|
187
|
+
#
|
|
188
|
+
# Returns nothing
|
|
189
|
+
def write
|
|
190
|
+
self.posts.each do |post|
|
|
191
|
+
post.write(self.dest)
|
|
192
|
+
end
|
|
193
|
+
self.pages.each do |page|
|
|
194
|
+
page.write(self.dest)
|
|
195
|
+
end
|
|
196
|
+
self.static_files.each do |sf|
|
|
197
|
+
sf.write(self.dest)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Reads the directories and finds posts, pages and static files that will
|
|
202
|
+
# become part of the valid site according to the rules in +filter_entries+.
|
|
203
|
+
# The +dir+ String is a relative path used to call this method
|
|
204
|
+
# recursively as it descends through directories
|
|
205
|
+
#
|
|
206
|
+
# Returns nothing
|
|
207
|
+
def read_directories(dir = '')
|
|
208
|
+
base = File.join(self.source, dir)
|
|
209
|
+
entries = filter_entries(Dir.entries(base))
|
|
210
|
+
|
|
211
|
+
self.read_posts(dir)
|
|
212
|
+
|
|
213
|
+
entries.each do |f|
|
|
214
|
+
f_abs = File.join(base, f)
|
|
215
|
+
f_rel = File.join(dir, f)
|
|
216
|
+
if File.directory?(f_abs)
|
|
217
|
+
next if self.dest.sub(/\/$/, '') == f_abs
|
|
218
|
+
read_directories(f_rel)
|
|
219
|
+
elsif !File.symlink?(f_abs)
|
|
220
|
+
first3 = File.open(f_abs) { |fd| fd.read(3) }
|
|
221
|
+
if first3 == "---"
|
|
222
|
+
# file appears to have a YAML header so process it as a page
|
|
223
|
+
pages << Page.new(self, self.source, dir, f)
|
|
224
|
+
else
|
|
225
|
+
# otherwise treat it as a static file
|
|
226
|
+
static_files << StaticFile.new(self, self.source, dir, f)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Constructs a hash map of Posts indexed by the specified Post attribute
|
|
233
|
+
#
|
|
234
|
+
# Returns {post_attr => [<Post>]}
|
|
235
|
+
def post_attr_hash(post_attr)
|
|
236
|
+
# Build a hash map based on the specified post attribute ( post attr => array of posts )
|
|
237
|
+
# then sort each array in reverse order
|
|
238
|
+
hash = Hash.new { |hash, key| hash[key] = Array.new }
|
|
239
|
+
self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
|
|
240
|
+
hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
|
|
241
|
+
return hash
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# The Hash payload containing site-wide data
|
|
245
|
+
#
|
|
246
|
+
# Returns {"site" => {"time" => <Time>,
|
|
247
|
+
# "posts" => [<Post>],
|
|
248
|
+
# "pages" => [<Page>],
|
|
249
|
+
# "categories" => [<Post>]}
|
|
250
|
+
def site_payload
|
|
251
|
+
{"site" => self.config.merge({
|
|
252
|
+
"time" => self.time,
|
|
253
|
+
"posts" => self.posts.sort { |a,b| b <=> a },
|
|
254
|
+
"pages" => self.pages,
|
|
255
|
+
"html_pages" => self.pages.reject { |page| !page.html? },
|
|
256
|
+
"categories" => post_attr_hash('categories'),
|
|
257
|
+
"tags" => post_attr_hash('tags')})}
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Filter out any files/directories that are hidden or backup files (start
|
|
261
|
+
# with "." or "#" or end with "~"), or contain site content (start with "_"),
|
|
262
|
+
# or are excluded in the site configuration, unless they are web server
|
|
263
|
+
# files such as '.htaccess'
|
|
264
|
+
def filter_entries(entries)
|
|
265
|
+
entries = entries.reject do |e|
|
|
266
|
+
unless ['.htaccess'].include?(e)
|
|
267
|
+
['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
end
|
|
273
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
|
|
3
|
+
class StaticFile
|
|
4
|
+
@@mtimes = Hash.new # the cache of last modification times [path] -> mtime
|
|
5
|
+
|
|
6
|
+
# Initialize a new StaticFile.
|
|
7
|
+
# +site+ is the Site
|
|
8
|
+
# +base+ is the String path to the <source>
|
|
9
|
+
# +dir+ is the String path between <source> and the file
|
|
10
|
+
# +name+ is the String filename of the file
|
|
11
|
+
#
|
|
12
|
+
# Returns <StaticFile>
|
|
13
|
+
def initialize(site, base, dir, name)
|
|
14
|
+
@site = site
|
|
15
|
+
@base = base
|
|
16
|
+
@dir = dir
|
|
17
|
+
@name = name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Obtains source file path.
|
|
21
|
+
#
|
|
22
|
+
# Returns source file path.
|
|
23
|
+
def path
|
|
24
|
+
File.join(@base, @dir, @name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Obtain destination path.
|
|
28
|
+
# +dest+ is the String path to the destination dir
|
|
29
|
+
#
|
|
30
|
+
# Returns destination file path.
|
|
31
|
+
def destination(dest)
|
|
32
|
+
File.join(dest, @dir, @name)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Obtain mtime of the source path.
|
|
36
|
+
#
|
|
37
|
+
# Returns last modifiaction time for this file.
|
|
38
|
+
def mtime
|
|
39
|
+
File.stat(path).mtime.to_i
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Is source path modified?
|
|
43
|
+
#
|
|
44
|
+
# Returns true if modified since last write.
|
|
45
|
+
def modified?
|
|
46
|
+
@@mtimes[path] != mtime
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Write the static file to the destination directory (if modified).
|
|
50
|
+
# +dest+ is the String path to the destination dir
|
|
51
|
+
#
|
|
52
|
+
# Returns false if the file was not modified since last time (no-op).
|
|
53
|
+
def write(dest)
|
|
54
|
+
dest_path = destination(dest)
|
|
55
|
+
|
|
56
|
+
return false if File.exist? dest_path and !modified?
|
|
57
|
+
@@mtimes[path] = mtime
|
|
58
|
+
|
|
59
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
60
|
+
FileUtils.cp(path, dest_path)
|
|
61
|
+
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Reset the mtimes cache (for testing purposes).
|
|
66
|
+
#
|
|
67
|
+
# Returns nothing.
|
|
68
|
+
def self.reset_cache
|
|
69
|
+
@@mtimes = Hash.new
|
|
70
|
+
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
|
|
3
|
+
class HighlightBlock < Liquid::Block
|
|
4
|
+
include Liquid::StandardFilters
|
|
5
|
+
|
|
6
|
+
# we need a language, but the linenos argument is optional.
|
|
7
|
+
SYNTAX = /(\w+)\s?([\w\s=]+)*/
|
|
8
|
+
|
|
9
|
+
def initialize(tag_name, markup, tokens)
|
|
10
|
+
super
|
|
11
|
+
if markup =~ SYNTAX
|
|
12
|
+
@lang = $1
|
|
13
|
+
if defined? $2
|
|
14
|
+
tmp_options = {}
|
|
15
|
+
$2.split.each do |opt|
|
|
16
|
+
key, value = opt.split('=')
|
|
17
|
+
if value.nil?
|
|
18
|
+
if key == 'linenos'
|
|
19
|
+
value = 'inline'
|
|
20
|
+
else
|
|
21
|
+
value = true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
tmp_options[key] = value
|
|
25
|
+
end
|
|
26
|
+
tmp_options = tmp_options.to_a.collect { |opt| opt.join('=') }
|
|
27
|
+
# additional options to pass to Albino.
|
|
28
|
+
@options = { 'O' => tmp_options.join(',') }
|
|
29
|
+
else
|
|
30
|
+
@options = {}
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
raise SyntaxError.new("Syntax Error in 'highlight' - Valid syntax: highlight <lang> [linenos]")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def render(context)
|
|
38
|
+
if context.registers[:site].pygments
|
|
39
|
+
render_pygments(context, super.join)
|
|
40
|
+
else
|
|
41
|
+
render_codehighlighter(context, super.join)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def render_pygments(context, code)
|
|
46
|
+
output = add_code_tags(Albino.new(code, @lang).to_s(@options), @lang)
|
|
47
|
+
output = context["pygments_prefix"] + output if context["pygments_prefix"]
|
|
48
|
+
output = output + context["pygments_suffix"] if context["pygments_suffix"]
|
|
49
|
+
output
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def render_codehighlighter(context, code)
|
|
53
|
+
#The div is required because RDiscount blows ass
|
|
54
|
+
<<-HTML
|
|
55
|
+
<div>
|
|
56
|
+
<pre>
|
|
57
|
+
<code class='#{@lang}'>#{h(code).strip}</code>
|
|
58
|
+
</pre>
|
|
59
|
+
</div>
|
|
60
|
+
HTML
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def add_code_tags(code, lang)
|
|
64
|
+
# Add nested <code> tags to code blocks
|
|
65
|
+
code = code.sub(/<pre>/,'<pre><code class="' + lang + '">')
|
|
66
|
+
code = code.sub(/<\/pre>/,"</code></pre>")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
Liquid::Template.register_tag('highlight', Jekyll::HighlightBlock)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
|
|
3
|
+
class IncludeTag < Liquid::Tag
|
|
4
|
+
def initialize(tag_name, file, tokens)
|
|
5
|
+
super
|
|
6
|
+
@file = file.strip
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render(context)
|
|
10
|
+
includes_dir = File.join(context.registers[:site].source, '_includes')
|
|
11
|
+
|
|
12
|
+
if File.symlink?(includes_dir)
|
|
13
|
+
return "Includes directory '#{includes_dir}' cannot be a symlink"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if @file !~ /^[a-zA-Z0-9_\/\.-]+$/ || @file =~ /\.\// || @file =~ /\/\./
|
|
17
|
+
return "Include file '#{@file}' contains invalid characters or sequences"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
Dir.chdir(includes_dir) do
|
|
21
|
+
choices = Dir['**/*'].reject { |x| File.symlink?(x) }
|
|
22
|
+
if choices.include?(@file)
|
|
23
|
+
source = File.read(@file)
|
|
24
|
+
partial = Liquid::Template.parse(source)
|
|
25
|
+
context.stack do
|
|
26
|
+
partial.render(context)
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
"Included file '#{@file}' not found in _includes directory"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Liquid::Template.register_tag('include', Jekyll::IncludeTag)
|