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.

Files changed (48) hide show
  1. data/History.txt +88 -31
  2. data/LICENSE +21 -0
  3. data/README.textile +1 -9
  4. data/Rakefile +119 -51
  5. data/bin/jekyll +26 -2
  6. data/cucumber.yml +1 -0
  7. data/features/create_sites.feature +28 -10
  8. data/features/post_data.feature +7 -7
  9. data/features/site_configuration.feature +41 -1
  10. data/features/step_definitions/jekyll_steps.rb +13 -4
  11. data/jekyll.gemspec +125 -143
  12. data/lib/jekyll.rb +40 -20
  13. data/lib/jekyll/albino.rb +5 -7
  14. data/lib/jekyll/converter.rb +50 -0
  15. data/lib/jekyll/converters/identity.rb +22 -0
  16. data/lib/jekyll/converters/markdown.rb +77 -0
  17. data/lib/jekyll/converters/textile.rb +33 -0
  18. data/lib/jekyll/convertible.rb +18 -24
  19. data/lib/jekyll/errors.rb +6 -0
  20. data/lib/jekyll/generator.rb +7 -0
  21. data/lib/jekyll/generators/pagination.rb +87 -0
  22. data/lib/jekyll/{converters → migrators}/csv.rb +0 -0
  23. data/lib/jekyll/{converters → migrators}/mephisto.rb +0 -0
  24. data/lib/jekyll/{converters → migrators}/mt.rb +0 -0
  25. data/lib/jekyll/{converters → migrators}/textpattern.rb +0 -0
  26. data/lib/jekyll/{converters → migrators}/typo.rb +0 -0
  27. data/lib/jekyll/{converters → migrators}/wordpress.rb +1 -0
  28. data/lib/jekyll/page.rb +28 -11
  29. data/lib/jekyll/plugin.rb +76 -0
  30. data/lib/jekyll/post.rb +10 -8
  31. data/lib/jekyll/site.rb +40 -88
  32. data/lib/jekyll/static_file.rb +52 -4
  33. data/lib/jekyll/tags/highlight.rb +20 -9
  34. data/test/helper.rb +6 -0
  35. data/test/source/_posts/2010-01-09-date-override.textile +2 -0
  36. data/test/source/_posts/2010-01-09-time-override.textile +2 -0
  37. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  38. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  39. data/test/source/sitemap.xml +27 -18
  40. data/test/test_configuration.rb +1 -1
  41. data/test/test_generated_site.rb +1 -1
  42. data/test/test_post.rb +63 -12
  43. data/test/test_site.rb +69 -7
  44. data/test/test_tags.rb +6 -14
  45. metadata +156 -52
  46. data/.gitignore +0 -6
  47. data/VERSION.yml +0 -5
  48. data/lib/jekyll/pager.rb +0 -45
@@ -1,44 +1,65 @@
1
- $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
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
- # core
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 'redcloth'
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('.', '_site'),
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
- # +override+ is a Hash of config directives
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. Using defaults (and options)."
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
@@ -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
- Open4.popen4(command) do |pid, stdin, stdout, stderr|
65
- stdin.puts @target
66
- stdin.close
67
- output = stdout.read.strip
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,22 @@
1
+ module Jekyll
2
+
3
+ class IdentityConverter < Converter
4
+ safe true
5
+
6
+ priority :lowest
7
+
8
+ def matches(ext)
9
+ true
10
+ end
11
+
12
+ def output_ext(ext)
13
+ ext
14
+ end
15
+
16
+ def convert(content)
17
+ content
18
+ end
19
+
20
+ end
21
+
22
+ 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
@@ -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 file extension.
35
+ # Transform the contents based on the content type.
35
36
  #
36
37
  # Returns nothing
37
38
  def transform
38
- case self.content_type
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 which formatting engine to use based on this convertible's
49
- # extension
42
+ # Determine the extension depending on content_type
50
43
  #
51
- # Returns one of :textile, :markdown or :unknown
52
- def content_type
53
- case self.ext[1..-1]
54
- when /textile/i
55
- return 'textile'
56
- when /markdown/i, /mkdn/i, /md/i, /mkd/i
57
- return 'markdown'
58
- end
59
- return 'unknown'
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["content_type"] = self.content_type
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,6 @@
1
+ module Jekyll
2
+
3
+ class FatalException < StandardError
4
+ end
5
+
6
+ end
@@ -0,0 +1,7 @@
1
+ module Jekyll
2
+
3
+ class Generator < Plugin
4
+
5
+ end
6
+
7
+ end
@@ -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