codeslinger-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.
@@ -1,6 +1,10 @@
1
1
  module Jekyll
2
-
2
+
3
3
  module Filters
4
+ def textilize(input)
5
+ RedCloth.new(input).to_html
6
+ end
7
+
4
8
  def date_to_string(date)
5
9
  date.strftime("%d %b %Y")
6
10
  end
@@ -8,19 +12,19 @@ module Jekyll
8
12
  def date_to_long_string(date)
9
13
  date.strftime("%d %B %Y")
10
14
  end
11
-
15
+
12
16
  def date_to_xmlschema(date)
13
17
  date.xmlschema
14
18
  end
15
-
19
+
16
20
  def xml_escape(input)
17
21
  input.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
18
22
  end
19
-
23
+
20
24
  def number_of_words(input)
21
25
  input.split.length
22
26
  end
23
-
27
+
24
28
  def array_to_sentence_string(array)
25
29
  connector = "and"
26
30
  case array.length
@@ -35,5 +39,5 @@ module Jekyll
35
39
  end
36
40
  end
37
41
 
38
- end
42
+ end
39
43
  end
data/lib/jekyll/layout.rb CHANGED
@@ -2,25 +2,28 @@ module Jekyll
2
2
 
3
3
  class Layout
4
4
  include Convertible
5
-
5
+
6
+ attr_accessor :site
6
7
  attr_accessor :ext
7
8
  attr_accessor :data, :content
8
-
9
+
9
10
  # Initialize a new Layout.
11
+ # +site+ is the Site
10
12
  # +base+ is the String path to the <source>
11
13
  # +name+ is the String filename of the post file
12
14
  #
13
15
  # Returns <Page>
14
- def initialize(base, name)
16
+ def initialize(site, base, name)
17
+ @site = site
15
18
  @base = base
16
19
  @name = name
17
-
20
+
18
21
  self.data = {}
19
-
22
+
20
23
  self.process(name)
21
24
  self.read_yaml(base, name)
22
25
  end
23
-
26
+
24
27
  # Extract information from the layout filename
25
28
  # +name+ is the String filename of the layout file
26
29
  #
data/lib/jekyll/page.rb CHANGED
@@ -2,28 +2,31 @@ module Jekyll
2
2
 
3
3
  class Page
4
4
  include Convertible
5
-
5
+
6
+ attr_accessor :site
6
7
  attr_accessor :ext
7
8
  attr_accessor :data, :content, :output
8
-
9
+
9
10
  # Initialize a new Page.
11
+ # +site+ is the Site
10
12
  # +base+ is the String path to the <source>
11
13
  # +dir+ is the String path between <source> and the file
12
14
  # +name+ is the String filename of the file
13
15
  #
14
16
  # Returns <Page>
15
- def initialize(base, dir, name)
17
+ def initialize(site, base, dir, name)
18
+ @site = site
16
19
  @base = base
17
20
  @dir = dir
18
21
  @name = name
19
-
22
+
20
23
  self.data = {}
21
-
24
+
22
25
  self.process(name)
23
26
  self.read_yaml(File.join(base, dir), name)
24
27
  #self.transform
25
28
  end
26
-
29
+
27
30
  # Extract information from the page filename
28
31
  # +name+ is the String filename of the page file
29
32
  #
@@ -31,7 +34,7 @@ module Jekyll
31
34
  def process(name)
32
35
  self.ext = File.extname(name)
33
36
  end
34
-
37
+
35
38
  # Add any necessary layouts to this post
36
39
  # +layouts+ is a Hash of {"name" => "layout"}
37
40
  # +site_payload+ is the site payload hash
@@ -41,19 +44,19 @@ module Jekyll
41
44
  payload = {"page" => self.data}.deep_merge(site_payload)
42
45
  do_layout(payload, layouts)
43
46
  end
44
-
47
+
45
48
  # Write the generated page file to the destination directory.
46
49
  # +dest+ is the String path to the destination dir
47
50
  #
48
51
  # Returns nothing
49
52
  def write(dest)
50
53
  FileUtils.mkdir_p(File.join(dest, @dir))
51
-
54
+
52
55
  name = @name
53
56
  if self.ext != ""
54
57
  name = @name.split(".")[0..-2].join('.') + self.ext
55
58
  end
56
-
59
+
57
60
  path = File.join(dest, @dir, name)
58
61
  File.open(path, 'w') do |f|
59
62
  f.write(self.output)
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,36 +17,59 @@ module Jekyll
17
17
  def self.valid?(name)
18
18
  name =~ MATCHER
19
19
  end
20
-
21
- attr_accessor :date, :slug, :ext, :categories, :topics
20
+
21
+ attr_accessor :site
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)
44
+
45
+ if self.data.has_key?('published') && self.data['published'] == false
46
+ self.published = false
47
+ else
48
+ self.published = true
49
+ end
50
+
51
+ if self.categories.empty?
52
+ if self.data.has_key?('category')
53
+ self.categories << self.data['category']
54
+ elsif self.data.has_key?('categories')
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
62
+ end
63
+ end
41
64
  end
42
-
65
+
43
66
  # Spaceship is based on Post#date
44
67
  #
45
68
  # Returns -1, 0, 1
46
69
  def <=>(other)
47
70
  self.date <=> other.date
48
71
  end
49
-
72
+
50
73
  # Extract information from the post filename
51
74
  # +name+ is the String filename of the post file
52
75
  #
@@ -57,7 +80,7 @@ module Jekyll
57
80
  self.slug = slug
58
81
  self.ext = ext
59
82
  end
60
-
83
+
61
84
  # The generated directory into which the post will be placed
62
85
  # upon generation. This is derived from the permalink or, if
63
86
  # permalink is absent, set to the default date
@@ -69,14 +92,14 @@ module Jekyll
69
92
  permalink.to_s.split("/")[0..-2].join("/") + '/'
70
93
  else
71
94
  prefix = self.categories.empty? ? '' : '/' + self.categories.join('/')
72
- if Jekyll.permalink_style == :date
95
+ if [:date, :pretty].include?(self.site.permalink_style)
73
96
  prefix + date.strftime("/%Y/%m/%d/")
74
97
  else
75
98
  prefix + '/'
76
99
  end
77
100
  end
78
101
  end
79
-
102
+
80
103
  # The full path and filename of the post.
81
104
  # Defined in the YAML of the post body
82
105
  # (Optional)
@@ -85,15 +108,16 @@ module Jekyll
85
108
  def permalink
86
109
  self.data && self.data['permalink']
87
110
  end
88
-
111
+
89
112
  # The generated relative url of this post
90
113
  # e.g. /2008/11/05/my-awesome-post.html
91
114
  #
92
115
  # Returns <String>
93
116
  def url
94
- permalink || self.dir + self.slug + ".html"
117
+ ext = self.site.permalink_style == :pretty ? '' : '.html'
118
+ permalink || self.id + ext
95
119
  end
96
-
120
+
97
121
  # The UID for this post (useful in feeds)
98
122
  # e.g. /2008/11/05/my-awesome-post
99
123
  #
@@ -101,14 +125,14 @@ module Jekyll
101
125
  def id
102
126
  self.dir + self.slug
103
127
  end
104
-
128
+
105
129
  # Calculate related posts.
106
130
  #
107
131
  # Returns [<Post>]
108
132
  def related_posts(posts)
109
133
  return [] unless posts.size > 1
110
-
111
- if Jekyll.lsi
134
+
135
+ if self.site.lsi
112
136
  self.class.lsi ||= begin
113
137
  puts "Running the classifier... this could take a while."
114
138
  lsi = Classifier::LSI.new
@@ -123,7 +147,7 @@ module Jekyll
123
147
  (posts - [self])[0..9]
124
148
  end
125
149
  end
126
-
150
+
127
151
  # Add any necessary layouts to this post
128
152
  # +layouts+ is a Hash of {"name" => "layout"}
129
153
  # +site_payload+ is the site payload hash
@@ -137,23 +161,29 @@ module Jekyll
137
161
  "page" => self.to_liquid
138
162
  }
139
163
  payload = payload.deep_merge(site_payload)
140
-
164
+
141
165
  do_layout(payload, layouts)
142
166
  end
143
-
167
+
144
168
  # Write the generated post file to the destination directory.
145
169
  # +dest+ is the String path to the destination dir
146
170
  #
147
171
  # Returns nothing
148
172
  def write(dest)
149
173
  FileUtils.mkdir_p(File.join(dest, dir))
150
-
174
+
151
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
+
152
182
  File.open(path, 'w') do |f|
153
183
  f.write(self.output)
154
184
  end
155
185
  end
156
-
186
+
157
187
  # Convert this post into a Hash for use in Liquid templates.
158
188
  #
159
189
  # Returns <Hash>
@@ -163,9 +193,10 @@ module Jekyll
163
193
  "date" => self.date,
164
194
  "id" => self.id,
165
195
  "topics" => self.topics,
196
+ "categories" => self.categories,
166
197
  "content" => self.content }.deep_merge(self.data)
167
198
  end
168
-
199
+
169
200
  def inspect
170
201
  "<Post: #{self.id}>"
171
202
  end
data/lib/jekyll/site.rb CHANGED
@@ -1,84 +1,146 @@
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
80
+ end
81
+
82
+ def textile(content)
83
+ RedCloth.new(content).to_html
20
84
  end
21
-
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)
66
- self.posts << post
67
- post.categories.each { |c| self.categories[c] << post }
124
+ post = Post.new(self, self.source, dir, f)
125
+
126
+ if post.published
127
+ self.posts << post
128
+ post.categories.each { |c| self.categories[c] << post }
129
+ end
68
130
  end
69
131
  end
70
-
132
+
71
133
  # second pass renders each post now that full site payload is available
72
134
  self.posts.each do |post|
73
135
  post.render(self.layouts, site_payload)
74
136
  end
75
-
137
+
76
138
  self.posts.sort!
77
139
  self.categories.values.map { |cats| cats.sort! { |a, b| b <=> a} }
78
140
  rescue Errno::ENOENT => e
79
141
  # ignore missing layout dir
80
142
  end
81
-
143
+
82
144
  # Write each post to <dest>/<year>/<month>/<day>/<slug>
83
145
  #
84
146
  # Returns nothing
@@ -87,10 +149,10 @@ module Jekyll
87
149
  post.write(self.dest)
88
150
  end
89
151
  end
90
-
152
+
91
153
  # Copy all regular files from <source> to <dest>/ ignoring
92
154
  # any files/directories that are hidden or backup files (start
93
- # with "." or end with "~") or contain site content (start with "_")
155
+ # with "." or "#" or end with "~") or contain site content (start with "_")
94
156
  # unless they are "_posts" directories or web server files such as
95
157
  # '.htaccess'
96
158
  # The +dir+ String is a relative path used to call this method
@@ -99,18 +161,14 @@ module Jekyll
99
161
  # Returns nothing
100
162
  def transform_pages(dir = '')
101
163
  base = File.join(self.source, dir)
102
- entries = Dir.entries(base)
103
- entries = entries.reject { |e| e[-1..-1] == '~' }
104
- entries = entries.reject do |e|
105
- (e != '_posts') and ['.', '_'].include?(e[0..0]) unless ['.htaccess'].include?(e)
106
- end
164
+ entries = filter_entries(Dir.entries(base))
107
165
  directories = entries.select { |e| File.directory?(File.join(base, e)) }
108
166
  files = entries.reject { |e| File.directory?(File.join(base, e)) }
109
167
 
110
- # we need to make sure to process _posts *first* otherwise they
168
+ # we need to make sure to process _posts *first* otherwise they
111
169
  # might not be available yet to other templates as {{ site.posts }}
112
- if entries.include?('_posts')
113
- entries.delete('_posts')
170
+ if directories.include?('_posts')
171
+ directories.delete('_posts')
114
172
  read_posts(dir)
115
173
  end
116
174
  [directories, files].each do |entries|
@@ -120,10 +178,10 @@ module Jekyll
120
178
  transform_pages(File.join(dir, f))
121
179
  else
122
180
  first3 = File.open(File.join(self.source, dir, f)) { |fd| fd.read(3) }
123
-
181
+
124
182
  if first3 == "---"
125
183
  # file appears to have a YAML header so process it as a page
126
- page = Page.new(self.source, dir, f)
184
+ page = Page.new(self, self.source, dir, f)
127
185
  page.render(self.layouts, site_payload)
128
186
  page.write(self.dest)
129
187
  else
@@ -156,12 +214,25 @@ module Jekyll
156
214
  # "topics" => [<Post>] }}
157
215
  def site_payload
158
216
  {"site" => {
159
- "time" => Time.now,
217
+ "time" => Time.now,
160
218
  "posts" => self.posts.sort { |a,b| b <=> a },
161
219
  "categories" => post_attr_hash('categories'),
162
220
  "topics" => post_attr_hash('topics')
163
221
  }}
164
222
  end
165
- end
166
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
167
238
  end