jekyll-reloaded 0.12

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.
Files changed (109) hide show
  1. data/Gemfile +2 -0
  2. data/History.txt +321 -0
  3. data/LICENSE +21 -0
  4. data/README.textile +41 -0
  5. data/Rakefile +161 -0
  6. data/bin/jekyll +289 -0
  7. data/cucumber.yml +1 -0
  8. data/features/create_sites.feature +112 -0
  9. data/features/embed_filters.feature +60 -0
  10. data/features/markdown.feature +30 -0
  11. data/features/pagination.feature +27 -0
  12. data/features/permalinks.feature +65 -0
  13. data/features/post_data.feature +153 -0
  14. data/features/site_configuration.feature +145 -0
  15. data/features/site_data.feature +82 -0
  16. data/features/step_definitions/jekyll_steps.rb +145 -0
  17. data/features/support/env.rb +19 -0
  18. data/jekyll.gemspec +146 -0
  19. data/lib/guard/jekyll.rb +57 -0
  20. data/lib/jekyll/converter.rb +50 -0
  21. data/lib/jekyll/converters/identity.rb +22 -0
  22. data/lib/jekyll/converters/markdown.rb +125 -0
  23. data/lib/jekyll/converters/textile.rb +50 -0
  24. data/lib/jekyll/convertible.rb +116 -0
  25. data/lib/jekyll/core_ext.rb +52 -0
  26. data/lib/jekyll/errors.rb +6 -0
  27. data/lib/jekyll/filters.rb +118 -0
  28. data/lib/jekyll/generator.rb +7 -0
  29. data/lib/jekyll/generators/pagination.rb +113 -0
  30. data/lib/jekyll/layout.rb +51 -0
  31. data/lib/jekyll/live_site.rb +216 -0
  32. data/lib/jekyll/migrators/csv.rb +26 -0
  33. data/lib/jekyll/migrators/drupal.rb +103 -0
  34. data/lib/jekyll/migrators/enki.rb +49 -0
  35. data/lib/jekyll/migrators/joomla.rb +53 -0
  36. data/lib/jekyll/migrators/marley.rb +52 -0
  37. data/lib/jekyll/migrators/mephisto.rb +84 -0
  38. data/lib/jekyll/migrators/mt.rb +86 -0
  39. data/lib/jekyll/migrators/posterous.rb +67 -0
  40. data/lib/jekyll/migrators/rss.rb +47 -0
  41. data/lib/jekyll/migrators/textpattern.rb +58 -0
  42. data/lib/jekyll/migrators/tumblr.rb +195 -0
  43. data/lib/jekyll/migrators/typo.rb +51 -0
  44. data/lib/jekyll/migrators/wordpress.rb +294 -0
  45. data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
  46. data/lib/jekyll/page.rb +160 -0
  47. data/lib/jekyll/plugin.rb +77 -0
  48. data/lib/jekyll/post.rb +262 -0
  49. data/lib/jekyll/site.rb +339 -0
  50. data/lib/jekyll/static_file.rb +77 -0
  51. data/lib/jekyll/tags/highlight.rb +118 -0
  52. data/lib/jekyll/tags/include.rb +37 -0
  53. data/lib/jekyll/tags/post_url.rb +38 -0
  54. data/lib/jekyll.rb +134 -0
  55. data/test/helper.rb +34 -0
  56. data/test/source/.htaccess +8 -0
  57. data/test/source/_includes/sig.markdown +3 -0
  58. data/test/source/_layouts/default.html +27 -0
  59. data/test/source/_layouts/simple.html +1 -0
  60. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  61. data/test/source/_posts/2008-02-02-published.textile +8 -0
  62. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  63. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  64. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  65. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  66. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  67. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  68. data/test/source/_posts/2009-01-27-category.textile +7 -0
  69. data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
  70. data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
  71. data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
  72. data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
  73. data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
  74. data/test/source/_posts/2009-05-18-tag.textile +6 -0
  75. data/test/source/_posts/2009-05-18-tags.textile +9 -0
  76. data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
  77. data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
  78. data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
  79. data/test/source/_posts/2010-01-09-date-override.textile +7 -0
  80. data/test/source/_posts/2010-01-09-time-override.textile +7 -0
  81. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  82. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  83. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  84. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  85. data/test/source/about.html +6 -0
  86. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  87. data/test/source/contacts.html +5 -0
  88. data/test/source/css/screen.css +76 -0
  89. data/test/source/deal.with.dots.html +7 -0
  90. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  91. data/test/source/index.html +22 -0
  92. data/test/source/sitemap.xml +32 -0
  93. data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
  94. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  95. data/test/suite.rb +11 -0
  96. data/test/test_configuration.rb +29 -0
  97. data/test/test_core_ext.rb +66 -0
  98. data/test/test_filters.rb +62 -0
  99. data/test/test_generated_site.rb +72 -0
  100. data/test/test_kramdown.rb +23 -0
  101. data/test/test_page.rb +117 -0
  102. data/test/test_pager.rb +113 -0
  103. data/test/test_post.rb +450 -0
  104. data/test/test_rdiscount.rb +18 -0
  105. data/test/test_redcarpet.rb +21 -0
  106. data/test/test_redcloth.rb +86 -0
  107. data/test/test_site.rb +220 -0
  108. data/test/test_tags.rb +201 -0
  109. metadata +332 -0
@@ -0,0 +1,51 @@
1
+ # Author: Toby DiPasquale <toby@cbcg.net>
2
+ require 'fileutils'
3
+ require 'rubygems'
4
+ require 'sequel'
5
+ require 'yaml'
6
+
7
+ module Jekyll
8
+ module Typo
9
+ # This SQL *should* work for both MySQL and PostgreSQL, but I haven't
10
+ # tested PostgreSQL yet (as of 2008-12-16).
11
+ SQL = <<-EOS
12
+ SELECT c.id id,
13
+ c.title title,
14
+ c.permalink slug,
15
+ c.body body,
16
+ c.published_at date,
17
+ c.state state,
18
+ COALESCE(tf.name, 'html') filter
19
+ FROM contents c
20
+ LEFT OUTER JOIN text_filters tf
21
+ ON c.text_filter_id = tf.id
22
+ EOS
23
+
24
+ def self.process dbname, user, pass, host='localhost'
25
+ FileUtils.mkdir_p '_posts'
26
+ db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
27
+ db[SQL].each do |post|
28
+ next unless post[:state] =~ /published/
29
+
30
+ name = [ sprintf("%.04d", post[:date].year),
31
+ sprintf("%.02d", post[:date].month),
32
+ sprintf("%.02d", post[:date].day),
33
+ post[:slug].strip ].join('-')
34
+
35
+ # Can have more than one text filter in this field, but we just want
36
+ # the first one for this.
37
+ name += '.' + post[:filter].split(' ')[0]
38
+
39
+ File.open("_posts/#{name}", 'w') do |f|
40
+ f.puts({ 'layout' => 'post',
41
+ 'title' => post[:title].to_s,
42
+ 'typo_id' => post[:id]
43
+ }.delete_if { |k, v| v.nil? || v == '' }.to_yaml)
44
+ f.puts '---'
45
+ f.puts post[:body].delete("\r")
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,294 @@
1
+ require 'rubygems'
2
+ require 'sequel'
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ # NOTE: This converter requires Sequel and the MySQL gems.
7
+ # The MySQL gem can be difficult to install on OS X. Once you have MySQL
8
+ # installed, running the following commands should work:
9
+ # $ sudo gem install sequel
10
+ # $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
11
+
12
+ module Jekyll
13
+ module WordPress
14
+
15
+ # Main migrator function. Call this to perform the migration.
16
+ #
17
+ # dbname:: The name of the database
18
+ # user:: The database user name
19
+ # pass:: The database user's password
20
+ # host:: The address of the MySQL database host. Default: 'localhost'
21
+ # options:: A hash table of configuration options.
22
+ #
23
+ # Supported options are:
24
+ #
25
+ # :table_prefix:: Prefix of database tables used by WordPress.
26
+ # Default: 'wp_'
27
+ # :clean_entities:: If true, convert non-ASCII characters to HTML
28
+ # entities in the posts, comments, titles, and
29
+ # names. Requires the 'htmlentities' gem to
30
+ # work. Default: true.
31
+ # :comments:: If true, migrate post comments too. Comments
32
+ # are saved in the post's YAML front matter.
33
+ # Default: true.
34
+ # :categories:: If true, save the post's categories in its
35
+ # YAML front matter.
36
+ # :tags:: If true, save the post's tags in its
37
+ # YAML front matter.
38
+ # :more_excerpt:: If true, when a post has no excerpt but
39
+ # does have a <!-- more --> tag, use the
40
+ # preceding post content as the excerpt.
41
+ # Default: true.
42
+ # :more_anchor:: If true, convert a <!-- more --> tag into
43
+ # two HTML anchors with ids "more" and
44
+ # "more-NNN" (where NNN is the post number).
45
+ # Default: true.
46
+ # :status:: Array of allowed post statuses. Only
47
+ # posts with matching status will be migrated.
48
+ # Known statuses are :publish, :draft, :private,
49
+ # and :revision. If this is nil or an empty
50
+ # array, all posts are migrated regardless of
51
+ # status. Default: [:publish].
52
+ #
53
+ def self.process(dbname, user, pass, host='localhost', options={})
54
+ options = {
55
+ :table_prefix => 'wp_',
56
+ :clean_entities => true,
57
+ :comments => true,
58
+ :categories => true,
59
+ :tags => true,
60
+ :more_excerpt => true,
61
+ :more_anchor => true,
62
+ :status => [:publish] # :draft, :private, :revision
63
+ }.merge(options)
64
+
65
+ if options[:clean_entities]
66
+ begin
67
+ require 'htmlentities'
68
+ rescue LoadError
69
+ STDERR.puts "Could not require 'htmlentities', so the " +
70
+ ":clean_entities option is now disabled."
71
+ options[:clean_entities] = false
72
+ end
73
+ end
74
+
75
+ FileUtils.mkdir_p("_posts")
76
+
77
+ db = Sequel.mysql(dbname, :user => user, :password => pass,
78
+ :host => host, :encoding => 'utf8')
79
+
80
+ px = options[:table_prefix]
81
+
82
+ posts_query = "
83
+ SELECT
84
+ posts.ID AS `id`,
85
+ posts.guid AS `guid`,
86
+ posts.post_type AS `type`,
87
+ posts.post_status AS `status`,
88
+ posts.post_title AS `title`,
89
+ posts.post_name AS `slug`,
90
+ posts.post_date AS `date`,
91
+ posts.post_content AS `content`,
92
+ posts.post_excerpt AS `excerpt`,
93
+ posts.comment_count AS `comment_count`,
94
+ users.display_name AS `author`,
95
+ users.user_login AS `author_login`,
96
+ users.user_email AS `author_email`,
97
+ users.user_url AS `author_url`
98
+ FROM #{px}posts AS `posts`
99
+ LEFT JOIN #{px}users AS `users`
100
+ ON posts.post_author = users.ID"
101
+
102
+ if options[:status] and not options[:status].empty?
103
+ status = options[:status][0]
104
+ posts_query << "
105
+ WHERE posts.post_status = '#{status.to_s}'"
106
+ options[:status][1..-1].each do |status|
107
+ posts_query << " OR
108
+ posts.post_status = '#{status.to_s}'"
109
+ end
110
+ end
111
+
112
+ db[posts_query].each do |post|
113
+ process_post(post, db, options)
114
+ end
115
+ end
116
+
117
+
118
+ def self.process_post(post, db, options)
119
+ px = options[:table_prefix]
120
+
121
+ title = post[:title]
122
+ if options[:clean_entities]
123
+ title = clean_entities(title)
124
+ end
125
+
126
+ slug = post[:slug]
127
+ if !slug or slug.empty?
128
+ slug = sluggify(title)
129
+ end
130
+
131
+ date = post[:date] || Time.now
132
+ name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month,
133
+ date.day, slug]
134
+ content = post[:content].to_s
135
+ if options[:clean_entities]
136
+ content = clean_entities(content)
137
+ end
138
+
139
+ excerpt = post[:excerpt].to_s
140
+
141
+ more_index = content.index(/<!-- *more *-->/)
142
+ more_anchor = nil
143
+ if more_index
144
+ if options[:more_excerpt] and
145
+ (post[:excerpt].nil? or post[:excerpt].empty?)
146
+ excerpt = content[0...more_index]
147
+ end
148
+ if options[:more_anchor]
149
+ more_link = "more"
150
+ content.sub!(/<!-- *more *-->/,
151
+ "<a id=\"more\"></a>" +
152
+ "<a id=\"more-#{post[:id]}\"></a>")
153
+ end
154
+ end
155
+
156
+ categories = []
157
+ tags = []
158
+
159
+ if options[:categories] or options[:tags]
160
+
161
+ cquery =
162
+ "SELECT
163
+ terms.name AS `name`,
164
+ ttax.taxonomy AS `type`
165
+ FROM
166
+ #{px}terms AS `terms`,
167
+ #{px}term_relationships AS `trels`,
168
+ #{px}term_taxonomy AS `ttax`
169
+ WHERE
170
+ trels.object_id = '#{post[:id]}' AND
171
+ trels.term_taxonomy_id = ttax.term_taxonomy_id AND
172
+ terms.term_id = ttax.term_id"
173
+
174
+ db[cquery].each do |term|
175
+ if options[:categories] and term[:type] == "category"
176
+ if options[:clean_entities]
177
+ categories << clean_entities(term[:name])
178
+ else
179
+ categories << term[:name]
180
+ end
181
+ elsif options[:tags] and term[:type] == "post_tag"
182
+ if options[:clean_entities]
183
+ tags << clean_entities(term[:name])
184
+ else
185
+ tags << term[:name]
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ comments = []
192
+
193
+ if options[:comments] and post[:comment_count].to_i > 0
194
+ cquery =
195
+ "SELECT
196
+ comment_ID AS `id`,
197
+ comment_author AS `author`,
198
+ comment_author_email AS `author_email`,
199
+ comment_author_url AS `author_url`,
200
+ comment_date AS `date`,
201
+ comment_date_gmt AS `date_gmt`,
202
+ comment_content AS `content`
203
+ FROM #{px}comments
204
+ WHERE
205
+ comment_post_ID = '#{post[:id]}' AND
206
+ comment_approved != 'spam'"
207
+
208
+
209
+ db[cquery].each do |comment|
210
+
211
+ comcontent = comment[:content].to_s
212
+ if comcontent.respond_to?(:force_encoding)
213
+ comcontent.force_encoding("UTF-8")
214
+ end
215
+ if options[:clean_entities]
216
+ comcontent = clean_entities(comcontent)
217
+ end
218
+ comauthor = comment[:author].to_s
219
+ if options[:clean_entities]
220
+ comauthor = clean_entities(comauthor)
221
+ end
222
+
223
+ comments << {
224
+ 'id' => comment[:id].to_i,
225
+ 'author' => comauthor,
226
+ 'author_email' => comment[:author_email].to_s,
227
+ 'author_url' => comment[:author_url].to_s,
228
+ 'date' => comment[:date].to_s,
229
+ 'date_gmt' => comment[:date_gmt].to_s,
230
+ 'content' => comcontent,
231
+ }
232
+ end
233
+
234
+ comments.sort!{ |a,b| a['id'] <=> b['id'] }
235
+ end
236
+
237
+ # Get the relevant fields as a hash, delete empty fields and
238
+ # convert to YAML for the header.
239
+ data = {
240
+ 'layout' => post[:type].to_s,
241
+ 'status' => post[:status].to_s,
242
+ 'published' => (post[:status].to_s == "publish"),
243
+ 'title' => title.to_s,
244
+ 'author' => post[:author].to_s,
245
+ 'author_login' => post[:author_login].to_s,
246
+ 'author_email' => post[:author_email].to_s,
247
+ 'author_url' => post[:author_url].to_s,
248
+ 'excerpt' => excerpt,
249
+ 'more_anchor' => more_anchor,
250
+ 'wordpress_id' => post[:id],
251
+ 'wordpress_url' => post[:guid].to_s,
252
+ 'date' => date,
253
+ 'categories' => options[:categories] ? categories : nil,
254
+ 'tags' => options[:tags] ? tags : nil,
255
+ 'comments' => options[:comments] ? comments : nil,
256
+ }.delete_if { |k,v| v.nil? || v == '' }.to_yaml
257
+
258
+ # Write out the data and content to file
259
+ File.open("_posts/#{name}", "w") do |f|
260
+ f.puts data
261
+ f.puts "---"
262
+ f.puts content
263
+ end
264
+ end
265
+
266
+
267
+ def self.clean_entities( text )
268
+ if text.respond_to?(:force_encoding)
269
+ text.force_encoding("UTF-8")
270
+ end
271
+ text = HTMLEntities.new.encode(text, :named)
272
+ # We don't want to convert these, it would break all
273
+ # HTML tags in the post and comments.
274
+ text.gsub!("&amp;", "&")
275
+ text.gsub!("&lt;", "<")
276
+ text.gsub!("&gt;", ">")
277
+ text.gsub!("&quot;", '"')
278
+ text.gsub!("&apos;", "'")
279
+ text
280
+ end
281
+
282
+
283
+ def self.sluggify( title )
284
+ begin
285
+ require 'unidecode'
286
+ title = title.to_ascii
287
+ rescue LoadError
288
+ STDERR.puts "Could not require 'unidecode'. If your post titles have non-ASCII characters, you could get nicer permalinks by installing unidecode."
289
+ end
290
+ title.downcase.gsub(/[^0-9A-Za-z]+/, " ").strip.gsub(" ", "-")
291
+ end
292
+
293
+ end
294
+ end
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'hpricot'
5
+ require 'fileutils'
6
+ require 'yaml'
7
+ require 'time'
8
+
9
+ module Jekyll
10
+ # This importer takes a wordpress.xml file, which can be exported from your
11
+ # wordpress.com blog (/wp-admin/export.php).
12
+ module WordpressDotCom
13
+ def self.process(filename = "wordpress.xml")
14
+ import_count = Hash.new(0)
15
+ doc = Hpricot::XML(File.read(filename))
16
+
17
+ (doc/:channel/:item).each do |item|
18
+ title = item.at(:title).inner_text.strip
19
+ permalink_title = item.at('wp:post_name').inner_text
20
+ # Fallback to "prettified" title if post_name is empty (can happen)
21
+ if permalink_title == ""
22
+ permalink_title = title.downcase.split.join('-')
23
+ end
24
+
25
+ date = Time.parse(item.at('wp:post_date').inner_text)
26
+ status = item.at('wp:status').inner_text
27
+
28
+ if status == "publish"
29
+ published = true
30
+ else
31
+ published = false
32
+ end
33
+
34
+ type = item.at('wp:post_type').inner_text
35
+ tags = (item/:category).map{|c| c.inner_text}.reject{|c| c == 'Uncategorized'}.uniq
36
+
37
+ metas = Hash.new
38
+ item.search("wp:postmeta").each do |meta|
39
+ key = meta.at('wp:meta_key').inner_text
40
+ value = meta.at('wp:meta_value').inner_text
41
+ metas[key] = value;
42
+ end
43
+
44
+ name = "#{date.strftime('%Y-%m-%d')}-#{permalink_title}.html"
45
+ header = {
46
+ 'layout' => type,
47
+ 'title' => title,
48
+ 'tags' => tags,
49
+ 'status' => status,
50
+ 'type' => type,
51
+ 'published' => published,
52
+ 'meta' => metas
53
+ }
54
+
55
+ FileUtils.mkdir_p "_#{type}s"
56
+ File.open("_#{type}s/#{name}", "w") do |f|
57
+ f.puts header.to_yaml
58
+ f.puts '---'
59
+ f.puts item.at('content:encoded').inner_text
60
+ end
61
+
62
+ import_count[type] += 1
63
+ end
64
+
65
+ import_count.each do |key, value|
66
+ puts "Imported #{value} #{key}s"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,160 @@
1
+ module Jekyll
2
+
3
+ class Page
4
+ include Convertible
5
+
6
+ attr_writer :dir
7
+ attr_accessor :site, :pager
8
+ attr_accessor :name, :ext, :basename
9
+ attr_accessor :data, :content, :output
10
+
11
+ # Initialize a new Page.
12
+ #
13
+ # site - The Site object.
14
+ # source - The String path to the source.
15
+ # dir - The String path between the source and the file.
16
+ # name - The String filename of the file.
17
+ def initialize(site, source, dir, name)
18
+ @site = site
19
+ @dir = dir
20
+ @base = File.join(source, @dir)
21
+ @name = name
22
+
23
+ self.process(name)
24
+ self.read_yaml(@base, name)
25
+ end
26
+
27
+ # The source filename for this page.
28
+ def filename
29
+ File.join(@base, name)
30
+ end
31
+
32
+ # The generated directory into which the page will be placed
33
+ # upon generation. This is derived from the permalink or, if
34
+ # permalink is absent, we be '/'
35
+ #
36
+ # Returns the String destination directory.
37
+ def dir
38
+ url[-1, 1] == '/' ? url : File.dirname(url)
39
+ end
40
+
41
+ # The full path and filename of the post. Defined in the YAML of the post
42
+ # body.
43
+ #
44
+ # Returns the String permalink or nil if none has been set.
45
+ def permalink
46
+ self.data && self.data['permalink']
47
+ end
48
+
49
+ # The template of the permalink.
50
+ #
51
+ # Returns the template String.
52
+ def template
53
+ if self.site.permalink_style == :pretty && !index? && html?
54
+ "/:basename/"
55
+ else
56
+ "/:basename:output_ext"
57
+ end
58
+ end
59
+
60
+ # The generated relative url of this page. e.g. /about.html.
61
+ #
62
+ # Returns the String url.
63
+ def url
64
+ return @url if @url
65
+
66
+ url = if permalink
67
+ permalink
68
+ else
69
+ {
70
+ "basename" => self.basename,
71
+ "output_ext" => self.output_ext,
72
+ }.inject(template) { |result, token|
73
+ result.gsub(/:#{token.first}/, token.last)
74
+ }.gsub(/\/\//, "/")
75
+ end
76
+
77
+ # sanitize url
78
+ @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
79
+ @url += "/" if url =~ /\/$/
80
+ @url
81
+ end
82
+
83
+ # Extract information from the page filename.
84
+ #
85
+ # name - The String filename of the page file.
86
+ #
87
+ # Returns nothing.
88
+ def process(name)
89
+ self.ext = File.extname(name)
90
+ self.basename = name[0 .. -self.ext.length-1]
91
+ end
92
+
93
+ # Add any necessary layouts to this post
94
+ #
95
+ # layouts - The Hash of {"name" => "layout"}.
96
+ # site_payload - The site payload Hash.
97
+ #
98
+ # Returns nothing.
99
+ def render(layouts, site_payload)
100
+ payload = {
101
+ "page" => self.to_liquid,
102
+ 'paginator' => pager.to_liquid
103
+ }.deep_merge(site_payload)
104
+
105
+ do_layout(payload, layouts)
106
+ end
107
+
108
+ # Convert this Page's data to a Hash suitable for use by Liquid.
109
+ #
110
+ # Returns the Hash representation of this Page.
111
+ def to_liquid
112
+ self.data.deep_merge({
113
+ "url" => File.join(@dir, self.url),
114
+ "content" => self.content })
115
+ end
116
+
117
+ # Obtain destination path.
118
+ #
119
+ # dest - The String path to the destination dir.
120
+ #
121
+ # Returns the destination file path String.
122
+ def destination(dest)
123
+ # The url needs to be unescaped in order to preserve the correct
124
+ # filename.
125
+ path = File.join(dest, @dir, CGI.unescape(self.url))
126
+ path = File.join(path, "index.html") if self.url =~ /\/$/
127
+ path
128
+ end
129
+
130
+ # Write the generated page file to the destination directory.
131
+ #
132
+ # dest - The String path to the destination dir.
133
+ #
134
+ # Returns nothing.
135
+ def write(dest)
136
+ path = destination(dest)
137
+ FileUtils.mkdir_p(File.dirname(path))
138
+ File.open(path, 'w') do |f|
139
+ f.write(self.output)
140
+ end
141
+ end
142
+
143
+ # Returns the object as a debug String.
144
+ def inspect
145
+ "#<Jekyll:Page @name=#{self.name.inspect}>"
146
+ end
147
+
148
+ # Returns the Boolean of whether this Page is HTML or not.
149
+ def html?
150
+ output_ext == '.html'
151
+ end
152
+
153
+ # Returns the Boolean of whether this Page is an index file or not.
154
+ def index?
155
+ basename == 'index'
156
+ end
157
+
158
+ end
159
+
160
+ end
@@ -0,0 +1,77 @@
1
+ module Jekyll
2
+
3
+ class Plugin
4
+ PRIORITIES = { :lowest => -100,
5
+ :low => -10,
6
+ :normal => 0,
7
+ :high => 10,
8
+ :highest => 100 }
9
+
10
+ # Install a hook so that subclasses are recorded. This method is only
11
+ # ever called by Ruby itself.
12
+ #
13
+ # base - The Class subclass.
14
+ #
15
+ # Returns nothing.
16
+ def self.inherited(base)
17
+ subclasses << base
18
+ subclasses.sort!
19
+ end
20
+
21
+ # The list of Classes that have been subclassed.
22
+ #
23
+ # Returns an Array of Class objects.
24
+ def self.subclasses
25
+ @subclasses ||= []
26
+ end
27
+
28
+ # Get or set the priority of this plugin. When called without an
29
+ # argument it returns the priority. When an argument is given, it will
30
+ # set the priority.
31
+ #
32
+ # priority - The Symbol priority (default: nil). Valid options are:
33
+ # :lowest, :low, :normal, :high, :highest
34
+ #
35
+ # Returns the Symbol priority.
36
+ def self.priority(priority = nil)
37
+ @priority ||= nil
38
+ if priority && PRIORITIES.has_key?(priority)
39
+ @priority = priority
40
+ end
41
+ @priority || :normal
42
+ end
43
+
44
+ # Get or set the safety of this plugin. When called without an argument
45
+ # it returns the safety. When an argument is given, it will set the
46
+ # safety.
47
+ #
48
+ # safe - The Boolean safety (default: nil).
49
+ #
50
+ # Returns the safety Boolean.
51
+ def self.safe(safe = nil)
52
+ if safe
53
+ @safe = safe
54
+ end
55
+ @safe || false
56
+ end
57
+
58
+ # Spaceship is priority [higher -> lower]
59
+ #
60
+ # other - The class to be compared.
61
+ #
62
+ # Returns -1, 0, 1.
63
+ def self.<=>(other)
64
+ PRIORITIES[other.priority] <=> PRIORITIES[self.priority]
65
+ end
66
+
67
+ # Initialize a new plugin. This should be overridden by the subclass.
68
+ #
69
+ # config - The Hash of configuration options.
70
+ #
71
+ # Returns a new instance.
72
+ def initialize(config = {})
73
+ # no-op for default
74
+ end
75
+ end
76
+
77
+ end