mojombo-jekyll 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,12 +17,14 @@ module Jekyll
17
17
  # Returns nothing
18
18
  def read_yaml(base, name)
19
19
  self.content = File.read(File.join(base, name))
20
-
21
- if self.content =~ /^(---\s*\n.*?)\n---\s*\n/m
22
- self.content = self.content[($1.size + 5)..-1]
23
-
20
+
21
+ if self.content =~ /^(---\s*\n.*?\n?)(---.*?\n)/m
22
+ self.content = self.content[($1.size + $2.size)..-1]
23
+
24
24
  self.data = YAML.load($1)
25
25
  end
26
+
27
+ self.data ||= {}
26
28
  end
27
29
 
28
30
  # Transform the contents based on the file extension.
@@ -19,4 +19,12 @@ class Hash
19
19
 
20
20
  target
21
21
  end
22
- end
22
+ end
23
+
24
+ # Thanks, ActiveSupport!
25
+ class Date
26
+ # Converts datetime to an appropriate format for use in XML
27
+ def xmlschema
28
+ strftime("%Y-%m-%dT%H:%M:%S%Z")
29
+ end if RUBY_VERSION < '1.9'
30
+ end
@@ -4,7 +4,7 @@ module Jekyll
4
4
  include Convertible
5
5
 
6
6
  attr_accessor :site
7
- attr_accessor :ext
7
+ attr_accessor :name, :ext, :basename
8
8
  attr_accessor :data, :content, :output
9
9
 
10
10
  # Initialize a new Page.
@@ -17,14 +17,47 @@ module Jekyll
17
17
  def initialize(site, base, dir, name)
18
18
  @site = site
19
19
  @base = base
20
- @dir = dir
20
+ @dir = dir
21
21
  @name = name
22
22
 
23
- self.data = {}
24
-
25
23
  self.process(name)
26
24
  self.read_yaml(File.join(base, dir), name)
27
- #self.transform
25
+ end
26
+
27
+ # The generated directory into which the page will be placed
28
+ # upon generation. This is derived from the permalink or, if
29
+ # permalink is absent, set to '/'
30
+ #
31
+ # Returns <String>
32
+ def dir
33
+ url[-1, 1] == '/' ? url : File.dirname(url)
34
+ end
35
+
36
+ # The full path and filename of the post.
37
+ # Defined in the YAML of the post body
38
+ # (Optional)
39
+ #
40
+ # Returns <String>
41
+ def permalink
42
+ self.data && self.data['permalink']
43
+ end
44
+
45
+ def template
46
+ if self.site.permalink_style == :pretty && !index?
47
+ "/:name/"
48
+ else
49
+ "/:name.html"
50
+ end
51
+ end
52
+
53
+ # The generated relative url of this page
54
+ # e.g. /about.html
55
+ #
56
+ # Returns <String>
57
+ def url
58
+ return permalink if permalink
59
+
60
+ @url ||= template.gsub(':name', basename)
28
61
  end
29
62
 
30
63
  # Extract information from the page filename
@@ -33,6 +66,7 @@ module Jekyll
33
66
  # Returns nothing
34
67
  def process(name)
35
68
  self.ext = File.extname(name)
69
+ self.basename = name.split('.')[0..-2].first
36
70
  end
37
71
 
38
72
  # Add any necessary layouts to this post
@@ -46,22 +80,33 @@ module Jekyll
46
80
  end
47
81
 
48
82
  # Write the generated page file to the destination directory.
49
- # +dest+ is the String path to the destination dir
83
+ # +dest_prefix+ is the String path to the destination dir
84
+ # +dest_suffix+ is a suffix path to the destination dir
50
85
  #
51
86
  # Returns nothing
52
- def write(dest)
53
- FileUtils.mkdir_p(File.join(dest, @dir))
87
+ def write(dest_prefix, dest_suffix = nil)
88
+ dest = File.join(dest_prefix, @dir)
89
+ dest = File.join(dest, dest_suffix) if dest_suffix
90
+ FileUtils.mkdir_p(dest)
54
91
 
55
- name = @name
56
- if self.ext != ""
57
- name = @name.split(".")[0..-2].join('.') + self.ext
92
+ # The url needs to be unescaped in order to preserve the correct filename
93
+ path = File.join(dest, CGI.unescape(self.url))
94
+ if self.url[/\.html$/].nil?
95
+ FileUtils.mkdir_p(path)
96
+ path = File.join(path, "index.html")
58
97
  end
59
98
 
60
- path = File.join(dest, @dir, name)
61
99
  File.open(path, 'w') do |f|
62
100
  f.write(self.output)
63
101
  end
64
102
  end
103
+
104
+ private
105
+
106
+ def index?
107
+ basename == 'index'
108
+ end
109
+
65
110
  end
66
111
 
67
- end
112
+ end
@@ -0,0 +1,45 @@
1
+ module Jekyll
2
+ class Pager
3
+ attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page
4
+
5
+ def self.calculate_pages(all_posts, per_page)
6
+ num_pages = all_posts.size / per_page.to_i
7
+ num_pages.abs + 1 if all_posts.size % per_page.to_i != 0
8
+ num_pages
9
+ end
10
+
11
+ def self.pagination_enabled?(config, file)
12
+ file == 'index.html' && !config['paginate'].nil?
13
+ end
14
+
15
+ def initialize(config, page, all_posts, num_pages = nil)
16
+ @page = page
17
+ @per_page = config['paginate'].to_i
18
+ @total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page)
19
+
20
+ if @page > @total_pages
21
+ raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
22
+ end
23
+
24
+ init = (@page - 1) * @per_page
25
+ offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1)
26
+
27
+ @total_posts = all_posts.size
28
+ @posts = all_posts[init..offset]
29
+ @previous_page = @page != 1 ? @page - 1 : nil
30
+ @next_page = @page != @total_pages ? @page + 1 : nil
31
+ end
32
+
33
+ def to_hash
34
+ {
35
+ 'page' => page,
36
+ 'per_page' => per_page,
37
+ 'posts' => posts,
38
+ 'total_posts' => total_posts,
39
+ 'total_pages' => total_pages,
40
+ 'previous_page' => previous_page,
41
+ 'next_page' => next_page
42
+ }
43
+ end
44
+ end
45
+ end
@@ -18,7 +18,7 @@ module Jekyll
18
18
  name =~ MATCHER
19
19
  end
20
20
 
21
- attr_accessor :site, :date, :slug, :ext, :topics, :published, :data, :content, :output
21
+ attr_accessor :site, :date, :slug, :ext, :published, :data, :content, :output, :tags
22
22
  attr_writer :categories
23
23
 
24
24
  def categories
@@ -38,10 +38,6 @@ module Jekyll
38
38
  @name = name
39
39
 
40
40
  self.categories = dir.split('/').reject { |x| x.empty? }
41
-
42
- parts = name.split('/')
43
- self.topics = parts.size > 1 ? parts[0..-2] : []
44
-
45
41
  self.process(name)
46
42
  self.read_yaml(@base, name)
47
43
 
@@ -51,6 +47,14 @@ module Jekyll
51
47
  self.published = true
52
48
  end
53
49
 
50
+ if self.data.has_key?("tag")
51
+ self.tags = [self.data["tag"]]
52
+ elsif self.data.has_key?("tags")
53
+ self.tags = self.data['tags']
54
+ else
55
+ self.tags = []
56
+ end
57
+
54
58
  if self.categories.empty?
55
59
  if self.data.has_key?('category')
56
60
  self.categories << self.data['category']
@@ -66,11 +70,15 @@ module Jekyll
66
70
  end
67
71
  end
68
72
 
69
- # Spaceship is based on Post#date
73
+ # Spaceship is based on Post#date, slug
70
74
  #
71
75
  # Returns -1, 0, 1
72
76
  def <=>(other)
73
- self.date <=> other.date
77
+ cmp = self.date <=> other.date
78
+ if 0 == cmp
79
+ cmp = self.slug <=> other.slug
80
+ end
81
+ return cmp
74
82
  end
75
83
 
76
84
  # Extract information from the post filename
@@ -106,7 +114,7 @@ module Jekyll
106
114
  def template
107
115
  case self.site.permalink_style
108
116
  when :pretty
109
- "/:categories/:year/:month/:day/:title"
117
+ "/:categories/:year/:month/:day/:title/"
110
118
  when :none
111
119
  "/:categories/:title.html"
112
120
  when :date
@@ -205,15 +213,15 @@ module Jekyll
205
213
  #
206
214
  # Returns <Hash>
207
215
  def to_liquid
208
- { "title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
209
- "url" => self.url,
210
- "date" => self.date,
211
- "id" => self.id,
212
- "topics" => self.topics,
216
+ { "title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
217
+ "url" => self.url,
218
+ "date" => self.date,
219
+ "id" => self.id,
213
220
  "categories" => self.categories,
214
- "next" => self.next,
215
- "previous" => self.previous,
216
- "content" => self.content }.deep_merge(self.data)
221
+ "next" => self.next,
222
+ "previous" => self.previous,
223
+ "tags" => self.tags,
224
+ "content" => self.content }.deep_merge(self.data)
217
225
  end
218
226
 
219
227
  def inspect
@@ -1,8 +1,8 @@
1
1
  module Jekyll
2
2
 
3
3
  class Site
4
- attr_accessor :config, :layouts, :posts, :categories, :exclude
5
- attr_accessor :source, :dest, :lsi, :pygments, :permalink_style
4
+ attr_accessor :config, :layouts, :posts, :categories, :exclude,
5
+ :source, :dest, :lsi, :pygments, :permalink_style, :tags
6
6
 
7
7
  # Initialize the site
8
8
  # +config+ is a Hash containing site configurations details
@@ -25,7 +25,8 @@ module Jekyll
25
25
  def reset
26
26
  self.layouts = {}
27
27
  self.posts = []
28
- self.categories = Hash.new { |hash, key| hash[key] = Array.new }
28
+ self.categories = Hash.new { |hash, key| hash[key] = [] }
29
+ self.tags = Hash.new { |hash, key| hash[key] = [] }
29
30
  end
30
31
 
31
32
  def setup
@@ -76,6 +77,8 @@ module Jekyll
76
77
  rescue LoadError
77
78
  puts "The maruku gem is required for markdown support!"
78
79
  end
80
+ else
81
+ raise "Invalid Markdown processor: '#{self.config['markdown']}' -- did you mean 'maruku' or 'rdiscount'?"
79
82
  end
80
83
  end
81
84
 
@@ -126,6 +129,7 @@ module Jekyll
126
129
  if post.published
127
130
  self.posts << post
128
131
  post.categories.each { |c| self.categories[c] << post }
132
+ post.tags.each { |c| self.tags[c] << post }
129
133
  end
130
134
  end
131
135
  end
@@ -137,7 +141,8 @@ module Jekyll
137
141
  post.render(self.layouts, site_payload)
138
142
  end
139
143
 
140
- self.categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
144
+ self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
145
+ self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
141
146
  rescue Errno::ENOENT => e
142
147
  # ignore missing layout dir
143
148
  end
@@ -172,11 +177,14 @@ module Jekyll
172
177
  directories.delete('_posts')
173
178
  read_posts(dir)
174
179
  end
180
+
175
181
  [directories, files].each do |entries|
176
182
  entries.each do |f|
177
183
  if File.directory?(File.join(base, f))
178
184
  next if self.dest.sub(/\/$/, '') == File.join(base, f)
179
185
  transform_pages(File.join(dir, f))
186
+ elsif Pager.pagination_enabled?(self.config, f)
187
+ paginate_posts(f, dir)
180
188
  else
181
189
  first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) }
182
190
 
@@ -211,15 +219,13 @@ module Jekyll
211
219
  #
212
220
  # Returns {"site" => {"time" => <Time>,
213
221
  # "posts" => [<Post>],
214
- # "categories" => [<Post>],
215
- # "topics" => [<Post>] }}
222
+ # "categories" => [<Post>]}
216
223
  def site_payload
217
- {"site" => {
218
- "time" => Time.now,
219
- "posts" => self.posts.sort { |a,b| b <=> a },
220
- "categories" => post_attr_hash('categories'),
221
- "topics" => post_attr_hash('topics')
222
- }}
224
+ {"site" => self.config.merge({
225
+ "time" => Time.now,
226
+ "posts" => self.posts.sort { |a,b| b <=> a },
227
+ "categories" => post_attr_hash('categories'),
228
+ "tags" => post_attr_hash('tags')})}
223
229
  end
224
230
 
225
231
  # Filter out any files/directories that are hidden or backup files (start
@@ -233,5 +239,28 @@ module Jekyll
233
239
  end
234
240
  end
235
241
  end
242
+
243
+ # Paginates the blog's posts. Renders the index.html file into paginated directories, ie: page2, page3...
244
+ # and adds more wite-wide data
245
+ #
246
+ # {"paginator" => { "page" => <Number>,
247
+ # "per_page" => <Number>,
248
+ # "posts" => [<Post>],
249
+ # "total_posts" => <Number>,
250
+ # "total_pages" => <Number>,
251
+ # "previous_page" => <Number>,
252
+ # "next_page" => <Number> }}
253
+ def paginate_posts(file, dir)
254
+ all_posts = self.posts.sort { |a,b| b <=> a }
255
+ pages = Pager.calculate_pages(all_posts, self.config['paginate'].to_i)
256
+ pages += 1
257
+ (1..pages).each do |num_page|
258
+ pager = Pager.new(self.config, num_page, all_posts, pages)
259
+ page = Page.new(self, self.source, dir, file)
260
+ page.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
261
+ suffix = "page#{num_page}" if num_page > 1
262
+ page.write(self.dest, suffix)
263
+ end
264
+ end
236
265
  end
237
266
  end
@@ -1,5 +1,5 @@
1
1
  require 'rubygems'
2
- gem 'RedCloth', '= 4.1.0'
2
+ gem 'RedCloth', '= 4.2.1'
3
3
 
4
4
  require File.join(File.dirname(__FILE__), *%w[.. lib jekyll])
5
5
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: A Tag
3
+ tag: code
4
+ ---
5
+
6
+ Whoa.
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Some Tags
3
+ tags:
4
+ - food
5
+ - cooking
6
+ - pizza
7
+ ---
8
+
9
+ Awesome!
@@ -0,0 +1,3 @@
1
+ ---
2
+ ---
3
+ Empty YAML.
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: About
3
+ permalink: /about/
4
+ ---
5
+
6
+ About the site
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Contact Information
3
+ ---
4
+
5
+ Contact Information
@@ -0,0 +1,7 @@
1
+ ---
2
+ layout: post
3
+ title: "Test title"
4
+ tag: "Ruby"
5
+ ---
6
+
7
+ This is the content
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestConfiguration < Test::Unit::TestCase
4
+ context "loading configuration" do
5
+ setup do
6
+ @path = './_config.yml'
7
+ end
8
+
9
+ should "fire warning with no _config.yml" do
10
+ mock(YAML).load_file(@path) { raise "No such file or directory - #{@path}" }
11
+ mock(STDERR).puts("WARNING: Could not read configuration. Using defaults (and options).")
12
+ mock(STDERR).puts("\tNo such file or directory - #{@path}")
13
+ assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
14
+ end
15
+
16
+ should "load configuration as hash" do
17
+ mock(YAML).load_file(@path) { Hash.new }
18
+ mock(STDOUT).puts("Configuration from #{@path}")
19
+ assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
20
+ end
21
+
22
+ should "fire warning with bad config" do
23
+ mock(YAML).load_file(@path) { Array.new }
24
+ mock(STDERR).puts("WARNING: Could not read configuration. Using defaults (and options).")
25
+ mock(STDERR).puts("\tInvalid configuration - #{@path}")
26
+ assert_equal Jekyll::DEFAULTS, Jekyll.configuration({})
27
+ end
28
+ end
29
+ end