diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index 2041e4c9..10069f6c 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -1,7 +1,6 @@ module Jekyll class Page include Convertible - include URL attr_writer :dir attr_accessor :site, :pager @@ -63,6 +62,17 @@ module Jekyll end end + # The generated relative url of this page. e.g. /about.html. + # + # Returns the String url. + def url + @url ||= URL.new({ + :template => template, + :placeholders => url_placeholders, + :permalink => permalink + }).to_s + end + # See url.rb for an explanation def url_placeholders { diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index 79e751fe..6b5c38d5 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -2,7 +2,6 @@ module Jekyll class Post include Comparable include Convertible - include URL class << self attr_accessor :lsi @@ -195,6 +194,17 @@ module Jekyll end end + # The generated relative url of this post. + # + # Returns the String url. + def url + @url ||= URL.new({ + :template => template, + :placeholders => url_placeholders, + :permalink => permalink + }).to_s + end + # See url.rb for an explanation def url_placeholders { @@ -204,7 +214,7 @@ module Jekyll "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('/'), + "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 diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb index fb9f8ee0..383cebaa 100644 --- a/lib/jekyll/url.rb +++ b/lib/jekyll/url.rb @@ -1,38 +1,49 @@ -# The URL module provides methods that generate a URL for a resource in which they're -# included, such as a Post or a Page. +# Public: Methods that generate a URL for a resource such as a Post or a Page. # -# Requires +# Examples # -# 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 +# URL.new({ +# :template => /:categories/:title.html", +# :placeholders => {:categories => "ruby", :title => "something"} +# }).to_s # -# 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 + class URL - # The generated relative url of this page. e.g. /about.html. - # - # Returns the String url. - def url - @url ||= sanitize_url(permalink || generate_url) + # options - One of :permalink or :template must be supplied. + # :template - The String used as template for URL generation, + # for example "/:path/:basename:output_ext", where + # a placeholder is prefixed with a colon. + # :placeholders - A hash containing the placeholders which will be + # replaced when used inside the template. E.g. + # { "year" => Time.now.strftime("%Y") } would replace + # the placeholder ":year" with the current year. + # :permalink - If supplied, no URL will be generated from the + # template. Instead, the given permalink will be + # used as URL. + def initialize(options) + @template = options[:template] + @placeholders = options[:placeholders] || {} + @permalink = options[:permalink] + + if (@template || @permalink).nil? + raise ArgumentError, "One of :template or :permalink must be supplied." + end end - # Generate the URL by replacing all placeholders with their respective values + # The generated relative URL of the resource + # + # Returns the String URL + def to_s + sanitize_url(@permalink || generate_url) + end + + # Internal: 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| + @placeholders.inject(@template) { |result, token| result.gsub(/:#{token.first}/, token.last) } end diff --git a/test/test_url.rb b/test/test_url.rb new file mode 100644 index 00000000..0576eda2 --- /dev/null +++ b/test/test_url.rb @@ -0,0 +1,28 @@ +require 'helper' + +class TestURL < Test::Unit::TestCase + context "The URL class" do + + should "throw an exception if neither permalink or template is specified" do + assert_raises ArgumentError do + URL.new(:placeholders => {}) + end + end + + should "replace placeholders in templates" do + assert_equal "/foo/bar", URL.new( + :template => "/:x/:y", + :placeholders => {:x => "foo", :y => "bar"} + ).to_s + end + + should "return permalink if given" do + assert_equal "/le/perma/link", URL.new( + :template => "/:x/:y", + :placeholders => {:x => "foo", :y => "bar"}, + :permalink => "/le/perma/link" + ).to_s + end + + end +end