jekyll 0.5.7 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of jekyll might be problematic. Click here for more details.
- data/History.txt +88 -31
- data/LICENSE +21 -0
- data/README.textile +1 -9
- data/Rakefile +119 -51
- data/bin/jekyll +26 -2
- data/cucumber.yml +1 -0
- data/features/create_sites.feature +28 -10
- data/features/post_data.feature +7 -7
- data/features/site_configuration.feature +41 -1
- data/features/step_definitions/jekyll_steps.rb +13 -4
- data/jekyll.gemspec +125 -143
- data/lib/jekyll.rb +40 -20
- data/lib/jekyll/albino.rb +5 -7
- data/lib/jekyll/converter.rb +50 -0
- data/lib/jekyll/converters/identity.rb +22 -0
- data/lib/jekyll/converters/markdown.rb +77 -0
- data/lib/jekyll/converters/textile.rb +33 -0
- data/lib/jekyll/convertible.rb +18 -24
- data/lib/jekyll/errors.rb +6 -0
- data/lib/jekyll/generator.rb +7 -0
- data/lib/jekyll/generators/pagination.rb +87 -0
- data/lib/jekyll/{converters → migrators}/csv.rb +0 -0
- data/lib/jekyll/{converters → migrators}/mephisto.rb +0 -0
- data/lib/jekyll/{converters → migrators}/mt.rb +0 -0
- data/lib/jekyll/{converters → migrators}/textpattern.rb +0 -0
- data/lib/jekyll/{converters → migrators}/typo.rb +0 -0
- data/lib/jekyll/{converters → migrators}/wordpress.rb +1 -0
- data/lib/jekyll/page.rb +28 -11
- data/lib/jekyll/plugin.rb +76 -0
- data/lib/jekyll/post.rb +10 -8
- data/lib/jekyll/site.rb +40 -88
- data/lib/jekyll/static_file.rb +52 -4
- data/lib/jekyll/tags/highlight.rb +20 -9
- data/test/helper.rb +6 -0
- data/test/source/_posts/2010-01-09-date-override.textile +2 -0
- data/test/source/_posts/2010-01-09-time-override.textile +2 -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/sitemap.xml +27 -18
- data/test/test_configuration.rb +1 -1
- data/test/test_generated_site.rb +1 -1
- data/test/test_post.rb +63 -12
- data/test/test_site.rb +69 -7
- data/test/test_tags.rb +6 -14
- metadata +156 -52
- data/.gitignore +0 -6
- data/VERSION.yml +0 -5
- data/lib/jekyll/pager.rb +0 -45
data/lib/jekyll.rb
CHANGED
@@ -1,44 +1,65 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
1
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
2
|
+
|
3
|
+
# Require all of the Ruby files in the given directory.
|
4
|
+
#
|
5
|
+
# path - The String relative path from here to the directory.
|
6
|
+
#
|
7
|
+
# Returns nothing.
|
8
|
+
def require_all(path)
|
9
|
+
glob = File.join(File.dirname(__FILE__), path, '*.rb')
|
10
|
+
Dir[glob].each do |f|
|
11
|
+
require f
|
12
|
+
end
|
13
|
+
end
|
2
14
|
|
3
15
|
# rubygems
|
4
16
|
require 'rubygems'
|
5
17
|
|
6
|
-
#
|
18
|
+
# stdlib
|
7
19
|
require 'fileutils'
|
8
20
|
require 'time'
|
9
21
|
require 'yaml'
|
10
22
|
|
11
|
-
# stdlib
|
12
|
-
|
13
23
|
# 3rd party
|
14
24
|
require 'liquid'
|
15
|
-
require '
|
25
|
+
require 'maruku'
|
16
26
|
|
17
27
|
# internal requires
|
18
28
|
require 'jekyll/core_ext'
|
19
|
-
require 'jekyll/pager'
|
20
29
|
require 'jekyll/site'
|
21
30
|
require 'jekyll/convertible'
|
22
31
|
require 'jekyll/layout'
|
23
32
|
require 'jekyll/page'
|
24
33
|
require 'jekyll/post'
|
25
34
|
require 'jekyll/filters'
|
26
|
-
require 'jekyll/tags/highlight'
|
27
|
-
require 'jekyll/tags/include'
|
28
35
|
require 'jekyll/albino'
|
29
36
|
require 'jekyll/static_file'
|
37
|
+
require 'jekyll/errors'
|
38
|
+
|
39
|
+
# extensions
|
40
|
+
require 'jekyll/plugin'
|
41
|
+
require 'jekyll/converter'
|
42
|
+
require 'jekyll/generator'
|
43
|
+
require_all 'jekyll/converters'
|
44
|
+
require_all 'jekyll/generators'
|
45
|
+
require_all 'jekyll/tags'
|
30
46
|
|
31
47
|
module Jekyll
|
48
|
+
VERSION = '0.6.0'
|
49
|
+
|
32
50
|
# Default options. Overriden by values in _config.yml or command-line opts.
|
33
|
-
# (Strings rather symbols used for compatability with YAML)
|
51
|
+
# (Strings rather symbols used for compatability with YAML).
|
34
52
|
DEFAULTS = {
|
53
|
+
'safe' => false,
|
35
54
|
'auto' => false,
|
36
55
|
'server' => false,
|
37
56
|
'server_port' => 4000,
|
38
57
|
|
39
|
-
'source' =>
|
40
|
-
'destination' => File.join(
|
58
|
+
'source' => Dir.pwd,
|
59
|
+
'destination' => File.join(Dir.pwd, '_site'),
|
60
|
+
'plugins' => File.join(Dir.pwd, '_plugins'),
|
41
61
|
|
62
|
+
'future' => true,
|
42
63
|
'lsi' => false,
|
43
64
|
'pygments' => false,
|
44
65
|
'markdown' => 'maruku',
|
@@ -54,10 +75,13 @@ module Jekyll
|
|
54
75
|
}
|
55
76
|
|
56
77
|
# Generate a Jekyll configuration Hash by merging the default options
|
57
|
-
# with anything in _config.yml, and adding the given options on top
|
58
|
-
#
|
78
|
+
# with anything in _config.yml, and adding the given options on top.
|
79
|
+
#
|
80
|
+
# override - A Hash of config directives that override any options in both
|
81
|
+
# the defaults and the config file. See Jekyll::DEFAULTS for a
|
82
|
+
# list of option names and their defaults.
|
59
83
|
#
|
60
|
-
# Returns Hash
|
84
|
+
# Returns the final configuration Hash.
|
61
85
|
def self.configuration(override)
|
62
86
|
# _config.yml may override default source location, but until
|
63
87
|
# then, we need to know where to look for _config.yml
|
@@ -70,7 +94,8 @@ module Jekyll
|
|
70
94
|
raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
|
71
95
|
$stdout.puts "Configuration from #{config_file}"
|
72
96
|
rescue => err
|
73
|
-
$stderr.puts "WARNING: Could not read configuration.
|
97
|
+
$stderr.puts "WARNING: Could not read configuration. " +
|
98
|
+
"Using defaults (and options)."
|
74
99
|
$stderr.puts "\t" + err.to_s
|
75
100
|
config = {}
|
76
101
|
end
|
@@ -78,9 +103,4 @@ module Jekyll
|
|
78
103
|
# Merge DEFAULTS < _config.yml < override
|
79
104
|
Jekyll::DEFAULTS.deep_merge(config).deep_merge(override)
|
80
105
|
end
|
81
|
-
|
82
|
-
def self.version
|
83
|
-
yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
|
84
|
-
"#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
|
85
|
-
end
|
86
106
|
end
|
data/lib/jekyll/albino.rb
CHANGED
@@ -41,7 +41,6 @@
|
|
41
41
|
# Chris Wanstrath // chris@ozmm.org
|
42
42
|
# GitHub // http://github.com
|
43
43
|
#
|
44
|
-
require 'open4'
|
45
44
|
|
46
45
|
class Albino
|
47
46
|
@@bin = Rails.development? ? 'pygmentize' : '/usr/bin/pygmentize' rescue 'pygmentize'
|
@@ -61,11 +60,10 @@ class Albino
|
|
61
60
|
|
62
61
|
def execute(command)
|
63
62
|
output = ''
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
output =
|
68
|
-
[stdout, stderr].each { |io| io.close }
|
63
|
+
IO.popen(command, mode='r+') do |p|
|
64
|
+
p.write @target
|
65
|
+
p.close_write
|
66
|
+
output = p.read.strip
|
69
67
|
end
|
70
68
|
output
|
71
69
|
end
|
@@ -119,4 +117,4 @@ if $0 == __FILE__
|
|
119
117
|
assert_equal @syntaxer.colorize, Albino.colorize(__FILE__, :ruby)
|
120
118
|
end
|
121
119
|
end
|
122
|
-
end
|
120
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Jekyll
|
2
|
+
|
3
|
+
class Converter < Plugin
|
4
|
+
# Public: Get or set the pygments prefix. When an argument is specified,
|
5
|
+
# the prefix will be set. If no argument is specified, the current prefix
|
6
|
+
# will be returned.
|
7
|
+
#
|
8
|
+
# pygments_prefix - The String prefix (default: nil).
|
9
|
+
#
|
10
|
+
# Returns the String prefix.
|
11
|
+
def self.pygments_prefix(pygments_prefix = nil)
|
12
|
+
@pygments_prefix = pygments_prefix if pygments_prefix
|
13
|
+
@pygments_prefix
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Get or set the pygments suffix. When an argument is specified,
|
17
|
+
# the suffix will be set. If no argument is specified, the current suffix
|
18
|
+
# will be returned.
|
19
|
+
#
|
20
|
+
# pygments_suffix - The String suffix (default: nil).
|
21
|
+
#
|
22
|
+
# Returns the String suffix.
|
23
|
+
def self.pygments_suffix(pygments_suffix = nil)
|
24
|
+
@pygments_suffix = pygments_suffix if pygments_suffix
|
25
|
+
@pygments_suffix
|
26
|
+
end
|
27
|
+
|
28
|
+
# Initialize the converter.
|
29
|
+
#
|
30
|
+
# Returns an initialized Converter.
|
31
|
+
def initialize(config = {})
|
32
|
+
@config = config
|
33
|
+
end
|
34
|
+
|
35
|
+
# Get the pygments prefix.
|
36
|
+
#
|
37
|
+
# Returns the String prefix.
|
38
|
+
def pygments_prefix
|
39
|
+
self.class.pygments_prefix
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get the pygments suffix.
|
43
|
+
#
|
44
|
+
# Returns the String suffix.
|
45
|
+
def pygments_suffix
|
46
|
+
self.class.pygments_suffix
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Jekyll
|
2
|
+
|
3
|
+
class MarkdownConverter < Converter
|
4
|
+
safe true
|
5
|
+
|
6
|
+
pygments_prefix '\n'
|
7
|
+
pygments_suffix '\n'
|
8
|
+
|
9
|
+
def setup
|
10
|
+
return if @setup
|
11
|
+
# Set the Markdown interpreter (and Maruku self.config, if necessary)
|
12
|
+
case @config['markdown']
|
13
|
+
when 'rdiscount'
|
14
|
+
begin
|
15
|
+
require 'rdiscount'
|
16
|
+
rescue LoadError
|
17
|
+
STDERR.puts 'You are missing a library required for Markdown. Please run:'
|
18
|
+
STDERR.puts ' $ [sudo] gem install rdiscount'
|
19
|
+
raise FatalException.new("Missing dependency: rdiscount")
|
20
|
+
end
|
21
|
+
when 'maruku'
|
22
|
+
begin
|
23
|
+
require 'maruku'
|
24
|
+
|
25
|
+
if @config['maruku']['use_divs']
|
26
|
+
require 'maruku/ext/div'
|
27
|
+
STDERR.puts 'Maruku: Using extended syntax for div elements.'
|
28
|
+
end
|
29
|
+
|
30
|
+
if @config['maruku']['use_tex']
|
31
|
+
require 'maruku/ext/math'
|
32
|
+
STDERR.puts "Maruku: Using LaTeX extension. Images in `#{@config['maruku']['png_dir']}`."
|
33
|
+
|
34
|
+
# Switch off MathML output
|
35
|
+
MaRuKu::Globals[:html_math_output_mathml] = false
|
36
|
+
MaRuKu::Globals[:html_math_engine] = 'none'
|
37
|
+
|
38
|
+
# Turn on math to PNG support with blahtex
|
39
|
+
# Resulting PNGs stored in `images/latex`
|
40
|
+
MaRuKu::Globals[:html_math_output_png] = true
|
41
|
+
MaRuKu::Globals[:html_png_engine] = @config['maruku']['png_engine']
|
42
|
+
MaRuKu::Globals[:html_png_dir] = @config['maruku']['png_dir']
|
43
|
+
MaRuKu::Globals[:html_png_url] = @config['maruku']['png_url']
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
STDERR.puts 'You are missing a library required for Markdown. Please run:'
|
47
|
+
STDERR.puts ' $ [sudo] gem install maruku'
|
48
|
+
raise FatalException.new("Missing dependency: maruku")
|
49
|
+
end
|
50
|
+
else
|
51
|
+
STDERR.puts "Invalid Markdown processor: #{@config['markdown']}"
|
52
|
+
STDERR.puts " Valid options are [ maruku | rdiscount ]"
|
53
|
+
raise FatalException.new("Invalid Markdown process: #{@config['markdown']}")
|
54
|
+
end
|
55
|
+
@setup = true
|
56
|
+
end
|
57
|
+
|
58
|
+
def matches(ext)
|
59
|
+
ext =~ /(markdown|mkdn?|md)/i
|
60
|
+
end
|
61
|
+
|
62
|
+
def output_ext(ext)
|
63
|
+
".html"
|
64
|
+
end
|
65
|
+
|
66
|
+
def convert(content)
|
67
|
+
setup
|
68
|
+
case @config['markdown']
|
69
|
+
when 'rdiscount'
|
70
|
+
RDiscount.new(content).to_html
|
71
|
+
when 'maruku'
|
72
|
+
Maruku.new(content).to_html
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Jekyll
|
2
|
+
|
3
|
+
class TextileConverter < Converter
|
4
|
+
safe true
|
5
|
+
|
6
|
+
pygments_prefix '<notextile>'
|
7
|
+
pygments_suffix '</notextile>'
|
8
|
+
|
9
|
+
def setup
|
10
|
+
return if @setup
|
11
|
+
require 'redcloth'
|
12
|
+
@setup = true
|
13
|
+
rescue LoadError
|
14
|
+
STDERR.puts 'You are missing a library required for Textile. Please run:'
|
15
|
+
STDERR.puts ' $ [sudo] gem install RedCloth'
|
16
|
+
raise FatalException.new("Missing dependency: RedCloth")
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches(ext)
|
20
|
+
ext =~ /textile/i
|
21
|
+
end
|
22
|
+
|
23
|
+
def output_ext(ext)
|
24
|
+
".html"
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert(content)
|
28
|
+
setup
|
29
|
+
RedCloth.new(content).to_html
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/jekyll/convertible.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# Requires
|
5
5
|
# self.site -> Jekyll::Site
|
6
|
+
# self.content
|
6
7
|
# self.content=
|
7
8
|
# self.data=
|
8
9
|
# self.ext=
|
@@ -21,42 +22,34 @@ module Jekyll
|
|
21
22
|
# Returns nothing
|
22
23
|
def read_yaml(base, name)
|
23
24
|
self.content = File.read(File.join(base, name))
|
24
|
-
|
25
|
+
|
25
26
|
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
26
27
|
self.content = self.content[($1.size + $2.size)..-1]
|
27
|
-
|
28
|
+
|
28
29
|
self.data = YAML.load($1)
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
self.data ||= {}
|
32
33
|
end
|
33
34
|
|
34
|
-
# Transform the contents based on the
|
35
|
+
# Transform the contents based on the content type.
|
35
36
|
#
|
36
37
|
# Returns nothing
|
37
38
|
def transform
|
38
|
-
|
39
|
-
when 'textile'
|
40
|
-
self.ext = ".html"
|
41
|
-
self.content = self.site.textile(self.content)
|
42
|
-
when 'markdown'
|
43
|
-
self.ext = ".html"
|
44
|
-
self.content = self.site.markdown(self.content)
|
45
|
-
end
|
39
|
+
self.content = converter.convert(self.content)
|
46
40
|
end
|
47
41
|
|
48
|
-
# Determine
|
49
|
-
# extension
|
42
|
+
# Determine the extension depending on content_type
|
50
43
|
#
|
51
|
-
# Returns
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
# Returns the extensions for the output file
|
45
|
+
def output_ext
|
46
|
+
converter.output_ext(self.ext)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Determine which converter to use based on this convertible's
|
50
|
+
# extension
|
51
|
+
def converter
|
52
|
+
@converter ||= self.site.converters.find { |c| c.matches(self.ext) }
|
60
53
|
end
|
61
54
|
|
62
55
|
# Add any necessary layouts to this convertible document
|
@@ -68,7 +61,8 @@ module Jekyll
|
|
68
61
|
info = { :filters => [Jekyll::Filters], :registers => { :site => self.site } }
|
69
62
|
|
70
63
|
# render and transform content (this becomes the final content of the object)
|
71
|
-
payload["
|
64
|
+
payload["pygments_prefix"] = converter.pygments_prefix
|
65
|
+
payload["pygments_suffix"] = converter.pygments_suffix
|
72
66
|
self.content = Liquid::Template.parse(self.content).render(payload, info)
|
73
67
|
self.transform
|
74
68
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Jekyll
|
2
|
+
|
3
|
+
class Pagination < Generator
|
4
|
+
safe true
|
5
|
+
|
6
|
+
def generate(site)
|
7
|
+
site.pages.dup.each do |page|
|
8
|
+
paginate(site, page) if Pager.pagination_enabled?(site.config, page.name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Paginates the blog's posts. Renders the index.html file into paginated
|
13
|
+
# directories, ie: page2/index.html, page3/index.html, etc and adds more
|
14
|
+
# site-wide data.
|
15
|
+
# +page+ is the index.html Page that requires pagination
|
16
|
+
#
|
17
|
+
# {"paginator" => { "page" => <Number>,
|
18
|
+
# "per_page" => <Number>,
|
19
|
+
# "posts" => [<Post>],
|
20
|
+
# "total_posts" => <Number>,
|
21
|
+
# "total_pages" => <Number>,
|
22
|
+
# "previous_page" => <Number>,
|
23
|
+
# "next_page" => <Number> }}
|
24
|
+
def paginate(site, page)
|
25
|
+
all_posts = site.site_payload['site']['posts']
|
26
|
+
pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i)
|
27
|
+
(1..pages).each do |num_page|
|
28
|
+
pager = Pager.new(site.config, num_page, all_posts, pages)
|
29
|
+
if num_page > 1
|
30
|
+
newpage = Page.new(site, site.source, page.dir, page.name)
|
31
|
+
newpage.pager = pager
|
32
|
+
newpage.dir = File.join(page.dir, "page#{num_page}")
|
33
|
+
site.pages << newpage
|
34
|
+
else
|
35
|
+
page.pager = pager
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class Pager
|
43
|
+
attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page
|
44
|
+
|
45
|
+
def self.calculate_pages(all_posts, per_page)
|
46
|
+
num_pages = all_posts.size / per_page.to_i
|
47
|
+
num_pages = num_pages + 1 if all_posts.size % per_page.to_i != 0
|
48
|
+
num_pages
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.pagination_enabled?(config, file)
|
52
|
+
file == 'index.html' && !config['paginate'].nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(config, page, all_posts, num_pages = nil)
|
56
|
+
@page = page
|
57
|
+
@per_page = config['paginate'].to_i
|
58
|
+
@total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page)
|
59
|
+
|
60
|
+
if @page > @total_pages
|
61
|
+
raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
|
62
|
+
end
|
63
|
+
|
64
|
+
init = (@page - 1) * @per_page
|
65
|
+
offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1)
|
66
|
+
|
67
|
+
@total_posts = all_posts.size
|
68
|
+
@posts = all_posts[init..offset]
|
69
|
+
@previous_page = @page != 1 ? @page - 1 : nil
|
70
|
+
@next_page = @page != @total_pages ? @page + 1 : nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_liquid
|
74
|
+
{
|
75
|
+
'page' => page,
|
76
|
+
'per_page' => per_page,
|
77
|
+
'posts' => posts,
|
78
|
+
'total_posts' => total_posts,
|
79
|
+
'total_pages' => total_pages,
|
80
|
+
'previous_page' => previous_page,
|
81
|
+
'next_page' => next_page
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|