diff --git a/lib/jekyll.rb b/lib/jekyll.rb index ab35a3b2..3357185b 100644 --- a/lib/jekyll.rb +++ b/lib/jekyll.rb @@ -30,6 +30,7 @@ require 'pygments' require 'jekyll/core_ext' require 'jekyll/site' require 'jekyll/convertible' +require 'jekyll/url' require 'jekyll/layout' require 'jekyll/page' require 'jekyll/post' diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 0de5e254..33294e5b 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -1,6 +1,7 @@ module Jekyll class Page include Convertible + include URL attr_writer :dir attr_accessor :site, :pager @@ -69,28 +70,13 @@ module Jekyll end end - # The generated relative url of this page. e.g. /about.html. - # - # Returns the String url. - def url - return @url if @url - - url = if permalink - permalink - else - { - "path" => @dir, - "basename" => self.basename, - "output_ext" => self.output_ext, - }.inject(template) { |result, token| - result.gsub(/:#{token.first}/, token.last) - }.gsub(/\/\//, "/") - end - - # sanitize url - @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/') - @url += "/" if url =~ /\/$/ - @url + # See url.rb for an explanation + def url_placeholders + { + "path" => @dir, + "basename" => self.basename, + "output_ext" => self.output_ext + } end # Extract information from the page filename. diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index 50fd983c..c3c3d9be 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -2,6 +2,7 @@ module Jekyll class Post include Comparable include Convertible + include URL class << self attr_accessor :lsi @@ -153,36 +154,20 @@ module Jekyll end end - # The generated relative url of this post. - # e.g. /2008/11/05/my-awesome-post.html - # - # Returns the String URL. - def url - return @url if @url - - url = if permalink - permalink - else - { - "year" => date.strftime("%Y"), - "month" => date.strftime("%m"), - "day" => date.strftime("%d"), - "title" => CGI.escape(slug), - "i_day" => date.strftime("%d").to_i.to_s, - "i_month" => date.strftime("%m").to_i.to_s, - "categories" => categories.map { |c| URI.escape(c.to_s) }.join('/'), - "short_month" => date.strftime("%b"), - "y_day" => date.strftime("%j"), - "output_ext" => self.output_ext - }.inject(template) { |result, token| - result.gsub(/:#{Regexp.escape token.first}/, token.last) - }.gsub(/\/\//, "/") - end - - # sanitize url - @url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/') - @url += "/" if url =~ /\/$/ - @url + # See url.rb for an explanation + def url_placeholders + { + "year" => date.strftime("%Y"), + "month" => date.strftime("%m"), + "day" => date.strftime("%d"), + "title" => CGI.escape(slug), + "i_day" => date.strftime("%d").to_i.to_s, + "i_month" => date.strftime("%m").to_i.to_s, + "categories" => categories.map { |c| URI.escape(c.to_s) }.join('/'), + "short_month" => date.strftime("%b"), + "y_day" => date.strftime("%j"), + "output_ext" => self.output_ext + } end # The UID for this post (useful in feeds). diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb new file mode 100644 index 00000000..93d381fb --- /dev/null +++ b/lib/jekyll/url.rb @@ -0,0 +1,53 @@ +# The URL module provides methods that generate a URL for a resource in which they're +# included, such as a Post or a Page. +# +# Requires +# +# self.permalink - If a permalink is set in the included instance, that permalink +# will be returned instead of any URL that might've been generated +# +# self.url_placeholders - Placeholders that may be used in the URL, which will be replaced +# with the values when the URL is generated. Must return a Hash +# mapping placeholder names to their values. For example, if this +# method returned +# +# { "year" => Time.now.strftime("%Y") } +# +# Every occurrence of ":year" (note the colon) would be replaced with +# the current year. +# +# + +module Jekyll + module URL + + # The generated relative url of this page. e.g. /about.html. + # + # Returns the String url. + def url + @url ||= sanitize_url(permalink || generate_url) + end + + # Generate the URL by replacing all placeholders with their respective values + # + # Returns the _unsanitizied_ String URL + def generate_url + url_placeholders.inject(template) { |result, token| + result.gsub(/:#{token.first}/, token.last) + } + end + + # Returns a sanitized String URL + def sanitize_url(in_url) + # Remove all double slashes + url = in_url.gsub(/\/\//, "/") + + # Remove every URL segment that consists solely of dots + url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/') + + # Append a trailing slash to the URL if the unsanitized URL had one + url += "/" if in_url =~ /\/$/ + url + end + end +end