diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb index e76fa755..ff13a233 100644 --- a/lib/jekyll/filters.rb +++ b/lib/jekyll/filters.rb @@ -51,12 +51,12 @@ module Jekyll # Slugify a filename or title. # # input - The filename or title to slugify. + # mode - how string is slugified # - # Returns the given filename or title as a lowercase String, with every - # sequence of spaces and non-alphanumeric characters replaced with a - # hyphen. - def slugify(input) - Utils.slugify(input) + # Returns the given filename or title as a lowercase URL String. + # See Utils.slugify for more detail. + def slugify(input, mode=nil) + Utils.slugify(input, mode) end # Format a date in short format e.g. "27 Jan 2011". diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb index a84847a4..ba0303a4 100644 --- a/lib/jekyll/utils.rb +++ b/lib/jekyll/utils.rb @@ -104,21 +104,53 @@ module Jekyll # Slugify a filename or title. # - # name - the filename or title to slugify + # string - the filename or title to slugify + # mode - how string is slugified # - # Returns the given filename or title in lowercase, with every - # sequence of spaces and non-alphanumeric characters replaced with a - # hyphen. - def slugify(string) - unless string.nil? - string \ - # Replace each non-alphanumeric character sequence with a hyphen - .gsub(/[^[:alnum:]]+/i, '-') \ - # Remove leading/trailing hyphen - .gsub(/^\-|\-$/i, '') \ - # Downcase it - .downcase + # When mode is "none", return the given string in lowercase. + # + # When mode is "raw", return the given string in lowercase, + # with every sequence of spaces characters replaced with a hyphen. + # + # When mode is "default" or nil, non-alphabetic characters are + # replaced with a hyphen too. + # + # When mode is "pretty", some non-alphabetic characters (._~!$&'()+,;=@) + # are not replaced with hyphen. + # + # Examples: + # slugify("The _config.yml file") + # # => "the-config-yml-file" + # + # slugify("The _config.yml file", "pretty") + # # => "the-_config.yml-file" + # + # Returns the slugified string. + def slugify(string, mode=nil) + mode ||= 'default' + return nil if string.nil? + + # Replace each character sequence with a hyphen + re = case mode + when 'raw' + Regexp.new('\\s+') + when 'default' + Regexp.new('[^[:alnum:]]+') + when 'pretty' + # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL + # and is allowed in both extN and NTFS. + Regexp.new("[^a-zA-Z0-9._~!$&'()+,;=@]+") + else + return string.downcase end + + string. + # Strip according to the mode + gsub(re, '-'). + # Remove leading/trailing hyphen + gsub(/^\-|\-$/i, ''). + # Downcase + downcase end end diff --git a/site/_docs/templates.md b/site/_docs/templates.md index 12a70fc4..1b2877b2 100644 --- a/site/_docs/templates.md +++ b/site/_docs/templates.md @@ -212,11 +212,20 @@ common tasks easier.

Slugify

-

Convert a string into a lowercase URL "slug" by replacing every sequence of spaces and non-alphanumeric characters with a hyphen.

+

Convert a string into a lowercase URL "slug". See below for options.

- {% raw %}{{ page.title | slugify }}{% endraw %} + {% raw %}{{ "The _config.yml file" | slugify }}{% endraw %} +

+

+ the-config-yml-file +

+

+ {% raw %}{{ "The _config.yml file" | slugify: 'pretty' }}{% endraw %} +

+

+ the-_config.yml-file

@@ -252,6 +261,16 @@ common tasks easier. +### Options for the `slugify` filter + +The `slugify` filter accepts an option, each specifying what to filter. +The default is `default`. The are as follows (with what they filter): + +- `none`: no characters +- `raw`: spaces +- `default`: spaces and non-alphanumeric characters +- `pretty`: spaces and non-alphanumeric characters except for `._~!$&'()+,;=@` + ## Tags ### Includes diff --git a/test/test_filters.rb b/test/test_filters.rb index a8cd9737..0e18dc02 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -323,6 +323,10 @@ class TestFilters < Test::Unit::TestCase should "return a slugified string" do assert_equal "q-bert-says", @filter.slugify(" Q*bert says @!#?@!") end + + should "return a slugified string with mode" do + assert_equal "q-bert-says-@!-@!", @filter.slugify(" Q*bert says @!#?@!", "pretty") + end end context "push filter" do diff --git a/test/test_utils.rb b/test/test_utils.rb index 6e643856..594281eb 100644 --- a/test/test_utils.rb +++ b/test/test_utils.rb @@ -144,6 +144,26 @@ class TestUtils < Test::Unit::TestCase Utils.slugify(title) assert_equal "Quick-start guide", title end + + should "not change behaviour if mode is default" do + assert_equal "the-config-yml-file", Utils.slugify("The _config.yml file?", "default") + end + + should "not change behaviour if mode is nil" do + assert_equal "the-config-yml-file", Utils.slugify("The _config.yml file?", nil) + end + + should "not replace period and underscore if mode is pretty" do + assert_equal "the-_config.yml-file", Utils.slugify("The _config.yml file?", "pretty") + end + + should "only replace whitespace if mode is raw" do + assert_equal "the-_config.yml-file?", Utils.slugify("The _config.yml file?", "raw") + end + + should "return the given string if mode is none" do + assert_equal "the _config.yml file?", Utils.slugify("The _config.yml file?", "none") + end end end