From 19e704f408268f037e9d612ae85adbf253583254 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Mon, 5 May 2014 10:26:46 +0200 Subject: [PATCH 01/14] Override the sort filter --- lib/jekyll/filters.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb index 997a0f5d..ced9623f 100644 --- a/lib/jekyll/filters.rb +++ b/lib/jekyll/filters.rb @@ -190,6 +190,29 @@ module Jekyll input.select { |object| object[key] == value } end + # Sort an array of objects + # + # input - the object array + # key - key within each object to filter by + # nils_last - nils appear after non-nil values in the sort ordering + # + # Returns the filtered array of objects + def sort(input, key = nil, nils_last = false) + if key.nil? + input.sort + else + input.sort { |a, b| + if a[key].nil? and !b[key].nil? + nils_last ? +1 : -1 + elsif !a[key].nil? and b[key].nil? + nils_last ? -1 : +1 + else + a[key] <=> b[key] + end + } + end + end + private def time(input) case input From 3517b9f4e2d2f7d38d448d49b9bb59f2419f875e Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Mon, 5 May 2014 10:35:19 +0200 Subject: [PATCH 02/14] Add scenario --- features/embed_filters.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/embed_filters.feature b/features/embed_filters.feature index 27f5f1df..e0d85cbd 100644 --- a/features/embed_filters.feature +++ b/features/embed_filters.feature @@ -73,3 +73,19 @@ Feature: Embed filters Then the _site directory should exist And I should see exactly "Page-2, Page-1" in "_site/page-1.html" And I should see exactly "Page-2, Page-1" in "_site/page-2.html" + + Scenario: Sort pages by the title + Given I have a _layouts directory + And I have the following page: + | title | layout | content | + | Dog | default | Run | + And I have the following page: + | title | layout | content | + | Bird | default | Fly | + And I have the following page: + | layout | content | + | default | Jump | + And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title' %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}" + When I run jekyll build + Then the _site directory should exist + And I should see exactly "The rule of 3: Jump, Fly, Run," in "_site/bird.html" From 367a818c267408f364427e0e7eba1d2a4ea9ea14 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Mon, 5 May 2014 10:37:21 +0200 Subject: [PATCH 03/14] Fallback title based on time --- features/support/env.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/support/env.rb b/features/support/env.rb index 80020690..29875629 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -28,7 +28,11 @@ def run_jekyll(args) end def slug(title) - title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-') + if title + title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-') + else + Time.now.strftime("%s%9N") # nanoseconds since the Epoch + end end def location(folder, direction) From 12d9f8b02bffb0cc779d78216d302758c7a4eb09 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Mon, 5 May 2014 10:49:29 +0200 Subject: [PATCH 04/14] Add scenario for ordering pages without title last --- features/embed_filters.feature | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/features/embed_filters.feature b/features/embed_filters.feature index e0d85cbd..b1a420f5 100644 --- a/features/embed_filters.feature +++ b/features/embed_filters.feature @@ -89,3 +89,19 @@ Feature: Embed filters When I run jekyll build Then the _site directory should exist And I should see exactly "The rule of 3: Jump, Fly, Run," in "_site/bird.html" + + Scenario: Sort pages by the title ordering pages without title last + Given I have a _layouts directory + And I have the following page: + | title | layout | content | + | Dog | default | Run | + And I have the following page: + | title | layout | content | + | Bird | default | Fly | + And I have the following page: + | layout | content | + | default | Jump | + And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title', true %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}" + When I run jekyll build + Then the _site directory should exist + And I should see exactly "The rule of 3: Fly, Run, Jump," in "_site/bird.html" From cc80aab1919ece7872af24f1ca735dea1e500464 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Mon, 5 May 2014 11:14:07 +0200 Subject: [PATCH 05/14] Add generic tests --- test/test_filters.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_filters.rb b/test/test_filters.rb index 67bcd096..0d3d8def 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -152,5 +152,24 @@ class TestFilters < Test::Unit::TestCase end end + context "sort filter" do + should "return sorted array" do + assert_equal [1, 2, 3, 4], @filter.sort([4, 3, 2, 1]) + end + should "return sorted by property array" do + assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], + @filter.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a") + end + should "return sorted by property array with nils first" do + ary = [{"a" => 2}, {"b" => 1}, {"a" => 1}] + assert_equal [{"b" => 1}, {"a" => 1}, {"a" => 2}], @filter.sort(ary, "a") + assert_equal @filter.sort(ary, "a"), @filter.sort(ary, "a", false) + end + should "return sorted by property array with nils last" do + assert_equal [{"a" => 1}, {"a" => 2}, {"b" => 1}], + @filter.sort([{"a" => 2}, {"b" => 1}, {"a" => 1}], "a", true) + end + end + end end From 9c9e96cfa7bfe73f41e2d35a71f822907000c554 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 07:48:33 +0200 Subject: [PATCH 06/14] Add lexicographical sort test --- test/test_filters.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_filters.rb b/test/test_filters.rb index 0d3d8def..94093259 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -169,6 +169,12 @@ class TestFilters < Test::Unit::TestCase assert_equal [{"a" => 1}, {"a" => 2}, {"b" => 1}], @filter.sort([{"a" => 2}, {"b" => 1}, {"a" => 1}], "a", true) end + should "return lexicographical sorted array" do + assert_equal [2, 10], @filter.sort([10, 2]) + assert_equal [{"a" => 2}, {"a" => 10}], @filter.sort([{"a" => 10}, {"a" => 2}], "a") + assert_equal ["10", "2"], @filter.sort(["10", "2"]) + assert_equal [{"a" => "10"}, {"a" => "2"}], @filter.sort([{"a" => "10"}, {"a" => "2"}], "a") + end end end From 558d0e8ac9ae48719a71eac48ffc5cb06fbd33c4 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:07:09 +0200 Subject: [PATCH 07/14] Add more strings tests --- test/test_filters.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test_filters.rb b/test/test_filters.rb index 94093259..66db980e 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -153,8 +153,14 @@ class TestFilters < Test::Unit::TestCase end context "sort filter" do - should "return sorted array" do - assert_equal [1, 2, 3, 4], @filter.sort([4, 3, 2, 1]) + should "return sorted numbers" do + assert_equal [1, 2, 2.2, 3], @filter.sort([3, 2.2, 2, 1]) + end + should "return sorted strings" do + assert_equal ["10", "2"], @filter.sort(["10", "2"]) + assert_equal [{"a" => "10"}, {"a" => "2"}], @filter.sort([{"a" => "10"}, {"a" => "2"}], "a") + assert_equal ["FOO", "Foo", "foo"], @filter.sort(["foo", "Foo", "FOO"]) + assert_equal ["_foo", "foo", "foo_"], @filter.sort(["foo_", "_foo", "foo"]) end should "return sorted by property array" do assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @@ -169,12 +175,6 @@ class TestFilters < Test::Unit::TestCase assert_equal [{"a" => 1}, {"a" => 2}, {"b" => 1}], @filter.sort([{"a" => 2}, {"b" => 1}, {"a" => 1}], "a", true) end - should "return lexicographical sorted array" do - assert_equal [2, 10], @filter.sort([10, 2]) - assert_equal [{"a" => 2}, {"a" => 10}], @filter.sort([{"a" => 10}, {"a" => 2}], "a") - assert_equal ["10", "2"], @filter.sort(["10", "2"]) - assert_equal [{"a" => "10"}, {"a" => "2"}], @filter.sort([{"a" => "10"}, {"a" => "2"}], "a") - end end end From 14e0abc4e2c4a2931199a39c88699a123d40e349 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:21:04 +0200 Subject: [PATCH 08/14] Add documentation --- site/docs/templates.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/site/docs/templates.md b/site/docs/templates.md index a4c79184..460e4d32 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -184,6 +184,18 @@ common tasks easier.

+ + +

Sort

+

Sort array. Optional arguments: property, nils last.

+ + +

+ {% raw %}{{ page.tags | sort }}{% endraw %} + {% raw %}{{ site.pages | sort: 'title', true }}{% endraw %} +

+ + From 7c1709fab4b0ef1ce9957cbcc6635f538850ae3c Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:36:13 +0200 Subject: [PATCH 09/14] Change nils argument to string --- features/embed_filters.feature | 2 +- lib/jekyll/filters.rb | 8 ++++---- site/docs/templates.md | 5 +++-- test/test_filters.rb | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/features/embed_filters.feature b/features/embed_filters.feature index b1a420f5..889a1fc7 100644 --- a/features/embed_filters.feature +++ b/features/embed_filters.feature @@ -101,7 +101,7 @@ Feature: Embed filters And I have the following page: | layout | content | | default | Jump | - And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title', true %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}" + And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title', 'last' %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}" When I run jekyll build Then the _site directory should exist And I should see exactly "The rule of 3: Fly, Run, Jump," in "_site/bird.html" diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb index ced9623f..fe438834 100644 --- a/lib/jekyll/filters.rb +++ b/lib/jekyll/filters.rb @@ -194,18 +194,18 @@ module Jekyll # # input - the object array # key - key within each object to filter by - # nils_last - nils appear after non-nil values in the sort ordering + # nils ('first' | 'last') - nils appear before or after non-nil values # # Returns the filtered array of objects - def sort(input, key = nil, nils_last = false) + def sort(input, key = nil, nils = 'first') if key.nil? input.sort else input.sort { |a, b| if a[key].nil? and !b[key].nil? - nils_last ? +1 : -1 + nils == 'first' ? -1 : +1 elsif !a[key].nil? and b[key].nil? - nils_last ? -1 : +1 + nils == 'first' ? +1 : -1 else a[key] <=> b[key] end diff --git a/site/docs/templates.md b/site/docs/templates.md index 460e4d32..dd8c8107 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -187,12 +187,13 @@ common tasks easier.

Sort

-

Sort array. Optional arguments: property, nils last.

+

Sort array. Optional arguments: property name; nils order (*first* or *last*).

{% raw %}{{ page.tags | sort }}{% endraw %} - {% raw %}{{ site.pages | sort: 'title', true }}{% endraw %} + {% raw %}{{ site.posts | sort: 'author' }}{% endraw %} + {% raw %}{{ site.pages | sort: 'title', 'last' }}{% endraw %}

diff --git a/test/test_filters.rb b/test/test_filters.rb index 66db980e..2f54538a 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -169,11 +169,11 @@ class TestFilters < Test::Unit::TestCase should "return sorted by property array with nils first" do ary = [{"a" => 2}, {"b" => 1}, {"a" => 1}] assert_equal [{"b" => 1}, {"a" => 1}, {"a" => 2}], @filter.sort(ary, "a") - assert_equal @filter.sort(ary, "a"), @filter.sort(ary, "a", false) + assert_equal @filter.sort(ary, "a"), @filter.sort(ary, "a", "first") end should "return sorted by property array with nils last" do assert_equal [{"a" => 1}, {"a" => 2}, {"b" => 1}], - @filter.sort([{"a" => 2}, {"b" => 1}, {"a" => 1}], "a", true) + @filter.sort([{"a" => 2}, {"b" => 1}, {"a" => 1}], "a", "last") end end From dc0e577b44193a8761c44c14812a65da96011152 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:40:52 +0200 Subject: [PATCH 10/14] Fix markup --- site/docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/templates.md b/site/docs/templates.md index dd8c8107..8e025779 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -187,7 +187,7 @@ common tasks easier.

Sort

-

Sort array. Optional arguments: property name; nils order (*first* or *last*).

+

Sort array. Optional arguments: property name; nils order ('first' or 'last').

From 2ee7e735318db0448ab45a7f1f69f8487363785f Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:50:33 +0200 Subject: [PATCH 11/14] Improve the description --- site/docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/templates.md b/site/docs/templates.md index 8e025779..03a42eec 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -187,7 +187,7 @@ common tasks easier.

Sort

-

Sort array. Optional arguments: property name; nils order ('first' or 'last').

+

Sort an array. Optional arguments for hashes: 1. property name (string) 2. nils order (string first or last).

From 3a1c18ede202385ce74cff7d8b2d6139fe81cd6a Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 21:54:12 +0200 Subject: [PATCH 12/14] Remove the hint aout type --- site/docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/templates.md b/site/docs/templates.md index 03a42eec..f7b58d84 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -187,7 +187,7 @@ common tasks easier.

Sort

-

Sort an array. Optional arguments for hashes: 1. property name (string) 2. nils order (string first or last).

+

Sort an array. Optional arguments for hashes: 1. property name 2. nils order (first or last).

From 19b0fe97812b2b31ce26b47fd73a07cc1f3264d4 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 22:00:28 +0200 Subject: [PATCH 13/14] Separate example codes [ci skip] --- site/docs/templates.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/site/docs/templates.md b/site/docs/templates.md index f7b58d84..81201339 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -192,7 +192,11 @@ common tasks easier.

{% raw %}{{ page.tags | sort }}{% endraw %} +

+

{% raw %}{{ site.posts | sort: 'author' }}{% endraw %} +

+

{% raw %}{{ site.pages | sort: 'title', 'last' }}{% endraw %}

From 1e0d9f899b5f81da7e2dbe7c324e34352dba4fd9 Mon Sep 17 00:00:00 2001 From: Anatol Broder Date: Tue, 6 May 2014 22:49:49 +0200 Subject: [PATCH 14/14] Follow Ruby Styleguide --- lib/jekyll/filters.rb | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb index fe438834..10c1aa41 100644 --- a/lib/jekyll/filters.rb +++ b/lib/jekyll/filters.rb @@ -197,15 +197,26 @@ module Jekyll # nils ('first' | 'last') - nils appear before or after non-nil values # # Returns the filtered array of objects - def sort(input, key = nil, nils = 'first') + def sort(input, key = nil, nils = "first") if key.nil? input.sort else + case + when nils == "first" + order = - 1 + when nils == "last" + order = + 1 + else + Jekyll.logger.error "Invalid nils order:", + "'#{nils}' is not a valid nils order. It must be 'first' or 'last'." + exit(1) + end + input.sort { |a, b| - if a[key].nil? and !b[key].nil? - nils == 'first' ? -1 : +1 - elsif !a[key].nil? and b[key].nil? - nils == 'first' ? +1 : -1 + if !a[key].nil? && b[key].nil? + - order + elsif a[key].nil? && !b[key].nil? + + order else a[key] <=> b[key] end