qrush-jekyll 0.4.1 → 0.5.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.
data/lib/jekyll/post.rb CHANGED
@@ -3,13 +3,13 @@ module Jekyll
3
3
  class Post
4
4
  include Comparable
5
5
  include Convertible
6
-
6
+
7
7
  class << self
8
8
  attr_accessor :lsi
9
9
  end
10
-
10
+
11
11
  MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
12
-
12
+
13
13
  # Post name validator. Post filenames must be like:
14
14
  # 2008-11-05-my-awesome-post.textile
15
15
  #
@@ -17,50 +17,59 @@ module Jekyll
17
17
  def self.valid?(name)
18
18
  name =~ MATCHER
19
19
  end
20
-
20
+
21
+ attr_accessor :site
21
22
  attr_accessor :date, :slug, :ext, :categories, :topics, :published
22
23
  attr_accessor :data, :content, :output
23
-
24
+
24
25
  # Initialize this Post instance.
26
+ # +site+ is the Site
25
27
  # +base+ is the String path to the dir containing the post file
26
28
  # +name+ is the String filename of the post file
27
29
  # +categories+ is an Array of Strings for the categories for this post
28
30
  #
29
31
  # Returns <Post>
30
- def initialize(source, dir, name)
32
+ def initialize(site, source, dir, name)
33
+ @site = site
31
34
  @base = File.join(source, dir, '_posts')
32
35
  @name = name
33
-
36
+
34
37
  self.categories = dir.split('/').reject { |x| x.empty? }
35
-
38
+
36
39
  parts = name.split('/')
37
40
  self.topics = parts.size > 1 ? parts[0..-2] : []
38
-
41
+
39
42
  self.process(name)
40
43
  self.read_yaml(@base, name)
41
44
 
42
- if self.data.has_key?('published') && self.data['published'] == false
43
- self.published = false
44
- else
45
- self.published = true
46
- end
47
-
45
+ if self.data.has_key?('published') && self.data['published'] == false
46
+ self.published = false
47
+ else
48
+ self.published = true
49
+ end
50
+
48
51
  if self.categories.empty?
49
52
  if self.data.has_key?('category')
50
53
  self.categories << self.data['category']
51
54
  elsif self.data.has_key?('categories')
52
- self.categories = self.data['categories'].split
55
+ # Look for categories in the YAML-header, either specified as
56
+ # an array or a string.
57
+ if self.data['categories'].kind_of? String
58
+ self.categories = self.data['categories'].split
59
+ else
60
+ self.categories = self.data['categories']
61
+ end
53
62
  end
54
63
  end
55
64
  end
56
-
65
+
57
66
  # Spaceship is based on Post#date
58
67
  #
59
68
  # Returns -1, 0, 1
60
69
  def <=>(other)
61
70
  self.date <=> other.date
62
71
  end
63
-
72
+
64
73
  # Extract information from the post filename
65
74
  # +name+ is the String filename of the post file
66
75
  #
@@ -71,7 +80,7 @@ module Jekyll
71
80
  self.slug = slug
72
81
  self.ext = ext
73
82
  end
74
-
83
+
75
84
  # The generated directory into which the post will be placed
76
85
  # upon generation. This is derived from the permalink or, if
77
86
  # permalink is absent, set to the default date
@@ -83,14 +92,14 @@ module Jekyll
83
92
  permalink.to_s.split("/")[0..-2].join("/") + '/'
84
93
  else
85
94
  prefix = self.categories.empty? ? '' : '/' + self.categories.join('/')
86
- if Jekyll.permalink_style == :date
95
+ if [:date, :pretty].include?(self.site.permalink_style)
87
96
  prefix + date.strftime("/%Y/%m/%d/")
88
97
  else
89
98
  prefix + '/'
90
99
  end
91
100
  end
92
101
  end
93
-
102
+
94
103
  # The full path and filename of the post.
95
104
  # Defined in the YAML of the post body
96
105
  # (Optional)
@@ -99,15 +108,16 @@ module Jekyll
99
108
  def permalink
100
109
  self.data && self.data['permalink']
101
110
  end
102
-
111
+
103
112
  # The generated relative url of this post
104
113
  # e.g. /2008/11/05/my-awesome-post.html
105
114
  #
106
115
  # Returns <String>
107
116
  def url
108
- permalink || self.dir + self.slug + ".html"
117
+ ext = self.site.permalink_style == :pretty ? '' : '.html'
118
+ permalink || self.id + ext
109
119
  end
110
-
120
+
111
121
  # The UID for this post (useful in feeds)
112
122
  # e.g. /2008/11/05/my-awesome-post
113
123
  #
@@ -115,14 +125,14 @@ module Jekyll
115
125
  def id
116
126
  self.dir + self.slug
117
127
  end
118
-
128
+
119
129
  # Calculate related posts.
120
130
  #
121
131
  # Returns [<Post>]
122
132
  def related_posts(posts)
123
133
  return [] unless posts.size > 1
124
-
125
- if Jekyll.lsi
134
+
135
+ if self.site.lsi
126
136
  self.class.lsi ||= begin
127
137
  puts "Running the classifier... this could take a while."
128
138
  lsi = Classifier::LSI.new
@@ -137,7 +147,7 @@ module Jekyll
137
147
  (posts - [self])[0..9]
138
148
  end
139
149
  end
140
-
150
+
141
151
  # Add any necessary layouts to this post
142
152
  # +layouts+ is a Hash of {"name" => "layout"}
143
153
  # +site_payload+ is the site payload hash
@@ -151,23 +161,29 @@ module Jekyll
151
161
  "page" => self.to_liquid
152
162
  }
153
163
  payload = payload.deep_merge(site_payload)
154
-
164
+
155
165
  do_layout(payload, layouts)
156
166
  end
157
-
167
+
158
168
  # Write the generated post file to the destination directory.
159
169
  # +dest+ is the String path to the destination dir
160
170
  #
161
171
  # Returns nothing
162
172
  def write(dest)
163
173
  FileUtils.mkdir_p(File.join(dest, dir))
164
-
174
+
165
175
  path = File.join(dest, self.url)
176
+
177
+ if self.site.permalink_style == :pretty
178
+ FileUtils.mkdir_p(path)
179
+ path = File.join(path, "index.html")
180
+ end
181
+
166
182
  File.open(path, 'w') do |f|
167
183
  f.write(self.output)
168
184
  end
169
185
  end
170
-
186
+
171
187
  # Convert this post into a Hash for use in Liquid templates.
172
188
  #
173
189
  # Returns <Hash>
@@ -177,12 +193,34 @@ module Jekyll
177
193
  "date" => self.date,
178
194
  "id" => self.id,
179
195
  "topics" => self.topics,
196
+ "categories" => self.categories,
197
+ "next" => self.next,
198
+ "previous" => self.previous,
180
199
  "content" => self.content }.deep_merge(self.data)
181
200
  end
182
-
201
+
183
202
  def inspect
184
203
  "<Post: #{self.id}>"
185
204
  end
205
+
206
+ def next
207
+ pos = self.site.posts.index(self)
208
+
209
+ if pos && pos < self.site.posts.length-1
210
+ self.site.posts[pos+1]
211
+ else
212
+ nil
213
+ end
214
+ end
215
+
216
+ def previous
217
+ pos = self.site.posts.index(self)
218
+ if pos && pos > 0
219
+ self.site.posts[pos-1]
220
+ else
221
+ nil
222
+ end
223
+ end
186
224
  end
187
225
 
188
226
  end
data/lib/jekyll/site.rb CHANGED
@@ -1,68 +1,127 @@
1
1
  module Jekyll
2
-
2
+
3
3
  class Site
4
- attr_accessor :source, :dest
5
- attr_accessor :layouts, :posts, :categories
6
-
4
+ attr_accessor :config, :layouts, :posts, :categories
5
+ attr_accessor :source, :dest, :lsi, :pygments, :permalink_style
6
+
7
7
  # Initialize the site
8
- # +source+ is String path to the source directory containing
9
- # the proto-site
10
- # +dest+ is the String path to the directory where the generated
11
- # site should be written
8
+ # +config+ is a Hash containing site configurations details
12
9
  #
13
10
  # Returns <Site>
14
- def initialize(source, dest)
15
- self.source = source
16
- self.dest = dest
17
- self.layouts = {}
18
- self.posts = []
19
- self.categories = Hash.new { |hash, key| hash[key] = Array.new }
11
+ def initialize(config)
12
+ self.config = config.clone
13
+
14
+ self.source = config['source']
15
+ self.dest = config['destination']
16
+ self.lsi = config['lsi']
17
+ self.pygments = config['pygments']
18
+ self.permalink_style = config['permalink'].to_sym
19
+
20
+ self.reset
21
+ self.setup
22
+ end
23
+
24
+ def reset
25
+ self.layouts = {}
26
+ self.posts = []
27
+ self.categories = Hash.new { |hash, key| hash[key] = Array.new }
28
+ end
29
+
30
+ def setup
31
+ # Check to see if LSI is enabled.
32
+ require 'classifier' if self.lsi
33
+
34
+ # Set the Markdown interpreter (and Maruku self.config, if necessary)
35
+ case self.config['markdown']
36
+ when 'rdiscount'
37
+ begin
38
+ require 'rdiscount'
39
+
40
+ def markdown(content)
41
+ RDiscount.new(content).to_html
42
+ end
43
+
44
+ puts 'Using rdiscount for Markdown'
45
+ rescue LoadError
46
+ puts 'You must have the rdiscount gem installed first'
47
+ end
48
+ when 'maruku'
49
+ begin
50
+ require 'maruku'
51
+
52
+ def markdown(content)
53
+ Maruku.new(content).to_html
54
+ end
55
+
56
+ if self.config['maruku']['use_divs']
57
+ require 'maruku/ext/div'
58
+ puts 'Maruku: Using extended syntax for div elements.'
59
+ end
60
+
61
+ if self.config['maruku']['use_tex']
62
+ require 'maruku/ext/math'
63
+ puts "Maruku: Using LaTeX extension. Images in `#{self.config['maruku']['png_dir']}`."
64
+
65
+ # Switch off MathML output
66
+ MaRuKu::Globals[:html_math_output_mathml] = false
67
+ MaRuKu::Globals[:html_math_engine] = 'none'
68
+
69
+ # Turn on math to PNG support with blahtex
70
+ # Resulting PNGs stored in `images/latex`
71
+ MaRuKu::Globals[:html_math_output_png] = true
72
+ MaRuKu::Globals[:html_png_engine] = self.config['maruku']['png_engine']
73
+ MaRuKu::Globals[:html_png_dir] = self.config['maruku']['png_dir']
74
+ MaRuKu::Globals[:html_png_url] = self.config['maruku']['png_url']
75
+ end
76
+ rescue LoadError
77
+ puts "The maruku gem is required for markdown support!"
78
+ end
79
+ end
20
80
  end
21
-
81
+
82
+ def textile(content)
83
+ RedCloth.new(content).to_html
84
+ end
85
+
22
86
  # Do the actual work of processing the site and generating the
23
87
  # real deal.
24
88
  #
25
89
  # Returns nothing
26
90
  def process
91
+ self.reset
27
92
  self.read_layouts
28
93
  self.transform_pages
29
94
  self.write_posts
30
95
  end
31
-
32
- # Read all the files in <source>/_layouts except backup files
33
- # (end with "~") into memory for later use.
96
+
97
+ # Read all the files in <source>/_layouts into memory for later use.
34
98
  #
35
99
  # Returns nothing
36
100
  def read_layouts
37
101
  base = File.join(self.source, "_layouts")
38
- entries = Dir.entries(base)
39
- entries = entries.reject { |e| e[-1..-1] == '~' }
40
- entries = entries.reject { |e| File.directory?(File.join(base, e)) }
41
-
102
+ entries = []
103
+ Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
104
+
42
105
  entries.each do |f|
43
106
  name = f.split(".")[0..-2].join(".")
44
- self.layouts[name] = Layout.new(base, f)
107
+ self.layouts[name] = Layout.new(self, base, f)
45
108
  end
46
109
  rescue Errno::ENOENT => e
47
110
  # ignore missing layout dir
48
111
  end
49
-
50
- # Read all the files in <base>/_posts except backup files (end with "~")
51
- # and create a new Post object with each one.
112
+
113
+ # Read all the files in <base>/_posts and create a new Post object with each one.
52
114
  #
53
115
  # Returns nothing
54
116
  def read_posts(dir)
55
117
  base = File.join(self.source, dir, '_posts')
56
-
57
118
  entries = []
58
- Dir.chdir(base) { entries = Dir['**/*'] }
59
- entries = entries.reject { |e| e[-1..-1] == '~' }
60
- entries = entries.reject { |e| File.directory?(File.join(base, e)) }
119
+ Dir.chdir(base) { entries = filter_entries(Dir['**/*']) }
61
120
 
62
121
  # first pass processes, but does not yet render post content
63
122
  entries.each do |f|
64
123
  if Post.valid?(f)
65
- post = Post.new(self.source, dir, f)
124
+ post = Post.new(self, self.source, dir, f)
66
125
 
67
126
  if post.published
68
127
  self.posts << post
@@ -70,18 +129,18 @@ module Jekyll
70
129
  end
71
130
  end
72
131
  end
73
-
132
+
74
133
  # second pass renders each post now that full site payload is available
75
134
  self.posts.each do |post|
76
135
  post.render(self.layouts, site_payload)
77
136
  end
78
-
137
+
79
138
  self.posts.sort!
80
139
  self.categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
81
140
  rescue Errno::ENOENT => e
82
141
  # ignore missing layout dir
83
142
  end
84
-
143
+
85
144
  # Write each post to <dest>/<year>/<month>/<day>/<slug>
86
145
  #
87
146
  # Returns nothing
@@ -90,10 +149,10 @@ module Jekyll
90
149
  post.write(self.dest)
91
150
  end
92
151
  end
93
-
152
+
94
153
  # Copy all regular files from <source> to <dest>/ ignoring
95
154
  # any files/directories that are hidden or backup files (start
96
- # with "." or end with "~") or contain site content (start with "_")
155
+ # with "." or "#" or end with "~") or contain site content (start with "_")
97
156
  # unless they are "_posts" directories or web server files such as
98
157
  # '.htaccess'
99
158
  # The +dir+ String is a relative path used to call this method
@@ -102,18 +161,14 @@ module Jekyll
102
161
  # Returns nothing
103
162
  def transform_pages(dir = '')
104
163
  base = File.join(self.source, dir)
105
- entries = Dir.entries(base)
106
- entries = entries.reject { |e| e[-1..-1] == '~' }
107
- entries = entries.reject do |e|
108
- (e != '_posts') and ['.', '_'].include?(e[0..0]) unless ['.htaccess'].include?(e)
109
- end
164
+ entries = filter_entries(Dir.entries(base))
110
165
  directories = entries.select { |e| File.directory?(File.join(base, e)) }
111
166
  files = entries.reject { |e| File.directory?(File.join(base, e)) }
112
167
 
113
- # we need to make sure to process _posts *first* otherwise they
168
+ # we need to make sure to process _posts *first* otherwise they
114
169
  # might not be available yet to other templates as {{ site.posts }}
115
- if entries.include?('_posts')
116
- entries.delete('_posts')
170
+ if directories.include?('_posts')
171
+ directories.delete('_posts')
117
172
  read_posts(dir)
118
173
  end
119
174
  [directories, files].each do |entries|
@@ -123,10 +178,10 @@ module Jekyll
123
178
  transform_pages(File.join(dir, f))
124
179
  else
125
180
  first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) }
126
-
181
+
127
182
  if first3 == "---"
128
183
  # file appears to have a YAML header so process it as a page
129
- page = Page.new(self.source, dir, f)
184
+ page = Page.new(self, self.source, dir, f)
130
185
  page.render(self.layouts, site_payload)
131
186
  page.write(self.dest)
132
187
  else
@@ -159,12 +214,25 @@ module Jekyll
159
214
  # "topics" => [<Post>] }}
160
215
  def site_payload
161
216
  {"site" => {
162
- "time" => Time.now,
217
+ "time" => Time.now,
163
218
  "posts" => self.posts.sort { |a,b| b <=> a },
164
219
  "categories" => post_attr_hash('categories'),
165
220
  "topics" => post_attr_hash('topics')
166
221
  }}
167
222
  end
168
- end
169
223
 
224
+ # Filter out any files/directories that are hidden or backup files (start
225
+ # with "." or "#" or end with "~") or contain site content (start with "_")
226
+ # unless they are "_posts" directories or web server files such as
227
+ # '.htaccess'
228
+ def filter_entries(entries)
229
+ entries = entries.reject do |e|
230
+ unless ['_posts', '.htaccess'].include?(e)
231
+ # Reject backup/hidden
232
+ ['.', '_', '#'].include?(e[0..0]) or e[-1..-1] == '~'
233
+ end
234
+ end
235
+ end
236
+
237
+ end
170
238
  end