cduruk-jekyll 0.5.2

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 (48) hide show
  1. data/History.txt +115 -0
  2. data/README.textile +649 -0
  3. data/Rakefile +91 -0
  4. data/VERSION.yml +4 -0
  5. data/bin/jekyll +156 -0
  6. data/lib/jekyll.rb +84 -0
  7. data/lib/jekyll/albino.rb +122 -0
  8. data/lib/jekyll/converters/csv.rb +26 -0
  9. data/lib/jekyll/converters/mephisto.rb +79 -0
  10. data/lib/jekyll/converters/mt.rb +59 -0
  11. data/lib/jekyll/converters/textpattern.rb +50 -0
  12. data/lib/jekyll/converters/typo.rb +49 -0
  13. data/lib/jekyll/converters/wordpress.rb +54 -0
  14. data/lib/jekyll/convertible.rb +117 -0
  15. data/lib/jekyll/core_ext.rb +29 -0
  16. data/lib/jekyll/filters.rb +47 -0
  17. data/lib/jekyll/haml_helpers.rb +15 -0
  18. data/lib/jekyll/layout.rb +37 -0
  19. data/lib/jekyll/page.rb +67 -0
  20. data/lib/jekyll/post.rb +305 -0
  21. data/lib/jekyll/site.rb +300 -0
  22. data/lib/jekyll/tags/highlight.rb +68 -0
  23. data/lib/jekyll/tags/include.rb +31 -0
  24. data/test/helper.rb +24 -0
  25. data/test/source/_includes/sig.markdown +3 -0
  26. data/test/source/_layouts/default.html +27 -0
  27. data/test/source/_layouts/simple.html +1 -0
  28. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  29. data/test/source/_posts/2008-02-02-published.textile +8 -0
  30. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  31. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  32. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  33. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  34. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  35. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  36. data/test/source/_posts/2009-01-27-category.textile +7 -0
  37. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  38. data/test/source/css/screen.css +76 -0
  39. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  40. data/test/source/index.html +22 -0
  41. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  42. data/test/suite.rb +9 -0
  43. data/test/test_filters.rb +41 -0
  44. data/test/test_generated_site.rb +38 -0
  45. data/test/test_post.rb +262 -0
  46. data/test/test_site.rb +57 -0
  47. data/test/test_tags.rb +51 -0
  48. metadata +165 -0
@@ -0,0 +1,47 @@
1
+ module Jekyll
2
+
3
+ module Filters
4
+ def textilize(input)
5
+ RedCloth.new(input).to_html
6
+ end
7
+
8
+ def date_to_string(date)
9
+ date.strftime("%d %b %Y")
10
+ end
11
+
12
+ def date_to_long_string(date)
13
+ date.strftime("%d %B %Y")
14
+ end
15
+
16
+ def date_to_xmlschema(date)
17
+ date.xmlschema
18
+ end
19
+
20
+ def date_to_utc(date)
21
+ date.utc
22
+ end
23
+
24
+ def xml_escape(input)
25
+ input.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;")
26
+ end
27
+
28
+ def number_of_words(input)
29
+ input.split.length
30
+ end
31
+
32
+ def array_to_sentence_string(array)
33
+ connector = "and"
34
+ case array.length
35
+ when 0
36
+ ""
37
+ when 1
38
+ array[0].to_s
39
+ when 2
40
+ "#{array[0]} #{connector} #{array[1]}"
41
+ else
42
+ "#{array[0...-1].join(', ')}, #{connector} #{array[-1]}"
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ require 'cgi'
2
+
3
+ module Jekyll
4
+ module HamlHelpers
5
+
6
+ def h(text)
7
+ CGI.escapeHTML(text)
8
+ end
9
+
10
+ def link_to(text, url)
11
+ %{<a href="#{h url}">#{text}</a>}
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module Jekyll
2
+
3
+ class Layout
4
+ include Convertible
5
+
6
+ attr_accessor :site
7
+ attr_accessor :ext
8
+ attr_accessor :data, :content
9
+
10
+ # Initialize a new Layout.
11
+ # +site+ is the Site
12
+ # +base+ is the String path to the <source>
13
+ # +name+ is the String filename of the post file
14
+ #
15
+ # Returns <Page>
16
+ def initialize(site, base, name)
17
+ @site = site
18
+ @base = base
19
+ @name = name
20
+
21
+ self.data = {}
22
+
23
+ self.process(name)
24
+ self.read_yaml(base, name)
25
+ self.transform
26
+ end
27
+
28
+ # Extract information from the layout filename
29
+ # +name+ is the String filename of the layout file
30
+ #
31
+ # Returns nothing
32
+ def process(name)
33
+ self.ext = File.extname(name)
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,67 @@
1
+ module Jekyll
2
+
3
+ class Page
4
+ include Convertible
5
+
6
+ attr_accessor :site
7
+ attr_accessor :ext
8
+ attr_accessor :data, :content, :output
9
+
10
+ # Initialize a new Page.
11
+ # +site+ is the Site
12
+ # +base+ is the String path to the <source>
13
+ # +dir+ is the String path between <source> and the file
14
+ # +name+ is the String filename of the file
15
+ #
16
+ # Returns <Page>
17
+ def initialize(site, base, dir, name)
18
+ @site = site
19
+ @base = base
20
+ @dir = dir
21
+ @name = name
22
+
23
+ self.data = {}
24
+
25
+ self.process(name)
26
+ self.read_yaml(File.join(base, dir), name)
27
+ #self.transform
28
+ end
29
+
30
+ # Extract information from the page filename
31
+ # +name+ is the String filename of the page file
32
+ #
33
+ # Returns nothing
34
+ def process(name)
35
+ self.ext = File.extname(name)
36
+ end
37
+
38
+ # Add any necessary layouts to this post
39
+ # +layouts+ is a Hash of {"name" => "layout"}
40
+ # +site_payload+ is the site payload hash
41
+ #
42
+ # Returns nothing
43
+ def render(layouts, site_payload)
44
+ payload = {"page" => self.data}.deep_merge(site_payload)
45
+ do_layout(payload, layouts)
46
+ end
47
+
48
+ # Write the generated page file to the destination directory.
49
+ # +dest+ is the String path to the destination dir
50
+ #
51
+ # Returns nothing
52
+ def write(dest)
53
+ FileUtils.mkdir_p(File.join(dest, @dir))
54
+
55
+ name = @name
56
+ if self.ext != ""
57
+ name = @name.split(".")[0..-2].join('.') + self.ext
58
+ end
59
+
60
+ path = File.join(dest, @dir, name)
61
+ File.open(path, 'w') do |f|
62
+ f.write(self.output)
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,305 @@
1
+ module Jekyll
2
+
3
+ class Post
4
+ include Comparable
5
+ include Convertible
6
+
7
+ class << self
8
+ attr_accessor :lsi
9
+ end
10
+
11
+ MATCHER = /^(.+\/)*(\d+-\d+-\d+(?:_\d+-\d+)?)-(.*)(\.[^.]+)$/
12
+
13
+ # Post name validator. Post filenames must be like:
14
+ # 2008-11-05-my-awesome-post.textile
15
+ # or:
16
+ # 2008-11-05_12-45-my-awesome-post.textile
17
+ #
18
+ # Returns <Bool>
19
+ def self.valid?(name)
20
+ name =~ MATCHER
21
+ end
22
+
23
+ attr_accessor :site, :date, :slug, :ext, :topics, :tags, :published, :data, :content, :output
24
+ attr_writer :categories
25
+
26
+ def categories
27
+ @categories ||= []
28
+ end
29
+
30
+ # Initialize this Post instance.
31
+ # +site+ is the Site
32
+ # +base+ is the String path to the dir containing the post file
33
+ # +name+ is the String filename of the post file
34
+ # +categories+ is an Array of Strings for the categories for this post
35
+ # +tags+ is an Array of Strings for the tags for this post
36
+ #
37
+ # Returns <Post>
38
+ def initialize(site, source, dir, name)
39
+ @site = site
40
+ @base = File.join(source, dir, '_posts')
41
+ @name = name
42
+
43
+ self.categories = dir.split('/').reject { |x| x.empty? }
44
+
45
+ parts = name.split('/')
46
+ self.topics = parts.size > 1 ? parts[0..-2] : []
47
+
48
+ self.process(name)
49
+ self.data = self.site.post_defaults.dup
50
+ self.read_yaml(@base, name)
51
+
52
+ extract_title_from_first_header_or_slug
53
+
54
+ if self.data.has_key?('published') && self.data['published'] == false
55
+ self.published = false
56
+ else
57
+ self.published = true
58
+ end
59
+
60
+ if self.categories.empty?
61
+ if self.data.has_key?('category')
62
+ self.categories << self.data['category']
63
+ elsif self.data.has_key?('categories')
64
+ # Look for categories in the YAML-header, either specified as
65
+ # an array or a string.
66
+ if self.data['categories'].kind_of? String
67
+ self.categories = self.data['categories'].split
68
+ else
69
+ self.categories = self.data['categories']
70
+ end
71
+ end
72
+ end
73
+
74
+ self.tags = self.data['tags'] || []
75
+ end
76
+
77
+ # Spaceship is based on Post#date
78
+ #
79
+ # Returns -1, 0, 1
80
+ def <=>(other)
81
+ self.date <=> other.date
82
+ end
83
+
84
+ # Extract information from the post filename
85
+ # +name+ is the String filename of the post file
86
+ #
87
+ # Returns nothing
88
+ def process(name)
89
+ m, cats, date, slug, ext = *name.match(MATCHER)
90
+ date = date.sub(/_(\d+)-(\d+)\Z/, ' \1:\2') # Make optional time part parsable.
91
+ self.date = Time.parse(date)
92
+ self.slug = slug
93
+ self.ext = ext
94
+ end
95
+
96
+ # The generated directory into which the post will be placed
97
+ # upon generation. This is derived from the permalink or, if
98
+ # permalink is absent, set to the default date
99
+ # e.g. "/2008/11/05/" if the permalink style is :date, otherwise nothing
100
+ #
101
+ # Returns <String>
102
+ def dir
103
+ File.dirname(generated_path)
104
+ end
105
+
106
+ # The full path and filename of the post.
107
+ # Defined in the YAML of the post body
108
+ # (Optional)
109
+ #
110
+ # Returns <String>
111
+ def permalink
112
+ self.data && self.data['permalink']
113
+ end
114
+
115
+ def template
116
+ case self.site.permalink_style
117
+ when :pretty
118
+ "/:categories/:year/:month/:day/:title"
119
+ when :none
120
+ "/:categories/:title.html"
121
+ when :date
122
+ "/:categories/:year/:month/:day/:title.html"
123
+ else
124
+ self.site.permalink_style.to_s
125
+ end
126
+ end
127
+
128
+ # The generated relative path of this post
129
+ # e.g. /2008/11/05/my-awesome-post.html
130
+ #
131
+ # Returns <String>
132
+ def generated_path
133
+ return permalink if permalink
134
+
135
+ @generated_path ||= {
136
+ "year" => date.strftime("%Y"),
137
+ "month" => date.strftime("%m"),
138
+ "day" => date.strftime("%d"),
139
+ "title" => slug,
140
+ "categories" => categories.sort.join('/')
141
+ }.inject(template) { |result, token|
142
+ result.gsub(/:#{token.first}/, token.last)
143
+ }.gsub("//", "/")
144
+ end
145
+
146
+ # The generated relative url of this post
147
+ # e.g. /2008/11/05/my-awesome-post
148
+ #
149
+ # Returns <String>
150
+ def url
151
+ site.config['multiviews'] ? generated_path.sub(/\.html$/, '') : generated_path
152
+ end
153
+
154
+ # The UID for this post (useful in feeds)
155
+ # e.g. /2008/11/05/my-awesome-post
156
+ #
157
+ # Returns <String>
158
+ def id
159
+ File.join(self.dir, self.slug)
160
+ end
161
+
162
+ # The post title
163
+ #
164
+ # Returns <String>
165
+ def title
166
+ self.data && self.data["title"]
167
+ end
168
+
169
+ # The post date and time
170
+ #
171
+ # Returns <Time>
172
+ def date
173
+ @date_with_time ||= begin
174
+ if self.data && self.data.key?("time")
175
+ time = Time.parse(self.data["time"])
176
+ Time.mktime(@date.year, @date.month, @date.day, time.hour, time.min)
177
+ else
178
+ @date
179
+ end
180
+ end
181
+ end
182
+
183
+ # The path to the post file.
184
+ #
185
+ # Returns <String>
186
+ def path
187
+ File.expand_path(File.join(@base, @name))
188
+ end
189
+
190
+ # Calculate related posts.
191
+ #
192
+ # Returns [<Post>]
193
+ def related_posts(posts)
194
+ return [] unless posts.size > 1
195
+
196
+ if self.site.lsi
197
+ self.class.lsi ||= begin
198
+ puts "Running the classifier... this could take a while."
199
+ lsi = Classifier::LSI.new
200
+ posts.each { |x| $stdout.print(".");$stdout.flush;lsi.add_item(x) }
201
+ puts ""
202
+ lsi
203
+ end
204
+
205
+ related = self.class.lsi.find_related(self.content, 11)
206
+ related - [self]
207
+ else
208
+ (posts - [self])[0..9]
209
+ end
210
+ end
211
+
212
+ # Add any necessary layouts to this post
213
+ # +layouts+ is a Hash of {"name" => "layout"}
214
+ # +site_payload+ is the site payload hash
215
+ #
216
+ # Returns nothing
217
+ def render(layouts, site_payload)
218
+ # construct payload
219
+ payload =
220
+ {
221
+ "site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) },
222
+ "page" => self.to_liquid
223
+ }
224
+ payload = payload.deep_merge(site_payload)
225
+
226
+ do_layout(payload, layouts)
227
+ end
228
+
229
+ # Write the generated post file to the destination directory.
230
+ # +dest+ is the String path to the destination dir
231
+ #
232
+ # Returns nothing
233
+ def write(dest)
234
+ FileUtils.mkdir_p(File.join(dest, dir))
235
+
236
+ path = File.join(dest, self.generated_path)
237
+
238
+ if template[/\.html$/].nil?
239
+ FileUtils.mkdir_p(path)
240
+ path = File.join(path, "index.html")
241
+ end
242
+
243
+ File.open(path, 'w') do |f|
244
+ f.write(self.output)
245
+ end
246
+ end
247
+
248
+ # Attempt to extract title from topmost header or slug.
249
+ #
250
+ # Returns <String>
251
+ def extract_title_from_first_header_or_slug
252
+ # Done before the transformation to HTML, or it won't go into <title>s.
253
+ self.data["title"] ||=
254
+ case content_type
255
+ when 'textile'
256
+ self.content[/\A\s*h\d\.\s*(.+)/, 1] # h1. Header
257
+ when 'markdown'
258
+ self.content[/\A\s*#+\s*(.+)\s*#*$/, 1] || # "# Header"
259
+ self.content[/\A\s*(\S.*)\r?\n\s*(-+|=+)\s*$/, 1] # "Header\n====="
260
+ end
261
+ self.data["title"] ||= self.slug.split('-').select {|w| w.capitalize! || w }.join(' ')
262
+ end
263
+
264
+ # Convert this post into a Hash for use in Liquid templates.
265
+ #
266
+ # Returns <Hash>
267
+ def to_liquid
268
+ { "title" => self.title,
269
+ "url" => self.url,
270
+ "date" => self.date,
271
+ "id" => self.id,
272
+ "path" => self.path,
273
+ "topics" => self.topics,
274
+ "categories" => self.categories,
275
+ "tags" => self.tags,
276
+ "next" => self.next,
277
+ "previous" => self.previous,
278
+ "content" => self.content }.deep_merge(self.data)
279
+ end
280
+
281
+ def inspect
282
+ "<Post: #{self.id}>"
283
+ end
284
+
285
+ def next
286
+ pos = self.site.posts.index(self)
287
+
288
+ if pos && pos < self.site.posts.length-1
289
+ self.site.posts[pos+1]
290
+ else
291
+ nil
292
+ end
293
+ end
294
+
295
+ def previous
296
+ pos = self.site.posts.index(self)
297
+ if pos && pos > 0
298
+ self.site.posts[pos-1]
299
+ else
300
+ nil
301
+ end
302
+ end
303
+ end
304
+
305
+ end