nirvdrum-jekyll 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,3 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
1
  # -*- encoding: utf-8 -*-
5
2
 
6
3
  Gem::Specification.new do |s|
@@ -9,7 +6,7 @@ Gem::Specification.new do |s|
9
6
 
10
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
8
  s.authors = ["Tom Preston-Werner"]
12
- s.date = %q{2010-02-11}
9
+ s.date = %q{2009-07-14}
13
10
  s.default_executable = %q{jekyll}
14
11
  s.description = %q{Jekyll is a simple, blog aware, static site generator.}
15
12
  s.email = %q{tom@mojombo.com}
@@ -71,15 +68,15 @@ Gem::Specification.new do |s|
71
68
  "test/source/_posts/2009-05-18-tags.textile",
72
69
  "test/source/_posts/2009-06-22-empty-yaml.textile",
73
70
  "test/source/_posts/2009-06-22-no-yaml.textile",
74
- "test/source/_stylesheets/nested/override.less",
75
- "test/source/_stylesheets/simple.less",
71
+ "test/source/_posts/2010-01-08-triple-dash.markdown",
72
+ "test/source/_posts/2010-01-09-date-override.textile",
73
+ "test/source/_posts/2010-01-09-time-override.textile",
76
74
  "test/source/about.html",
77
75
  "test/source/category/_posts/2008-9-23-categories.textile",
78
76
  "test/source/contacts.html",
79
77
  "test/source/css/screen.css",
80
78
  "test/source/foo/_posts/bar/2008-12-12-topical-post.textile",
81
79
  "test/source/index.html",
82
- "test/source/sitemap.xml",
83
80
  "test/source/win/_posts/2009-05-24-yaml-linebreak.markdown",
84
81
  "test/source/z_category/_posts/2008-9-23-categories.textile",
85
82
  "test/suite.rb",
@@ -97,7 +94,6 @@ Gem::Specification.new do |s|
97
94
  s.rdoc_options = ["--charset=UTF-8"]
98
95
  s.require_paths = ["lib"]
99
96
  s.rubyforge_project = %q{jekyll}
100
- s.rubygems_version = %q{1.3.5}
101
97
  s.summary = %q{Jekyll is a simple, blog aware, static site generator.}
102
98
  s.test_files = [
103
99
  "test/helper.rb",
@@ -141,4 +137,3 @@ Gem::Specification.new do |s|
141
137
  s.add_dependency(%q<open4>, [">= 0.9.6"])
142
138
  end
143
139
  end
144
-
@@ -27,6 +27,7 @@ require 'jekyll/filters'
27
27
  require 'jekyll/tags/highlight'
28
28
  require 'jekyll/tags/include'
29
29
  require 'jekyll/albino'
30
+ require 'jekyll/static_file'
30
31
 
31
32
  module Jekyll
32
33
  # Default options. Overriden by values in _config.yml or command-line opts.
@@ -68,10 +69,10 @@ module Jekyll
68
69
  begin
69
70
  config = YAML.load_file(config_file)
70
71
  raise "Invalid configuration - #{config_file}" if !config.is_a?(Hash)
71
- STDOUT.puts "Configuration from #{config_file}"
72
+ $stdout.puts "Configuration from #{config_file}"
72
73
  rescue => err
73
- STDERR.puts "WARNING: Could not read configuration. Using defaults (and options)."
74
- STDERR.puts "\t" + err.to_s
74
+ $stderr.puts "WARNING: Could not read configuration. Using defaults (and options)."
75
+ $stderr.puts "\t" + err.to_s
75
76
  config = {}
76
77
  end
77
78
 
@@ -3,6 +3,10 @@
3
3
  #
4
4
  # Requires
5
5
  # self.site -> Jekyll::Site
6
+ # self.content=
7
+ # self.data=
8
+ # self.ext=
9
+ # self.output=
6
10
  module Jekyll
7
11
  module Convertible
8
12
  # Return the contents as a string
@@ -18,7 +22,7 @@ module Jekyll
18
22
  def read_yaml(base, name)
19
23
  self.content = File.read(File.join(base, name))
20
24
 
21
- if self.content =~ /^(---\s*\n.*?\n?)(---.*?\n)/m
25
+ if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
22
26
  self.content = self.content[($1.size + $2.size)..-1]
23
27
 
24
28
  self.data = YAML.load($1)
@@ -52,7 +56,7 @@ module Jekyll
52
56
  case self.ext[1..-1]
53
57
  when /textile/i
54
58
  return 'textile'
55
- when /markdown/i, /mkdn/i, /md/i
59
+ when /markdown/i, /mkdn/i, /md/i, /mkd/i
56
60
  return 'markdown'
57
61
  when /less/i
58
62
  return 'less'
@@ -19,6 +19,28 @@ class Hash
19
19
 
20
20
  target
21
21
  end
22
+
23
+ # Read array from the supplied hash favouring the singular key
24
+ # and then the plural key, and handling any nil entries.
25
+ # +hash+ the hash to read from
26
+ # +singular_key+ the singular key
27
+ # +plural_key+ the singular key
28
+ #
29
+ # Returns an array
30
+ def pluralized_array(singular_key, plural_key)
31
+ hash = self
32
+ if hash.has_key?(singular_key)
33
+ array = [hash[singular_key]] if hash[singular_key]
34
+ elsif hash.has_key?(plural_key)
35
+ case hash[plural_key]
36
+ when String
37
+ array = hash[plural_key].split
38
+ when Array
39
+ array = hash[plural_key].compact
40
+ end
41
+ end
42
+ array || []
43
+ end
22
44
  end
23
45
 
24
46
  # Thanks, ActiveSupport!
@@ -4,7 +4,7 @@ module Jekyll
4
4
  include Convertible
5
5
 
6
6
  attr_accessor :site
7
- attr_accessor :name, :ext, :basename
7
+ attr_accessor :name, :ext, :basename, :dir
8
8
  attr_accessor :data, :content, :output
9
9
 
10
10
  # Initialize a new Page.
@@ -101,6 +101,10 @@ module Jekyll
101
101
  end
102
102
  end
103
103
 
104
+ def inspect
105
+ "#<Jekyll:Page @name=#{self.name.inspect}>"
106
+ end
107
+
104
108
  private
105
109
 
106
110
  def index?
@@ -4,7 +4,7 @@ module Jekyll
4
4
 
5
5
  def self.calculate_pages(all_posts, per_page)
6
6
  num_pages = all_posts.size / per_page.to_i
7
- num_pages.abs + 1 if all_posts.size % per_page.to_i != 0
7
+ num_pages = num_pages + 1 if all_posts.size % per_page.to_i != 0
8
8
  num_pages
9
9
  end
10
10
 
@@ -18,12 +18,9 @@ module Jekyll
18
18
  name =~ MATCHER
19
19
  end
20
20
 
21
- attr_accessor :site, :date, :slug, :ext, :published, :data, :content, :output, :tags
22
- attr_writer :categories
23
-
24
- def categories
25
- @categories ||= []
26
- end
21
+ attr_accessor :site
22
+ attr_accessor :data, :content, :output, :ext
23
+ attr_accessor :date, :slug, :published, :tags, :categories
27
24
 
28
25
  # Initialize this Post instance.
29
26
  # +site+ is the Site
@@ -41,32 +38,23 @@ module Jekyll
41
38
  self.process(name)
42
39
  self.read_yaml(@base, name)
43
40
 
41
+ #If we've added a date and time to the yaml, use that instead of the filename date
42
+ #Means we'll sort correctly.
43
+ if self.data.has_key?('date')
44
+ # ensure Time via to_s and reparse
45
+ self.date = Time.parse(self.data["date"].to_s)
46
+ end
47
+
44
48
  if self.data.has_key?('published') && self.data['published'] == false
45
49
  self.published = false
46
50
  else
47
51
  self.published = true
48
52
  end
49
53
 
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
54
+ self.tags = self.data.pluralized_array("tag", "tags")
57
55
 
58
56
  if self.categories.empty?
59
- if self.data.has_key?('category')
60
- self.categories << self.data['category']
61
- elsif self.data.has_key?('categories')
62
- # Look for categories in the YAML-header, either specified as
63
- # an array or a string.
64
- if self.data['categories'].kind_of? String
65
- self.categories = self.data['categories'].split
66
- else
67
- self.categories = self.data['categories']
68
- end
69
- end
57
+ self.categories = self.data.pluralized_array('category', 'categories')
70
58
  end
71
59
  end
72
60
 
@@ -136,7 +124,7 @@ module Jekyll
136
124
  "month" => date.strftime("%m"),
137
125
  "day" => date.strftime("%d"),
138
126
  "title" => CGI.escape(slug),
139
- "categories" => categories.sort.join('/')
127
+ "categories" => categories.join('/')
140
128
  }.inject(template) { |result, token|
141
129
  result.gsub(/:#{token.first}/, token.last)
142
130
  }.gsub(/\/\//, "/")
@@ -1,7 +1,7 @@
1
1
  module Jekyll
2
2
 
3
3
  class Site
4
- attr_accessor :config, :layouts, :posts, :categories, :exclude,
4
+ attr_accessor :config, :layouts, :stylesheets, :posts, :pages, :static_files, :categories, :exclude,
5
5
  :source, :dest, :lsi, :pygments, :permalink_style, :tags
6
6
 
7
7
  # Initialize the site
@@ -11,7 +11,7 @@ module Jekyll
11
11
  def initialize(config)
12
12
  self.config = config.clone
13
13
 
14
- self.source = config['source']
14
+ self.source = File.expand_path(config['source'])
15
15
  self.dest = config['destination']
16
16
  self.lsi = config['lsi']
17
17
  self.pygments = config['pygments']
@@ -24,7 +24,10 @@ module Jekyll
24
24
 
25
25
  def reset
26
26
  self.layouts = {}
27
+ self.stylesheets = []
27
28
  self.posts = []
29
+ self.pages = []
30
+ self.static_files = []
28
31
  self.categories = Hash.new { |hash, key| hash[key] = [] }
29
32
  self.tags = Hash.new { |hash, key| hash[key] = [] }
30
33
  end
@@ -97,22 +100,29 @@ module Jekyll
97
100
  end
98
101
 
99
102
  # Do the actual work of processing the site and generating the
100
- # real deal.
103
+ # real deal. Now has 4 phases; reset, read, render, write. This allows
104
+ # rendering to have full site payload available.
101
105
  #
102
106
  # Returns nothing
103
107
  def process
104
108
  self.reset
105
- self.read_layouts
106
- self.transform_stylesheets
107
- self.transform_pages
108
- self.write_posts
109
+ self.read
110
+ self.render
111
+ self.write
109
112
  end
110
113
 
111
- # Read all the files in <source>/_layouts into memory for later use.
114
+ def read
115
+ self.read_layouts # existing implementation did this at top level only so preserved that
116
+ self.read_directories
117
+ end
118
+
119
+ # Read all the files in <source>/<dir>/_layouts and create a new Layout
120
+ # object with each one.
112
121
  #
113
122
  # Returns nothing
114
- def read_layouts
115
- base = File.join(self.source, "_layouts")
123
+ def read_layouts(dir = '')
124
+ base = File.join(self.source, dir, "_layouts")
125
+ return unless File.exists?(base)
116
126
  entries = []
117
127
  Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
118
128
 
@@ -120,17 +130,16 @@ module Jekyll
120
130
  name = f.split(".")[0..-2].join(".")
121
131
  self.layouts[name] = Layout.new(self, base, f)
122
132
  end
123
- rescue Errno::ENOENT => e
124
- # ignore missing layout dir
125
133
  end
126
134
 
127
- # Read all the files in <base>/_posts and create a new Post object with each one.
135
+ # Read all the files in <source>/<dir>/_posts and create a new Post
136
+ # object with each one.
128
137
  #
129
138
  # Returns nothing
130
139
  def read_posts(dir)
131
140
  base = File.join(self.source, dir, '_posts')
132
- entries = []
133
- Dir.chdir(base) { entries = filter_entries(Dir['**/*']) }
141
+ return unless File.exists?(base)
142
+ entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
134
143
 
135
144
  # first pass processes, but does not yet render post content
136
145
  entries.each do |f|
@@ -146,87 +155,86 @@ module Jekyll
146
155
  end
147
156
 
148
157
  self.posts.sort!
158
+ end
159
+
160
+ def read_stylesheets(dir)
161
+ base = File.join(self.source, dir, '_stylesheets')
162
+ return unless File.exists?(base)
163
+
164
+ entries = []
165
+ Dir.chdir(base) { entries = filter_entries(Dir['**/*.*']) }
166
+
167
+ entries.each do |f|
168
+ stylesheet = Stylesheet.new(self, base, dir, f)
169
+ stylesheet.render()
170
+ stylesheet.write(self.dest)
171
+ end
172
+ end
149
173
 
150
- # second pass renders each post now that full site payload is available
174
+ def render
151
175
  self.posts.each do |post|
152
176
  post.render(self.layouts, site_payload)
153
177
  end
154
178
 
179
+ self.pages.dup.each do |page|
180
+ if Pager.pagination_enabled?(self.config, page.name)
181
+ paginate(page)
182
+ else
183
+ page.render(self.layouts, site_payload)
184
+ end
185
+ end
186
+
155
187
  self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
156
188
  self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
157
189
  rescue Errno::ENOENT => e
158
190
  # ignore missing layout dir
159
191
  end
160
192
 
161
- # Write each post to <dest>/<year>/<month>/<day>/<slug>
193
+ # Write static files, pages and posts
162
194
  #
163
195
  # Returns nothing
164
- def write_posts
196
+ def write
165
197
  self.posts.each do |post|
166
198
  post.write(self.dest)
167
199
  end
200
+ self.pages.each do |page|
201
+ page.write(self.dest)
202
+ end
203
+ self.static_files.each do |sf|
204
+ sf.write(self.dest)
205
+ end
168
206
  end
169
207
 
170
- # Copy all regular files from <source> to <dest>/ ignoring
171
- # any files/directories that are hidden or backup files (start
172
- # with "." or "#" or end with "~") or contain site content (start with "_")
173
- # unless they are "_posts" directories or web server files such as
174
- # '.htaccess'
208
+ # Reads the directories and finds posts, pages and static files that will
209
+ # become part of the valid site according to the rules in +filter_entries+.
175
210
  # The +dir+ String is a relative path used to call this method
176
211
  # recursively as it descends through directories
177
212
  #
178
213
  # Returns nothing
179
- def transform_pages(dir = '')
214
+ def read_directories(dir = '')
180
215
  base = File.join(self.source, dir)
181
216
  entries = filter_entries(Dir.entries(base))
182
- directories = entries.select { |e| File.directory?(File.join(base, e)) }
183
- files = entries.reject { |e| File.directory?(File.join(base, e)) }
184
-
185
- # we need to make sure to process _posts *first* otherwise they
186
- # might not be available yet to other templates as {{ site.posts }}
187
- if directories.include?('_posts')
188
- directories.delete('_posts')
189
- read_posts(dir)
190
- end
191
-
192
- [directories, files].each do |entries|
193
- entries.each do |f|
194
- if File.directory?(File.join(base, f))
195
- next if self.dest.sub(/\/$/, '') == File.join(base, f)
196
- transform_pages(File.join(dir, f))
197
- elsif Pager.pagination_enabled?(self.config, f)
198
- paginate_posts(f, dir)
199
- else
200
- first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) }
201
-
202
- if first3 == "---"
203
- # file appears to have a YAML header so process it as a page
204
- page = Page.new(self, self.source, dir, f)
205
- page.render(self.layouts, site_payload)
206
- page.write(self.dest)
207
- else
208
- # otherwise copy the file without transforming it
209
- FileUtils.mkdir_p(File.join(self.dest, dir))
210
- FileUtils.cp(File.join(self.source, dir, f), File.join(self.dest, dir, f))
211
- end
212
- end
213
- end
214
- end
215
- end
216
217
 
217
- def transform_stylesheets
218
- dir = "_stylesheets"
219
- base = File.join(self.source, dir)
220
- entries = []
221
- Dir.chdir(base) { entries = filter_entries(Dir['**/*.*']) }
218
+ self.read_posts(dir)
219
+ self.read_stylesheets(dir)
222
220
 
223
221
  entries.each do |f|
224
- stylesheet = Stylesheet.new(self, self.source, dir, f)
225
- stylesheet.render()
226
- stylesheet.write(self.dest)
222
+ f_abs = File.join(base, f)
223
+ f_rel = File.join(dir, f)
224
+ if File.directory?(f_abs)
225
+ next if self.dest.sub(/\/$/, '') == f_abs
226
+ read_directories(f_rel)
227
+ elsif !File.symlink?(f_abs)
228
+ first3 = File.open(f_abs) { |fd| fd.read(3) }
229
+ if first3 == "---"
230
+ # file appears to have a YAML header so process it as a page
231
+ pages << Page.new(self, self.source, dir, f)
232
+ else
233
+ # otherwise treat it as a static file
234
+ static_files << StaticFile.new(self, self.source, dir, f)
235
+ end
236
+ end
227
237
  end
228
- rescue Errno::ENOENT => e
229
- # ignore missing stylesheet dir
230
238
  end
231
239
 
232
240
  # Constructs a hash map of Posts indexed by the specified Post attribute
@@ -255,19 +263,21 @@ module Jekyll
255
263
  end
256
264
 
257
265
  # Filter out any files/directories that are hidden or backup files (start
258
- # with "." or "#" or end with "~") or contain site content (start with "_")
259
- # unless they are "_posts" directories or web server files such as
260
- # '.htaccess'
266
+ # with "." or "#" or end with "~"), or contain site content (start with "_"),
267
+ # or are excluded in the site configuration, unless they are web server
268
+ # files such as '.htaccess'
261
269
  def filter_entries(entries)
262
270
  entries = entries.reject do |e|
263
- unless ['_posts', '.htaccess'].include?(e)
271
+ unless ['.htaccess'].include?(e)
264
272
  ['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
265
273
  end
266
274
  end
267
275
  end
268
276
 
269
- # Paginates the blog's posts. Renders the index.html file into paginated directories, ie: page2, page3...
270
- # and adds more wite-wide data
277
+ # Paginates the blog's posts. Renders the index.html file into paginated
278
+ # directories, ie: page2/index.html, page3/index.html, etc and adds more
279
+ # site-wide data.
280
+ # +page+ is the index.html Page that requires pagination
271
281
  #
272
282
  # {"paginator" => { "page" => <Number>,
273
283
  # "per_page" => <Number>,
@@ -276,16 +286,19 @@ module Jekyll
276
286
  # "total_pages" => <Number>,
277
287
  # "previous_page" => <Number>,
278
288
  # "next_page" => <Number> }}
279
- def paginate_posts(file, dir)
280
- all_posts = self.posts.sort { |a,b| b <=> a }
289
+ def paginate(page)
290
+ all_posts = site_payload['site']['posts']
281
291
  pages = Pager.calculate_pages(all_posts, self.config['paginate'].to_i)
282
- pages += 1
283
292
  (1..pages).each do |num_page|
284
293
  pager = Pager.new(self.config, num_page, all_posts, pages)
285
- page = Page.new(self, self.source, dir, file)
286
- page.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
287
- suffix = "page#{num_page}" if num_page > 1
288
- page.write(self.dest, suffix)
294
+ if num_page > 1
295
+ newpage = Page.new(self, self.source, page.dir, page.name)
296
+ newpage.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
297
+ newpage.dir = File.join(page.dir, "page#{num_page}")
298
+ self.pages << newpage
299
+ else
300
+ page.render(self.layouts, site_payload.merge({'paginator' => pager.to_hash}))
301
+ end
289
302
  end
290
303
  end
291
304
  end