realityforge-jekyll 0.7.1-java
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/History.txt +255 -0
- data/LICENSE +21 -0
- data/README.textile +41 -0
- data/Rakefile +159 -0
- data/bin/jekyll +178 -0
- data/cucumber.yml +1 -0
- data/features/create_sites.feature +94 -0
- data/features/embed_filters.feature +60 -0
- data/features/markdown.feature +30 -0
- data/features/pagination.feature +27 -0
- data/features/permalinks.feature +65 -0
- data/features/post_data.feature +153 -0
- data/features/site_configuration.feature +103 -0
- data/features/site_data.feature +82 -0
- data/features/step_definitions/jekyll_steps.rb +145 -0
- data/features/support/env.rb +16 -0
- data/jekyll.gemspec +135 -0
- data/lib/jekyll.rb +109 -0
- data/lib/jekyll/albino.rb +120 -0
- data/lib/jekyll/converter.rb +50 -0
- data/lib/jekyll/converters/identity.rb +22 -0
- data/lib/jekyll/converters/markdown.rb +80 -0
- data/lib/jekyll/converters/textile.rb +33 -0
- data/lib/jekyll/convertible.rb +82 -0
- data/lib/jekyll/core_ext.rb +52 -0
- data/lib/jekyll/errors.rb +6 -0
- data/lib/jekyll/filters.rb +47 -0
- data/lib/jekyll/generator.rb +7 -0
- data/lib/jekyll/generators/pagination.rb +87 -0
- data/lib/jekyll/layout.rb +36 -0
- data/lib/jekyll/migrators/csv.rb +26 -0
- data/lib/jekyll/migrators/mephisto.rb +79 -0
- data/lib/jekyll/migrators/mt.rb +59 -0
- data/lib/jekyll/migrators/textpattern.rb +50 -0
- data/lib/jekyll/migrators/typo.rb +49 -0
- data/lib/jekyll/migrators/wordpress.rb +55 -0
- data/lib/jekyll/page.rb +133 -0
- data/lib/jekyll/plugin.rb +76 -0
- data/lib/jekyll/post.rb +242 -0
- data/lib/jekyll/site.rb +235 -0
- data/lib/jekyll/static_file.rb +76 -0
- data/lib/jekyll/tags/highlight.rb +73 -0
- data/lib/jekyll/tags/include.rb +31 -0
- data/test/helper.rb +33 -0
- data/test/source/_includes/sig.markdown +3 -0
- data/test/source/_layouts/default.html +27 -0
- data/test/source/_layouts/simple.html +1 -0
- data/test/source/_posts/2008-02-02-not-published.textile +8 -0
- data/test/source/_posts/2008-02-02-published.textile +8 -0
- data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
- data/test/source/_posts/2008-11-21-complex.textile +8 -0
- data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
- data/test/source/_posts/2008-12-13-include.markdown +8 -0
- data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
- data/test/source/_posts/2009-01-27-categories.textile +7 -0
- data/test/source/_posts/2009-01-27-category.textile +7 -0
- data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
- data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
- data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
- data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
- data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
- data/test/source/_posts/2009-05-18-tag.textile +6 -0
- data/test/source/_posts/2009-05-18-tags.textile +9 -0
- data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
- data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
- data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
- data/test/source/_posts/2010-01-09-date-override.textile +7 -0
- data/test/source/_posts/2010-01-09-time-override.textile +7 -0
- data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
- data/test/source/_posts/2010-01-16-override-data.textile +4 -0
- data/test/source/about.html +6 -0
- data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
- data/test/source/contacts.html +5 -0
- data/test/source/css/screen.css +76 -0
- data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
- data/test/source/index.html +22 -0
- data/test/source/sitemap.xml +32 -0
- data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
- data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
- data/test/suite.rb +9 -0
- data/test/test_configuration.rb +29 -0
- data/test/test_core_ext.rb +66 -0
- data/test/test_filters.rb +49 -0
- data/test/test_generated_site.rb +44 -0
- data/test/test_page.rb +98 -0
- data/test/test_pager.rb +113 -0
- data/test/test_post.rb +396 -0
- data/test/test_rdiscount.rb +18 -0
- data/test/test_site.rb +153 -0
- data/test/test_tags.rb +116 -0
- metadata +282 -0
data/lib/jekyll/post.rb
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
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+)-(.*)(\.[^.]+)$/
|
|
12
|
+
|
|
13
|
+
# Post name validator. Post filenames must be like:
|
|
14
|
+
# 2008-11-05-my-awesome-post.textile
|
|
15
|
+
#
|
|
16
|
+
# Returns <Bool>
|
|
17
|
+
def self.valid?(name)
|
|
18
|
+
name =~ MATCHER
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_accessor :site
|
|
22
|
+
attr_accessor :data, :content, :output, :ext
|
|
23
|
+
attr_accessor :date, :slug, :published, :tags, :categories
|
|
24
|
+
|
|
25
|
+
# Initialize this Post instance.
|
|
26
|
+
# +site+ is the Site
|
|
27
|
+
# +base+ is the String path to the dir containing the post file
|
|
28
|
+
# +name+ is the String filename of the post file
|
|
29
|
+
# +categories+ is an Array of Strings for the categories for this post
|
|
30
|
+
#
|
|
31
|
+
# Returns <Post>
|
|
32
|
+
def initialize(site, source, dir, name)
|
|
33
|
+
@site = site
|
|
34
|
+
@base = File.join(source, dir, '_posts')
|
|
35
|
+
@name = name
|
|
36
|
+
|
|
37
|
+
self.categories = dir.split('/').reject { |x| x.empty? }
|
|
38
|
+
self.process(name)
|
|
39
|
+
self.read_yaml(@base, name)
|
|
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
|
+
|
|
48
|
+
if self.data.has_key?('published') && self.data['published'] == false
|
|
49
|
+
self.published = false
|
|
50
|
+
else
|
|
51
|
+
self.published = true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
self.tags = self.data.pluralized_array("tag", "tags")
|
|
55
|
+
|
|
56
|
+
if self.categories.empty?
|
|
57
|
+
self.categories = self.data.pluralized_array('category', 'categories')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Spaceship is based on Post#date, slug
|
|
62
|
+
#
|
|
63
|
+
# Returns -1, 0, 1
|
|
64
|
+
def <=>(other)
|
|
65
|
+
cmp = self.date <=> other.date
|
|
66
|
+
if 0 == cmp
|
|
67
|
+
cmp = self.slug <=> other.slug
|
|
68
|
+
end
|
|
69
|
+
return cmp
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Extract information from the post filename
|
|
73
|
+
# +name+ is the String filename of the post file
|
|
74
|
+
#
|
|
75
|
+
# Returns nothing
|
|
76
|
+
def process(name)
|
|
77
|
+
m, cats, date, slug, ext = *name.match(MATCHER)
|
|
78
|
+
self.date = Time.parse(date)
|
|
79
|
+
self.slug = slug
|
|
80
|
+
self.ext = ext
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The generated directory into which the post will be placed
|
|
84
|
+
# upon generation. This is derived from the permalink or, if
|
|
85
|
+
# permalink is absent, set to the default date
|
|
86
|
+
# e.g. "/2008/11/05/" if the permalink style is :date, otherwise nothing
|
|
87
|
+
#
|
|
88
|
+
# Returns <String>
|
|
89
|
+
def dir
|
|
90
|
+
File.dirname(url)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The full path and filename of the post.
|
|
94
|
+
# Defined in the YAML of the post body
|
|
95
|
+
# (Optional)
|
|
96
|
+
#
|
|
97
|
+
# Returns <String>
|
|
98
|
+
def permalink
|
|
99
|
+
self.data && self.data['permalink']
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def template
|
|
103
|
+
case self.site.permalink_style
|
|
104
|
+
when :pretty
|
|
105
|
+
"/:categories/:year/:month/:day/:title/"
|
|
106
|
+
when :none
|
|
107
|
+
"/:categories/:title.html"
|
|
108
|
+
when :date
|
|
109
|
+
"/:categories/:year/:month/:day/:title.html"
|
|
110
|
+
else
|
|
111
|
+
self.site.permalink_style.to_s
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# The generated relative url of this post
|
|
116
|
+
# e.g. /2008/11/05/my-awesome-post.html
|
|
117
|
+
#
|
|
118
|
+
# Returns <String>
|
|
119
|
+
def url
|
|
120
|
+
return permalink if permalink
|
|
121
|
+
|
|
122
|
+
@url ||= {
|
|
123
|
+
"year" => date.strftime("%Y"),
|
|
124
|
+
"month" => date.strftime("%m"),
|
|
125
|
+
"day" => date.strftime("%d"),
|
|
126
|
+
"title" => CGI.escape(slug),
|
|
127
|
+
"i_day" => date.strftime("%d").to_i.to_s,
|
|
128
|
+
"i_month" => date.strftime("%m").to_i.to_s,
|
|
129
|
+
"categories" => categories.join('/'),
|
|
130
|
+
"output_ext" => self.output_ext
|
|
131
|
+
}.inject(template) { |result, token|
|
|
132
|
+
result.gsub(/:#{Regexp.escape token.first}/, token.last)
|
|
133
|
+
}.gsub(/\/\//, "/")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# The UID for this post (useful in feeds)
|
|
137
|
+
# e.g. /2008/11/05/my-awesome-post
|
|
138
|
+
#
|
|
139
|
+
# Returns <String>
|
|
140
|
+
def id
|
|
141
|
+
File.join(self.dir, self.slug)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Calculate related posts.
|
|
145
|
+
#
|
|
146
|
+
# Returns [<Post>]
|
|
147
|
+
def related_posts(posts)
|
|
148
|
+
return [] unless posts.size > 1
|
|
149
|
+
return [] if defined?(JRUBY_VERSION)
|
|
150
|
+
|
|
151
|
+
if self.site.lsi
|
|
152
|
+
self.class.lsi ||= begin
|
|
153
|
+
puts "Running the classifier... this could take a while."
|
|
154
|
+
lsi = Classifier::LSI.new
|
|
155
|
+
posts.each { |x| $stdout.print(".");$stdout.flush;lsi.add_item(x) }
|
|
156
|
+
puts ""
|
|
157
|
+
lsi
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
related = self.class.lsi.find_related(self.content, 11)
|
|
161
|
+
related - [self]
|
|
162
|
+
else
|
|
163
|
+
(posts - [self])[0..9]
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Add any necessary layouts to this post
|
|
168
|
+
# +layouts+ is a Hash of {"name" => "layout"}
|
|
169
|
+
# +site_payload+ is the site payload hash
|
|
170
|
+
#
|
|
171
|
+
# Returns nothing
|
|
172
|
+
def render(layouts, site_payload)
|
|
173
|
+
# construct payload
|
|
174
|
+
payload = {
|
|
175
|
+
"site" => { "related_posts" => related_posts(site_payload["site"]["posts"]) },
|
|
176
|
+
"page" => self.to_liquid
|
|
177
|
+
}.deep_merge(site_payload)
|
|
178
|
+
|
|
179
|
+
do_layout(payload, layouts)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Write the generated post file to the destination directory.
|
|
183
|
+
# +dest+ is the String path to the destination dir
|
|
184
|
+
#
|
|
185
|
+
# Returns nothing
|
|
186
|
+
def write(dest)
|
|
187
|
+
FileUtils.mkdir_p(File.join(dest, dir))
|
|
188
|
+
|
|
189
|
+
# The url needs to be unescaped in order to preserve the correct filename
|
|
190
|
+
path = File.join(dest, CGI.unescape(self.url))
|
|
191
|
+
|
|
192
|
+
if template[/\.html$/].nil?
|
|
193
|
+
FileUtils.mkdir_p(path)
|
|
194
|
+
path = File.join(path, "index.html")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
File.open(path, 'w') do |f|
|
|
198
|
+
f.write(self.output)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Convert this post into a Hash for use in Liquid templates.
|
|
203
|
+
#
|
|
204
|
+
# Returns <Hash>
|
|
205
|
+
def to_liquid
|
|
206
|
+
self.data.deep_merge({
|
|
207
|
+
"title" => self.data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' '),
|
|
208
|
+
"url" => self.url,
|
|
209
|
+
"date" => self.date,
|
|
210
|
+
"id" => self.id,
|
|
211
|
+
"categories" => self.categories,
|
|
212
|
+
"next" => self.next,
|
|
213
|
+
"previous" => self.previous,
|
|
214
|
+
"tags" => self.tags,
|
|
215
|
+
"content" => self.content })
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def inspect
|
|
219
|
+
"<Post: #{self.id}>"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def next
|
|
223
|
+
pos = self.site.posts.index(self)
|
|
224
|
+
|
|
225
|
+
if pos && pos < self.site.posts.length-1
|
|
226
|
+
self.site.posts[pos+1]
|
|
227
|
+
else
|
|
228
|
+
nil
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def previous
|
|
233
|
+
pos = self.site.posts.index(self)
|
|
234
|
+
if pos && pos > 0
|
|
235
|
+
self.site.posts[pos-1]
|
|
236
|
+
else
|
|
237
|
+
nil
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
end
|
data/lib/jekyll/site.rb
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
module Jekyll
|
|
2
|
+
|
|
3
|
+
class Site
|
|
4
|
+
attr_accessor :config, :layouts, :posts, :pages, :static_files,
|
|
5
|
+
:categories, :exclude, :source, :dest, :lsi, :pygments,
|
|
6
|
+
:permalink_style, :tags, :time, :future, :safe, :plugins
|
|
7
|
+
attr_accessor :converters, :generators
|
|
8
|
+
|
|
9
|
+
# Initialize the site
|
|
10
|
+
# +config+ is a Hash containing site configurations details
|
|
11
|
+
#
|
|
12
|
+
# Returns <Site>
|
|
13
|
+
def initialize(config)
|
|
14
|
+
self.config = config.clone
|
|
15
|
+
|
|
16
|
+
self.safe = config['safe']
|
|
17
|
+
self.source = File.expand_path(config['source'])
|
|
18
|
+
self.dest = File.expand_path(config['destination'])
|
|
19
|
+
self.plugins = File.expand_path(config['plugins'])
|
|
20
|
+
self.lsi = config['lsi']
|
|
21
|
+
self.pygments = config['pygments']
|
|
22
|
+
self.permalink_style = config['permalink'].to_sym
|
|
23
|
+
self.exclude = config['exclude'] || []
|
|
24
|
+
self.future = config['future']
|
|
25
|
+
|
|
26
|
+
self.reset
|
|
27
|
+
self.setup
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reset
|
|
31
|
+
self.time = if self.config['time']
|
|
32
|
+
Time.parse(self.config['time'].to_s)
|
|
33
|
+
else
|
|
34
|
+
Time.now
|
|
35
|
+
end
|
|
36
|
+
self.layouts = {}
|
|
37
|
+
self.posts = []
|
|
38
|
+
self.pages = []
|
|
39
|
+
self.static_files = []
|
|
40
|
+
self.categories = Hash.new { |hash, key| hash[key] = [] }
|
|
41
|
+
self.tags = Hash.new { |hash, key| hash[key] = [] }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def setup
|
|
45
|
+
require 'classifier' if self.lsi
|
|
46
|
+
|
|
47
|
+
# If safe mode is off, load in any ruby files under the plugins
|
|
48
|
+
# directory.
|
|
49
|
+
unless self.safe
|
|
50
|
+
Dir[File.join(self.plugins, "**/*.rb")].each do |f|
|
|
51
|
+
require f
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
self.converters = Jekyll::Converter.subclasses.select do |c|
|
|
56
|
+
!self.safe || c.safe
|
|
57
|
+
end.map do |c|
|
|
58
|
+
c.new(self.config)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
self.generators = Jekyll::Generator.subclasses.select do |c|
|
|
62
|
+
!self.safe || c.safe
|
|
63
|
+
end.map do |c|
|
|
64
|
+
c.new(self.config)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Do the actual work of processing the site and generating the
|
|
69
|
+
# real deal. 5 phases; reset, read, generate, render, write. This allows
|
|
70
|
+
# rendering to have full site payload available.
|
|
71
|
+
#
|
|
72
|
+
# Returns nothing
|
|
73
|
+
def process
|
|
74
|
+
self.reset
|
|
75
|
+
self.read
|
|
76
|
+
self.generate
|
|
77
|
+
self.render
|
|
78
|
+
self.write
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def read
|
|
82
|
+
self.read_layouts # existing implementation did this at top level only so preserved that
|
|
83
|
+
self.read_directories
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Read all the files in <source>/<dir>/_layouts and create a new Layout
|
|
87
|
+
# object with each one.
|
|
88
|
+
#
|
|
89
|
+
# Returns nothing
|
|
90
|
+
def read_layouts(dir = '')
|
|
91
|
+
base = File.join(self.source, dir, "_layouts")
|
|
92
|
+
return unless File.exists?(base)
|
|
93
|
+
entries = []
|
|
94
|
+
Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
|
|
95
|
+
|
|
96
|
+
entries.each do |f|
|
|
97
|
+
name = f.split(".")[0..-2].join(".")
|
|
98
|
+
self.layouts[name] = Layout.new(self, base, f)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Read all the files in <source>/<dir>/_posts and create a new Post
|
|
103
|
+
# object with each one.
|
|
104
|
+
#
|
|
105
|
+
# Returns nothing
|
|
106
|
+
def read_posts(dir)
|
|
107
|
+
base = File.join(self.source, dir, '_posts')
|
|
108
|
+
return unless File.exists?(base)
|
|
109
|
+
entries = Dir.chdir(base) { filter_entries(Dir['**/*']) }
|
|
110
|
+
|
|
111
|
+
# first pass processes, but does not yet render post content
|
|
112
|
+
entries.each do |f|
|
|
113
|
+
if Post.valid?(f)
|
|
114
|
+
post = Post.new(self, self.source, dir, f)
|
|
115
|
+
|
|
116
|
+
if post.published && (self.future || post.date <= self.time)
|
|
117
|
+
self.posts << post
|
|
118
|
+
post.categories.each { |c| self.categories[c] << post }
|
|
119
|
+
post.tags.each { |c| self.tags[c] << post }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
self.posts.sort!
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def generate
|
|
128
|
+
self.generators.each do |generator|
|
|
129
|
+
generator.generate(self)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def render
|
|
134
|
+
self.posts.each do |post|
|
|
135
|
+
post.render(self.layouts, site_payload)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
self.pages.each do |page|
|
|
139
|
+
page.render(self.layouts, site_payload)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
self.categories.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
|
143
|
+
self.tags.values.map { |ps| ps.sort! { |a, b| b <=> a} }
|
|
144
|
+
rescue Errno::ENOENT => e
|
|
145
|
+
# ignore missing layout dir
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Write static files, pages and posts
|
|
149
|
+
#
|
|
150
|
+
# Returns nothing
|
|
151
|
+
def write
|
|
152
|
+
self.posts.each do |post|
|
|
153
|
+
post.write(self.dest)
|
|
154
|
+
end
|
|
155
|
+
self.pages.each do |page|
|
|
156
|
+
page.write(self.dest)
|
|
157
|
+
end
|
|
158
|
+
self.static_files.each do |sf|
|
|
159
|
+
sf.write(self.dest)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Reads the directories and finds posts, pages and static files that will
|
|
164
|
+
# become part of the valid site according to the rules in +filter_entries+.
|
|
165
|
+
# The +dir+ String is a relative path used to call this method
|
|
166
|
+
# recursively as it descends through directories
|
|
167
|
+
#
|
|
168
|
+
# Returns nothing
|
|
169
|
+
def read_directories(dir = '')
|
|
170
|
+
base = File.join(self.source, dir)
|
|
171
|
+
entries = filter_entries(Dir.entries(base))
|
|
172
|
+
|
|
173
|
+
self.read_posts(dir)
|
|
174
|
+
|
|
175
|
+
entries.each do |f|
|
|
176
|
+
f_abs = File.join(base, f)
|
|
177
|
+
f_rel = File.join(dir, f)
|
|
178
|
+
if File.directory?(f_abs)
|
|
179
|
+
next if self.dest.sub(/\/$/, '') == f_abs
|
|
180
|
+
read_directories(f_rel)
|
|
181
|
+
elsif !File.symlink?(f_abs)
|
|
182
|
+
first3 = File.open(f_abs) { |fd| fd.read(3) }
|
|
183
|
+
if first3 == "---"
|
|
184
|
+
# file appears to have a YAML header so process it as a page
|
|
185
|
+
pages << Page.new(self, self.source, dir, f)
|
|
186
|
+
else
|
|
187
|
+
# otherwise treat it as a static file
|
|
188
|
+
static_files << StaticFile.new(self, self.source, dir, f)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Constructs a hash map of Posts indexed by the specified Post attribute
|
|
195
|
+
#
|
|
196
|
+
# Returns {post_attr => [<Post>]}
|
|
197
|
+
def post_attr_hash(post_attr)
|
|
198
|
+
# Build a hash map based on the specified post attribute ( post attr => array of posts )
|
|
199
|
+
# then sort each array in reverse order
|
|
200
|
+
hash = Hash.new { |hash, key| hash[key] = Array.new }
|
|
201
|
+
self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
|
|
202
|
+
hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
|
|
203
|
+
return hash
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# The Hash payload containing site-wide data
|
|
207
|
+
#
|
|
208
|
+
# Returns {"site" => {"time" => <Time>,
|
|
209
|
+
# "posts" => [<Post>],
|
|
210
|
+
# "pages" => [<Page>],
|
|
211
|
+
# "categories" => [<Post>]}
|
|
212
|
+
def site_payload
|
|
213
|
+
{"site" => self.config.merge({
|
|
214
|
+
"time" => self.time,
|
|
215
|
+
"posts" => self.posts.sort { |a,b| b <=> a },
|
|
216
|
+
"pages" => self.pages,
|
|
217
|
+
"html_pages" => self.pages.reject { |page| !page.html? },
|
|
218
|
+
"categories" => post_attr_hash('categories'),
|
|
219
|
+
"tags" => post_attr_hash('tags')})}
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Filter out any files/directories that are hidden or backup files (start
|
|
223
|
+
# with "." or "#" or end with "~"), or contain site content (start with "_"),
|
|
224
|
+
# or are excluded in the site configuration, unless they are web server
|
|
225
|
+
# files such as '.htaccess'
|
|
226
|
+
def filter_entries(entries)
|
|
227
|
+
entries = entries.reject do |e|
|
|
228
|
+
unless ['.htaccess'].include?(e)
|
|
229
|
+
['.', '_', '#'].include?(e[0..0]) || e[-1..-1] == '~' || self.exclude.include?(e)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
end
|
|
235
|
+
end
|