jekyll 0.10.0 → 0.11.0

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.

Potentially problematic release.


This version of jekyll might be problematic. Click here for more details.

Files changed (64) hide show
  1. data/Gemfile +2 -0
  2. data/History.txt +20 -1
  3. data/README.textile +1 -1
  4. data/Rakefile +2 -0
  5. data/bin/jekyll +92 -2
  6. data/doc/output/book.html +574 -0
  7. data/doc/output/ch00-preface.asc +41 -0
  8. data/doc/output/ch01-quick-start.asc +153 -0
  9. data/doc/output/ch02-directory-layout.asc +90 -0
  10. data/doc/output/stylesheets/handbookish-quirks.css +0 -0
  11. data/doc/output/stylesheets/handbookish.css +231 -0
  12. data/doc/output/stylesheets/scribe-quirks.css +0 -0
  13. data/doc/output/stylesheets/scribe.css +177 -0
  14. data/features/post_data.feature +2 -2
  15. data/features/site_configuration.feature +7 -0
  16. data/features/support/env.rb +3 -0
  17. data/g.pl +48 -0
  18. data/jekyll.gemspec +35 -16
  19. data/lib/jekyll.rb +11 -4
  20. data/lib/jekyll/converters/markdown.rb +14 -2
  21. data/lib/jekyll/converters/textile.rb +2 -1
  22. data/lib/jekyll/convertible.rb +34 -19
  23. data/lib/jekyll/filters.rb +66 -1
  24. data/lib/jekyll/generators/pagination.rb +33 -7
  25. data/lib/jekyll/layout.rb +18 -10
  26. data/lib/jekyll/migrators/csv.rb +3 -3
  27. data/lib/jekyll/migrators/drupal.rb +12 -6
  28. data/lib/jekyll/migrators/enki.rb +49 -0
  29. data/lib/jekyll/migrators/marley.rb +0 -1
  30. data/lib/jekyll/migrators/mephisto.rb +17 -12
  31. data/lib/jekyll/migrators/mt.rb +26 -17
  32. data/lib/jekyll/migrators/posterous.rb +68 -0
  33. data/lib/jekyll/migrators/textpattern.rb +15 -8
  34. data/lib/jekyll/migrators/tumblr.rb +119 -0
  35. data/lib/jekyll/migrators/typo.rb +8 -6
  36. data/lib/jekyll/migrators/wordpress.rb +23 -16
  37. data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
  38. data/lib/jekyll/page.rb +56 -35
  39. data/lib/jekyll/plugin.rb +1 -0
  40. data/lib/jekyll/post.rb +25 -14
  41. data/lib/jekyll/site.rb +138 -80
  42. data/lib/jekyll/static_file.rb +12 -15
  43. data/lib/jekyll/tags/highlight.rb +5 -5
  44. data/output/stylesheets/scribe-quirks.css +0 -0
  45. data/output/stylesheets/scribe.css +177 -0
  46. data/test/helper.rb +3 -3
  47. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  48. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  49. data/test/suite.rb +3 -1
  50. data/test/test_configuration.rb +1 -1
  51. data/test/test_core_ext.rb +1 -1
  52. data/test/test_filters.rb +10 -1
  53. data/test/test_generated_site.rb +2 -2
  54. data/test/test_kramdown.rb +1 -1
  55. data/test/test_page.rb +1 -1
  56. data/test/test_pager.rb +1 -1
  57. data/test/test_post.rb +49 -2
  58. data/test/test_rdiscount.rb +1 -1
  59. data/test/test_redcarpet.rb +21 -0
  60. data/test/test_site.rb +1 -1
  61. data/test/test_tags.rb +14 -1
  62. metadata +104 -38
  63. data/lib/jekyll/albino.rb +0 -120
  64. data/lib/jekyll/migrators/wordpress.com.rb +0 -38
@@ -3,7 +3,6 @@ require 'fileutils'
3
3
 
4
4
  module Jekyll
5
5
  module Marley
6
-
7
6
  def self.regexp
8
7
  { :id => /^\d{0,4}-{0,1}(.*)$/,
9
8
  :title => /^#\s*(.*)\s+$/,
@@ -36,11 +36,22 @@ module Jekyll
36
36
  # This query will pull blog posts from all entries across all blogs. If
37
37
  # you've got unpublished, deleted or otherwise hidden posts please sift
38
38
  # through the created posts to make sure nothing is accidently published.
39
-
40
- QUERY = "SELECT id, permalink, body, published_at, title FROM contents WHERE user_id = 1 AND type = 'Article' AND published_at IS NOT NULL ORDER BY published_at"
39
+ QUERY = "SELECT id, \
40
+ permalink, \
41
+ body, \
42
+ published_at, \
43
+ title \
44
+ FROM contents \
45
+ WHERE user_id = 1 AND \
46
+ type = 'Article' AND \
47
+ published_at IS NOT NULL \
48
+ ORDER BY published_at"
41
49
 
42
50
  def self.process(dbname, user, pass, host = 'localhost')
43
- db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
51
+ db = Sequel.mysql(dbname, :user => user,
52
+ :password => pass,
53
+ :host => host,
54
+ :encoding => 'utf8')
44
55
 
45
56
  FileUtils.mkdir_p "_posts"
46
57
 
@@ -49,16 +60,10 @@ module Jekyll
49
60
  slug = post[:permalink]
50
61
  date = post[:published_at]
51
62
  content = post[:body]
52
- # more_content = ''
53
-
54
- # Be sure to include the body and extended body.
55
- # if more_content != nil
56
- # content = content + " \n" + more_content
57
- # end
58
63
 
59
- # Ideally, this script would determine the post format (markdown, html
60
- # , etc) and create files with proper extensions. At this point it
61
- # just assumes that markdown will be acceptable.
64
+ # Ideally, this script would determine the post format (markdown,
65
+ # html, etc) and create files with proper extensions. At this point
66
+ # it just assumes that markdown will be acceptable.
62
67
  name = [date.year, date.month, date.day, slug].join('-') + ".markdown"
63
68
 
64
69
  data = {
@@ -18,7 +18,14 @@ module Jekyll
18
18
  # This query will pull blog posts from all entries across all blogs. If
19
19
  # you've got unpublished, deleted or otherwise hidden posts please sift
20
20
  # through the created posts to make sure nothing is accidently published.
21
- QUERY = "SELECT entry_id, entry_basename, entry_text, entry_text_more, entry_authored_on, entry_title, entry_convert_breaks FROM mt_entry"
21
+ QUERY = "SELECT entry_id, \
22
+ entry_basename, \
23
+ entry_text, \
24
+ entry_text_more, \
25
+ entry_authored_on, \
26
+ entry_title, \
27
+ entry_convert_breaks \
28
+ FROM mt_entry"
22
29
 
23
30
  def self.process(dbname, user, pass, host = 'localhost')
24
31
  db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
@@ -38,17 +45,18 @@ module Jekyll
38
45
  content = content + " \n" + more_content
39
46
  end
40
47
 
41
- # Ideally, this script would determine the post format (markdown, html
42
- # , etc) and create files with proper extensions. At this point it
43
- # just assumes that markdown will be acceptable.
44
- name = [date.year, date.month, date.day, slug].join('-') + '.' + self.suffix(entry_convert_breaks)
48
+ # Ideally, this script would determine the post format (markdown,
49
+ # html, etc) and create files with proper extensions. At this point
50
+ # it just assumes that markdown will be acceptable.
51
+ name = [date.year, date.month, date.day, slug].join('-') + '.' +
52
+ self.suffix(entry_convert_breaks)
45
53
 
46
54
  data = {
47
55
  'layout' => 'post',
48
56
  'title' => title.to_s,
49
57
  'mt_id' => post[:entry_id],
50
58
  'date' => date
51
- }.delete_if { |k,v| v.nil? || v == ''}.to_yaml
59
+ }.delete_if { |k,v| v.nil? || v == '' }.to_yaml
52
60
 
53
61
  File.open("_posts/#{name}", "w") do |f|
54
62
  f.puts data
@@ -60,17 +68,18 @@ module Jekyll
60
68
 
61
69
  def self.suffix(entry_type)
62
70
  if entry_type.nil? || entry_type.include?("markdown")
63
- # The markdown plugin I have saves this as "markdown_with_smarty_pants", so I just look for "markdown".
64
- "markdown"
65
- elsif entry_type.include?("textile")
66
- # This is saved as "textile_2" on my installation of MT 5.1.
67
- "textile"
68
- elsif entry_type == "0" || entry_type.include?("richtext")
69
- # richtext looks to me like it's saved as HTML, so I include it here.
70
- "html"
71
- else
72
- # Other values might need custom work.
73
- entry_type
71
+ # The markdown plugin I have saves this as
72
+ # "markdown_with_smarty_pants", so I just look for "markdown".
73
+ "markdown"
74
+ elsif entry_type.include?("textile")
75
+ # This is saved as "textile_2" on my installation of MT 5.1.
76
+ "textile"
77
+ elsif entry_type == "0" || entry_type.include?("richtext")
78
+ # Richtext looks to me like it's saved as HTML, so I include it here.
79
+ "html"
80
+ else
81
+ # Other values might need custom work.
82
+ entry_type
74
83
  end
75
84
  end
76
85
  end
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
2
+ require 'jekyll'
3
+ require 'fileutils'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require "json"
7
+
8
+ # ruby -r './lib/jekyll/migrators/posterous.rb' -e 'Jekyll::Posterous.process(email, pass, blog)'
9
+
10
+ module Jekyll
11
+ module Posterous
12
+ def self.fetch(uri_str, limit = 10)
13
+ # You should choose better exception.
14
+ raise ArgumentError, 'Stuck in a redirect loop. Please double check your email and password' if limit == 0
15
+
16
+ response = nil
17
+ Net::HTTP.start('posterous.com') do |http|
18
+ req = Net::HTTP::Get.new(uri_str)
19
+ req.basic_auth @email, @pass
20
+ response = http.request(req)
21
+ end
22
+
23
+ case response
24
+ when Net::HTTPSuccess then response
25
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
26
+ else response.error!
27
+ end
28
+ end
29
+
30
+ def self.process(email, pass, blog = 'primary')
31
+ @email, @pass = email, pass
32
+ @api_token = JSON.parse(self.fetch("/api/2/auth/token").body)['api_token']
33
+ FileUtils.mkdir_p "_posts"
34
+
35
+ posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}").body)
36
+ page = 1
37
+
38
+ while posts.any?
39
+ posts.each do |post|
40
+ title = post["title"]
41
+ slug = title.gsub(/[^[:alnum:]]+/, '-').downcase
42
+ date = Date.parse(post["display_date"])
43
+ content = post["body_html"]
44
+ published = !post["is_private"]
45
+ name = "%02d-%02d-%02d-%s.html" % [date.year, date.month, date.day, slug]
46
+
47
+ # Get the relevant fields as a hash, delete empty fields and convert
48
+ # to YAML for the header
49
+ data = {
50
+ 'layout' => 'post',
51
+ 'title' => title.to_s,
52
+ 'published' => published
53
+ }.delete_if { |k,v| v.nil? || v == ''}.to_yaml
54
+
55
+ # Write out the data and content to file
56
+ File.open("_posts/#{name}", "w") do |f|
57
+ f.puts data
58
+ f.puts "---"
59
+ f.puts content
60
+ end
61
+ end
62
+
63
+ page += 1
64
+ posts = JSON.parse(self.fetch("/api/v2/users/me/sites/#{blog}/posts?api_token=#{@api_token}&page=#{page}").body)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -11,10 +11,17 @@ require 'fileutils'
11
11
  module Jekyll
12
12
  module TextPattern
13
13
  # Reads a MySQL database via Sequel and creates a post file for each post.
14
- # The only posts selected are those with a status of 4 or 5, which means "live"
15
- # and "sticky" respectively.
16
- # Other statuses is 1 => draft, 2 => hidden and 3 => pending
17
- QUERY = "select Title, url_title, Posted, Body, Keywords from textpattern where Status = '4' or Status = '5'"
14
+ # The only posts selected are those with a status of 4 or 5, which means
15
+ # "live" and "sticky" respectively.
16
+ # Other statuses are 1 => draft, 2 => hidden and 3 => pending.
17
+ QUERY = "SELECT Title, \
18
+ url_title, \
19
+ Posted, \
20
+ Body, \
21
+ Keywords \
22
+ FROM textpattern \
23
+ WHERE Status = '4' OR \
24
+ Status = '5'"
18
25
 
19
26
  def self.process(dbname, user, pass, host = 'localhost')
20
27
  db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
@@ -22,7 +29,7 @@ module Jekyll
22
29
  FileUtils.mkdir_p "_posts"
23
30
 
24
31
  db[QUERY].each do |post|
25
- # Get required fields and construct Jekyll compatible name
32
+ # Get required fields and construct Jekyll compatible name.
26
33
  title = post[:Title]
27
34
  slug = post[:url_title]
28
35
  date = post[:Posted]
@@ -31,14 +38,14 @@ module Jekyll
31
38
  name = [date.strftime("%Y-%m-%d"), slug].join('-') + ".textile"
32
39
 
33
40
  # Get the relevant fields as a hash, delete empty fields and convert
34
- # to YAML for the header
41
+ # to YAML for the header.
35
42
  data = {
36
43
  'layout' => 'post',
37
44
  'title' => title.to_s,
38
45
  'tags' => post[:Keywords].split(',')
39
46
  }.delete_if { |k,v| v.nil? || v == ''}.to_yaml
40
47
 
41
- # Write out the data and content to file
48
+ # Write out the data and content to file.
42
49
  File.open("_posts/#{name}", "w") do |f|
43
50
  f.puts data
44
51
  f.puts "---"
@@ -47,4 +54,4 @@ module Jekyll
47
54
  end
48
55
  end
49
56
  end
50
- end
57
+ end
@@ -0,0 +1,119 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require 'open-uri'
4
+ require 'fileutils'
5
+ require 'CGI'
6
+ require 'iconv'
7
+ require 'date'
8
+
9
+ module Jekyll
10
+ module Tumblr
11
+ def self.process(url, grab_images = false)
12
+ current_page = 0
13
+
14
+ while true
15
+ f = open(url + "/api/read?num=50&start=#{current_page * 50}")
16
+ doc = Nokogiri::HTML(Iconv.conv("utf-8", f.charset, f.readlines.join("\n")))
17
+
18
+ puts "Page: #{current_page + 1} - Posts: #{(doc/:tumblr/:posts/:post).size}"
19
+
20
+ FileUtils.mkdir_p "_posts/tumblr"
21
+
22
+ (doc/:tumblr/:posts/:post).each do |post|
23
+ title = ""
24
+ content = nil
25
+ name = nil
26
+
27
+ if post['type'] == "regular"
28
+ title_element = post.at("regular-title")
29
+ title = title_element.inner_text unless title_element == nil
30
+ content = CGI::unescapeHTML post.at("regular-body").inner_html unless post.at("regular-body") == nil
31
+ elsif post['type'] == "link"
32
+ title = post.at("link-text").inner_html unless post.at("link-text") == nil
33
+
34
+ if post.at("link-text") != nil
35
+ content = "<a href=\"#{post.at("link-url").inner_html}\">#{post.at("link-text").inner_html}</a>"
36
+ else
37
+ content = "<a href=\"#{post.at("link-url").inner_html}\">#{post.at("link-url").inner_html}</a>"
38
+ end
39
+
40
+ content << "<br/>" + CGI::unescapeHTML(post.at("link-description").inner_html) unless post.at("link-description") == nil
41
+ elsif post['type'] == "photo"
42
+ content = ""
43
+
44
+ if post.at("photo-link-url") != nil
45
+ content = "<a href=\"#{post.at("photo-link-url").inner_html}\"><img src=\"#{save_file((post/"photo-url")[1].inner_html, grab_images)}\"/></a>"
46
+ else
47
+ content = "<img src=\"#{save_file((post/"photo-url")[1].inner_html, grab_images)}\"/>"
48
+ end
49
+
50
+ if post.at("photo-caption") != nil
51
+ content << "<br/>" unless content == nil
52
+ content << CGI::unescapeHTML(post.at("photo-caption").inner_html)
53
+ end
54
+ elsif post['type'] == "audio"
55
+ content = CGI::unescapeHTML(post.at("audio-player").inner_html)
56
+ content << CGI::unescapeHTML(post.at("audio-caption").inner_html) unless post.at("audio-caption") == nil
57
+ elsif post['type'] == "quote"
58
+ content = "<blockquote>" + CGI::unescapeHTML(post.at("quote-text").inner_html) + "</blockquote>"
59
+ content << "&#8212;" + CGI::unescapeHTML(post.at("quote-source").inner_html) unless post.at("quote-source") == nil
60
+ elsif post['type'] == "conversation"
61
+ title = post.at("conversation-title").inner_html unless post.at("conversation-title") == nil
62
+ content = "<section><dialog>"
63
+
64
+ (post/:conversation/:line).each do |line|
65
+ content << "<dt>" + line['label'] + "</dt><dd>" + line.inner_html + "</dd>" unless line['label'] == nil || line == nil
66
+ end
67
+
68
+ content << "</section></dialog>"
69
+ elsif post['type'] == "video"
70
+ title = post.at("video-title").inner_html unless post.at("video-title") == nil
71
+ content = CGI::unescapeHTML(post.at("video-player").inner_html)
72
+ content << CGI::unescapeHTML(post.at("video-caption").inner_html) unless post.at("video-caption") == nil
73
+ end # End post types
74
+
75
+ name = "#{Date.parse(post['date']).to_s}-#{post['id'].downcase.gsub(/[^a-z0-9]/, '-')}.html"
76
+
77
+ if title != nil || content != nil && name != nil
78
+ File.open("_posts/tumblr/#{name}", "w") do |f|
79
+
80
+ f.puts <<-HEADER
81
+ ---
82
+ layout: post
83
+ title: #{title}
84
+ ---
85
+
86
+ HEADER
87
+
88
+ f.puts content
89
+ end # End file
90
+ end
91
+
92
+ end # End post XML
93
+
94
+ if (doc/:tumblr/:posts/:post).size < 50
95
+ break
96
+ else
97
+ current_page = current_page + 1
98
+ end
99
+
100
+ end # End while loop
101
+ end # End method
102
+
103
+ private
104
+
105
+ def self.save_file(url, grab_image = false)
106
+ unless grab_image == false
107
+ FileUtils.mkdir_p "tumblr_files"
108
+
109
+ File.open("tumblr_files/#{url.split('/').last}", "w") do |f|
110
+ f.write(open(url).read)
111
+ end
112
+
113
+ return "/tumblr_files/#{url.split('/').last}"
114
+ else
115
+ return url
116
+ end
117
+ end
118
+ end
119
+ end
@@ -2,11 +2,12 @@
2
2
  require 'fileutils'
3
3
  require 'rubygems'
4
4
  require 'sequel'
5
+ require 'yaml'
5
6
 
6
7
  module Jekyll
7
8
  module Typo
8
- # this SQL *should* work for both MySQL and PostgreSQL, but I haven't
9
- # tested PostgreSQL yet (as of 2008-12-16)
9
+ # This SQL *should* work for both MySQL and PostgreSQL, but I haven't
10
+ # tested PostgreSQL yet (as of 2008-12-16).
10
11
  SQL = <<-EOS
11
12
  SELECT c.id id,
12
13
  c.title title,
@@ -24,14 +25,15 @@ module Jekyll
24
25
  FileUtils.mkdir_p '_posts'
25
26
  db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
26
27
  db[SQL].each do |post|
27
- next unless post[:state] =~ /Published/
28
+ next unless post[:state] =~ /published/
28
29
 
29
30
  name = [ sprintf("%.04d", post[:date].year),
30
31
  sprintf("%.02d", post[:date].month),
31
32
  sprintf("%.02d", post[:date].day),
32
33
  post[:slug].strip ].join('-')
34
+
33
35
  # Can have more than one text filter in this field, but we just want
34
- # the first one for this
36
+ # the first one for this.
35
37
  name += '.' + post[:filter].split(' ')[0]
36
38
 
37
39
  File.open("_posts/#{name}", 'w') do |f|
@@ -45,5 +47,5 @@ module Jekyll
45
47
  end
46
48
  end
47
49
 
48
- end # module Typo
49
- end # module Jekyll
50
+ end
51
+ end
@@ -11,20 +11,27 @@ require 'yaml'
11
11
 
12
12
  module Jekyll
13
13
  module WordPress
14
-
15
- # Reads a MySQL database via Sequel and creates a post file for each
16
- # post in wp_posts that has post_status = 'publish'.
17
- # This restriction is made because 'draft' posts are not guaranteed to
18
- # have valid dates.
19
- QUERY = "select post_title, post_name, post_date, post_content, post_excerpt, ID, guid from wp_posts where post_status = 'publish' and post_type = 'post'"
20
-
21
- def self.process(dbname, user, pass, host = 'localhost')
14
+ def self.process(dbname, user, pass, host = 'localhost', table_prefix = 'wp_')
22
15
  db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
23
16
 
24
- FileUtils.mkdir_p "_posts"
25
-
26
- db[QUERY].each do |post|
27
- # Get required fields and construct Jekyll compatible name
17
+ FileUtils.mkdir_p("_posts")
18
+
19
+ # Reads a MySQL database via Sequel and creates a post file for each
20
+ # post in wp_posts that has post_status = 'publish'. This restriction is
21
+ # made because 'draft' posts are not guaranteed to have valid dates.
22
+ query = "SELECT post_title, \
23
+ post_name, \
24
+ post_date, \
25
+ post_content, \
26
+ post_excerpt, \
27
+ ID, \
28
+ guid \
29
+ FROM #{table_prefix}posts \
30
+ WHERE post_status = 'publish' AND \
31
+ post_type = 'post'"
32
+
33
+ db[query].each do |post|
34
+ # Get required fields and construct Jekyll compatible name.
28
35
  title = post[:post_title]
29
36
  slug = post[:post_name]
30
37
  date = post[:post_date]
@@ -33,14 +40,15 @@ module Jekyll
33
40
  slug]
34
41
 
35
42
  # Get the relevant fields as a hash, delete empty fields and convert
36
- # to YAML for the header
43
+ # to YAML for the header.
37
44
  data = {
38
45
  'layout' => 'post',
39
46
  'title' => title.to_s,
40
47
  'excerpt' => post[:post_excerpt].to_s,
41
48
  'wordpress_id' => post[:ID],
42
- 'wordpress_url' => post[:guid]
43
- }.delete_if { |k,v| v.nil? || v == ''}.to_yaml
49
+ 'wordpress_url' => post[:guid],
50
+ 'date' => date
51
+ }.delete_if { |k,v| v.nil? || v == '' }.to_yaml
44
52
 
45
53
  # Write out the data and content to file
46
54
  File.open("_posts/#{name}", "w") do |f|
@@ -49,7 +57,6 @@ module Jekyll
49
57
  f.puts content
50
58
  end
51
59
  end
52
-
53
60
  end
54
61
  end
55
62
  end