Class: Serif::Site
- Inherits:
-
Object
- Object
- Serif::Site
- Defined in:
- lib/serif/site.rb
Instance Method Summary collapse
-
#archive_url_for_date(date) ⇒ Object
Returns the relative archive URL for the given date, using the value of config.archive_url_format.
-
#archives ⇒ Object
Returns a nested hash with the following structure:.
- #bypass?(filename) ⇒ Boolean
- #config ⇒ Object
-
#conflicts(content_to_check = nil) ⇒ Object
Returns a hash representing any conflicting URLs, in the form.
- #directory ⇒ Object
- #drafts ⇒ Object
- #generate ⇒ Object
-
#initialize(source_directory) ⇒ Site
constructor
A new instance of Site.
- #latest_update_time ⇒ Object
-
#posts ⇒ Object
Returns all of the site’s posts, in reverse chronological order by creation time.
-
#private_url(draft) ⇒ Object
Gives the URL absolute path to a private draft preview.
- #site_path(path) ⇒ Object
- #tmp_path(path) ⇒ Object
- #to_liquid ⇒ Object
Constructor Details
#initialize(source_directory) ⇒ Site
Returns a new instance of Site.
96 97 98 |
# File 'lib/serif/site.rb', line 96 def initialize(source_directory) @source_directory = source_directory end |
Instance Method Details
#archive_url_for_date(date) ⇒ Object
Returns the relative archive URL for the given date, using the value of config.archive_url_format
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/serif/site.rb', line 149 def archive_url_for_date(date) format = config.archive_url_format parts = { "year" => date.year.to_s, "month" => date.month.to_s.rjust(2, "0") } output = format parts.each do |placeholder, value| output = output.gsub(Regexp.quote(":" + placeholder), value) end output end |
#archives ⇒ Object
Returns a nested hash with the following structure:
{
:posts => [],
:years => [
{
:date => Date.new(2012),
:posts => [],
:months => [
{ :date => Date.new(2012, 12), :archive_url => "/archive/2012/12", :posts => [] },
{ :date => Date.new(2012, 11), :archive_url => "/archive/2012/11", :posts => [] },
# ...
]
},
# ...
]
}
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/serif/site.rb', line 184 def archives h = {} h[:posts] = posts # group posts by Date instances for the first day of the year year_groups = posts.group_by { |post| Date.new(post.created.year) }.to_a # collect all elements as maps for the year start date and the posts in that year year_groups.map! do |year_start_date, posts_by_year| { :date => year_start_date, :posts => posts_by_year.sort_by { |post| post.created }.reverse } end year_groups.sort_by! { |year_hash| year_hash[:date] } year_groups.reverse! year_groups.each do |year_hash| year_posts = year_hash[:posts] # group the posts in the year by month month_groups = year_posts.group_by { |post| Date.new(post.created.year, post.created.month) }.to_a # collect the elements as maps for the month start date and the posts in that month month_groups.map! do |month_start_date, posts_by_month| { :date => month_start_date, :posts => posts_by_month.sort_by { |post| post.created }.reverse, :archive_url => archive_url_for_date(month_start_date) } end month_groups.sort_by! { |month_hash| month_hash[:date] } month_groups.reverse! # set the months for the current year year_hash[:months] = month_groups end h[:years] = year_groups # return the final hash h end |
#bypass?(filename) ⇒ Boolean
143 144 145 |
# File 'lib/serif/site.rb', line 143 def bypass?(filename) !%w[.html .xml].include?(File.extname(filename)) end |
#config ⇒ Object
114 115 116 |
# File 'lib/serif/site.rb', line 114 def config @config ||= Serif::Config.new(File.join(@source_directory, "_config.yml")) end |
#conflicts(content_to_check = nil) ⇒ Object
Returns a hash representing any conflicting URLs, in the form
{ "/url_1" => [e_1, e_2, ..., e_n], ... }
The elements e_i are the conflicting Post and Draft instances that share the URL “/url_1”.
Note that if n = 1 (that is, the array value is [e_1], containing a single element), then it is not included in the Hash, since it does not contribute to a conflict.
If there are no conflicts found, returns nil.
If an argument is specified, its #url value is compared against all post and draft URLs, and the value returned is either:
-
an array of post/draft instances that conflict, including the argument given; or,
-
nil if there is no conflict.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/serif/site.rb', line 252 def conflicts(content_to_check = nil) if content_to_check content = drafts + posts + [content_to_check] # In the event that the given argument is actually one of the # drafts + posts, we need to de-duplicate, otherwise our return # value will contain two of the same Draft/Post, which isn't # actually a conflict. # # So to do that, we can use the path on the filesystem. However, # we can't just rely on calling #path, because if content_to_check # doesn't have a #path value, it'll be nil and it's possible that # we might expand checking to multiple files/Drafts/Posts. # # Thus, if #path is nil, simply rely on object_id. # # FIXME: Replace this with a proper implementation of # ContentFile equality/hashing. content.uniq! { |e| e.path ? e.path : e.object_id } conflicts = content.select { |e| e.url == content_to_check.url } if conflicts.length <= 1 return nil else return conflicts end end conflicts = (drafts + posts).group_by { |e| e.url } conflicts.reject! { |k, v| v.length == 1 } if conflicts.empty? nil else conflicts end end |
#directory ⇒ Object
100 101 102 |
# File 'lib/serif/site.rb', line 100 def directory @source_directory end |
#generate ⇒ Object
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/serif/site.rb', line 305 def generate FileUtils.cd(@source_directory) FileUtils.rm_rf("tmp/_site") FileUtils.mkdir_p("tmp/_site") files = Dir["**/*"].select { |f| f !~ /\A_/ && File.file?(f) } default_layout = Liquid::Template.parse(File.read("_layouts/default.html")) if conflicts raise PostConflictError, "Generating would cause a conflict." end # preprocess any drafts marked for autopublish, before grabbing the posts # to operate on. preprocess_autopublish_drafts # preprocess any posts that might have had an update flag set in the header preprocess_autoupdate_posts posts = self.posts files.each do |path| puts "Processing file: #{path}" dirname = File.dirname(path) filename = File.basename(path) FileUtils.mkdir_p(tmp_path(dirname)) if bypass?(filename) FileUtils.cp(path, tmp_path(path)) else File.open(tmp_path(path), "w") do |f| file = File.read(path) title = nil layout_option = :default if Redhead::String.has_headers?(file) file_with_headers = Redhead::String[file] title = file_with_headers.headers[:title] && file_with_headers.headers[:title].value layout_option = file_with_headers.headers[:layout] && file_with_headers.headers[:layout].value layout_option ||= :default # all good? use the headered string file = file_with_headers end if layout_option == "none" f.puts Liquid::Template.parse(file.to_s).render!("site" => self) else if layout_option == :default layout = default_layout else layout_file = File.join(self.directory, "_layouts", "#{layout_option}.html") layout = Liquid::Template.parse(File.read(layout_file)) end f.puts layout.render!("site" => self, "page" => { "title" => title }, "content" => Liquid::Template.parse(file.to_s).render!("site" => self)) end end end end # run through the posts + nil so we can keep |a, b| such that a hits every element # while iterating. posts.each.with_index do |post, i| # the posts are iterated over in reverse chrological order, and # next_post here is post published chronologically after than # the post in the iteration. # # if i == 0, we don't want posts.last, so return nil if i - 1 == -1 next_post = (i == 0 ? nil : posts[i - 1]) prev_post = posts[i + 1] puts "Processing post: #{post.path}" FileUtils.mkdir_p(tmp_path(File.dirname(post.url))) post_layout = default_layout if post.headers[:layout] post_layout = Liquid::Template.parse(File.read(File.join(self.directory, "_layouts", "#{post.headers[:layout]}.html"))) end File.open(tmp_path(post.url + ".html"), "w") do |f| # variables available in the post template post_template_variables = { "post" => post, "post_page" => true, "prev_post" => prev_post, "next_post" => next_post } f.puts post_layout.render!( "site" => self, "page" => { "title" => post.title }, "post_page" => true, "content" => Liquid::Template.parse(File.read("_templates/post.html")).render!(post_template_variables) ) end end generate_draft_previews(default_layout) generate_archives(default_layout) if Dir.exist?("_site") FileUtils.mv("_site", "/tmp/_site.#{Time.now.strftime("%Y-%m-%d-%H-%M-%S.%6N")}") end FileUtils.mv("tmp/_site", ".") && FileUtils.rm_rf("tmp/_site") FileUtils.rmdir("tmp") end |
#latest_update_time ⇒ Object
126 127 128 129 |
# File 'lib/serif/site.rb', line 126 def latest_update_time most_recent = posts.max_by { |p| p.updated } most_recent ? most_recent.updated : Time.now end |
#posts ⇒ Object
Returns all of the site’s posts, in reverse chronological order by creation time.
106 107 108 |
# File 'lib/serif/site.rb', line 106 def posts Post.all(self).sort_by { |entry| entry.created }.reverse end |
#private_url(draft) ⇒ Object
Gives the URL absolute path to a private draft preview.
If the draft has no such preview available, returns nil.
134 135 136 137 138 139 140 141 |
# File 'lib/serif/site.rb', line 134 def private_url(draft) private_draft_pattern = site_path("/drafts/#{draft.slug}/*") file = Dir[private_draft_pattern].first return nil unless file "/drafts/#{draft.slug}/#{File.basename(file, ".html")}" end |
#site_path(path) ⇒ Object
118 119 120 |
# File 'lib/serif/site.rb', line 118 def site_path(path) File.join("_site", path) end |
#tmp_path(path) ⇒ Object
122 123 124 |
# File 'lib/serif/site.rb', line 122 def tmp_path(path) File.join("tmp", site_path(path)) end |
#to_liquid ⇒ Object
291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/serif/site.rb', line 291 def to_liquid @liquid_cache_store ||= TimeoutCache.new(1) cached_value = @liquid_cache_store[:liquid] return cached_value if cached_value @liquid_cache_store[:liquid] = { "posts" => posts, "latest_update_time" => latest_update_time, "archive" => self.class.stringify_keys(archives), "directory" => directory } end |