From 7f18ac8f9943a88f29a9f8e61bc6dc7cd3fa2e20 Mon Sep 17 00:00:00 2001
From: Thiago Arrais
Group By Expression
+Group an array's items using a Liquid expression.
+
+ {% raw %}{{ site.members | group_by_exp:"item",
+"item.graduation_year | truncate: 3, \"\"" }}{% endraw %}
+
+ [{"name"=>"201...", "items"=>[...]},
+{"name"=>"200...", "items"=>[...]}]
+
XML Escape
diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb index 29f2a2b5..f1467fa5 100644 --- a/lib/jekyll/filters.rb +++ b/lib/jekyll/filters.rb @@ -8,6 +8,8 @@ require_all "jekyll/filters" module Jekyll module Filters include URLFilters + include GroupingFilters + # Convert a Markdown string into HTML output. # # input - The Markdown String to convert. @@ -205,29 +207,6 @@ module Jekyll as_liquid(input).to_json end - # Group an array of items by a property - # - # input - the inputted Enumerable - # property - the property - # - # Returns an array of Hashes, each looking something like this: - # {"name" => "larry" - # "items" => [...] } # all the items where `property` == "larry" - def group_by(input, property) - if groupable?(input) - input.group_by { |item| item_property(item, property).to_s } - .each_with_object([]) do |item, array| - array << { - "name" => item.first, - "items" => item.last, - "size" => item.last.size - } - end - else - input - end - end - # Filter an array of objects # # input - the object array @@ -381,11 +360,6 @@ module Jekyll end.localtime end - private - def groupable?(element) - element.respond_to?(:group_by) - end - private def item_property(item, property) if item.respond_to?(:to_liquid) @@ -436,6 +410,7 @@ module Jekyll condition end + end end diff --git a/lib/jekyll/filters/grouping_filters.rb b/lib/jekyll/filters/grouping_filters.rb new file mode 100644 index 00000000..372b1e7b --- /dev/null +++ b/lib/jekyll/filters/grouping_filters.rb @@ -0,0 +1,56 @@ +module Jekyll + module Filters + module GroupingFilters + # Group an array of items by a property + # + # input - the inputted Enumerable + # property - the property + # + # Returns an array of Hashes, each looking something like this: + # {"name" => "larry" + # "items" => [...] } # all the items where `property` == "larry" + def group_by(input, property) + if groupable?(input) + groups = input.group_by { |item| item_property(item, property).to_s } + make_grouped_array(groups) + else + input + end + end + + def group_by_exp(input, variable, expression) + return input unless groupable?(input) + + parsed_expr = parse_expression(expression) + @context.stack do + groups = input.group_by do |item| + @context[variable] = item + parsed_expr.render(@context) + end + make_grouped_array(groups) + end + end + + private + def parse_expression(str) + Liquid::Variable.new(str, {}) + end + + private + def groupable?(element) + element.respond_to?(:group_by) + end + + private + def make_grouped_array(groups) + groups.each_with_object([]) do |item, array| + array << { + "name" => item.first, + "items" => item.last, + "size" => item.last.size + } + end + end + end + end +end diff --git a/test/test_filters.rb b/test/test_filters.rb index 9a0f87d4..9a2909ef 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -747,6 +747,88 @@ class TestFilters < JekyllUnitTest end end + context "group_by_exp filter" do + should "successfully group array of Jekyll::Page's" do + @filter.site.process + groups = @filter.group_by_exp(@filter.site.pages, "page", "page.layout | upcase") + groups.each do |g| + assert( + ["DEFAULT", "NIL", ""].include?(g["name"]), + "#{g["name"]} isn't a valid grouping." + ) + case g["name"] + when "DEFAULT" + assert( + g["items"].is_a?(Array), + "The list of grouped items for 'default' is not an Array." + ) + assert_equal 5, g["items"].size + when "nil" + assert( + g["items"].is_a?(Array), + "The list of grouped items for 'nil' is not an Array." + ) + assert_equal 2, g["items"].size + when "" + assert( + g["items"].is_a?(Array), + "The list of grouped items for '' is not an Array." + ) + assert_equal 15, g["items"].size + end + end + end + + should "include the size of each grouping" do + groups = @filter.group_by_exp(@filter.site.pages, "page", "page.layout") + groups.each do |g| + p g + assert_equal( + g["items"].size, + g["size"], + "The size property for '#{g["name"]}' doesn't match the size of the Array." + ) + end + end + + should "allow more complex filters" do + items = [ + { "version"=>"1.0", "result"=>"slow" }, + { "version"=>"1.1.5", "result"=>"medium" }, + { "version"=>"2.7.3", "result"=>"fast" } + ] + + result = @filter.group_by_exp(items, "item", "item.version | split: '.' | first") + assert_equal 2, result.size + end + + should "be equivalent of group_by" do + actual = @filter.group_by_exp(@filter.site.pages, "page", "page.layout") + expected = @filter.group_by(@filter.site.pages, "layout") + + assert_equal expected, actual + end + + should "return any input that is not an array" do + assert_equal "some string", @filter.group_by_exp("some string", "la", "le") + end + + should "group by full element (as opposed to a field of the element)" do + items = %w(a b c d) + + result = @filter.group_by_exp(items, "item", "item") + assert_equal 4, result.length + assert_equal ["a"], result.first["items"] + end + + should "accept hashes" do + hash = { 1 => "a", 2 => "b", 3 => "c", 4 => "d" } + + result = @filter.group_by_exp(hash, "item", "item") + assert_equal 4, result.length + end + end + context "sort filter" do should "raise Exception when input is nil" do err = assert_raises ArgumentError do From 7ac9653f4efe61f12b27adb0a7261547c17e266c Mon Sep 17 00:00:00 2001 From: Thiago Arraiscontent for entry1.
\n built at 2013-04-09T23:22:00-04:00" in "_site/2013/04/09/entry1.html" - And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T03:14:00-04:00" in "_site/2013/04/10/entry2.html" + And I should see "Post Layout:content for entry1.
\n built at 2013-04-09T23:22:00-04:00" in "_site/2013/04/09/entry1.html" unless Windows + And I should see "Post Layout:content for entry1.
\n built at 2013-04-09T22:22:00-05:00" in "_site/2013/04/09/entry1.html" if on Windows + And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T03:14:00-04:00" in "_site/2013/04/10/entry2.html" unless Windows + And I should see "Post Layout:content for entry2.
\n built at 2013-04-10T02:14:00-05:00" in "_site/2013/04/10/entry2.html" if on Windows Scenario: Generate proper dates with explicitly set timezone (different than posts' time) Given I have a _layouts directory From f3300c177258e656d642a6d36c4b868c9706f70c Mon Sep 17 00:00:00 2001 From: Dean Attali
+ Built-in permalink styles are not recognized in YAML Front Matter. So
+ permalink: pretty
will not work, but the equivalent
+ /:categories/:year/:month/:day/:title/
+ using template variables will.
+
layout
.
For example, if you specify class: full_page
- in a page’s front matter, that value will be available as
+ in a layout’s front matter, that value will be available as
layout.class
in the layout and its parents.
From 2856fd3ac70bd4f566a40966c77c06f2a0389b96 Mon Sep 17 00:00:00 2001
From: jekyllbot file.path
- The relative path to the file, e.g /assets/img/image.jpg
+ The relative path to the file, e.g. /assets/img/image.jpg
file.modified_time
- The `Time` the file was last modified, e.g 2016-04-01 16:35:26 +0200
+ The `Time` the file was last modified, e.g. 2016-04-01 16:35:26 +0200
- Built-in permalink styles are not recognized in YAML Front Matter. So
- permalink: pretty
will not work, but the equivalent
- /:categories/:year/:month/:day/:title/
- using template variables will.
-
Built-in permalink styles are not recognized in YAML Front Matter. As a result, permalink: pretty
will not work, but the equivalent /:categories/:year/:month/:day/:title/
using template variables will.
- Year from the Post’s filename +Year from the post's filename |
- Month from the Post’s filename +Month from the post's filename |
- Month from the Post’s filename without leading zeros. +Month from the post's filename without leading zeros. |
- Day from the Post’s filename +Day from the post's filename |
- Day from the Post’s filename without leading zeros. +Day from the post's filename without leading zeros. |
- Year from the Post’s filename without the century. +Year from the post's filename without the century. |
- Hour of the day, 24-hour clock, zero-padded from the post’s |
- Minute of the hour from the post’s |
@@ -109,7 +144,7 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
- Second of the minute from the post’s |
@@ -130,8 +165,8 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
- Slugified title from the document’s filename ( any character
- except numbers and letters is replaced as hyphen ). May be
+ Slugified title from the document’s filename (any character
+ except numbers and letters is replaced as hyphen). May be
overridden via the document’s |
@@ -142,7 +177,7 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
- The specified categories for this Post. If a post has multiple
+ The specified categories for this post. If a post has multiple
categories, Jekyll will create a hierarchy (e.g. |
Built-in permalink styles are not recognized in YAML Front Matter. As a result, permalink: pretty
will not work, but the equivalent /:categories/:year/:month/:day/:title/
using template variables will.
Built-in permalink styles are not recognized in YAML Front Matter. As a result, permalink: pretty
will not work.
/:year/:month/:title
See extensionless permalinks for details.
+See Extensionless permalinks with no trailing slashes for details.
/2009/04/slap-chop
- Built-in permalink styles are not recognized in YAML Front Matter. So
- permalink: pretty
will not work, but the equivalent
- /:categories/:year/:month/:day/:title/
- using template variables will.
-
Variable | -Description | -
---|---|
-
|
-
- Year from the Post’s filename - |
-
-
|
-
- Month from the Post’s filename - |
-
-
|
-
- Month from the Post’s filename without leading zeros. - |
-
-
|
-
- Day from the Post’s filename - |
-
-
|
-
- Day from the Post’s filename without leading zeros. - |
-
-
|
-
- Year from the Post’s filename without the century. - |
-
-
|
-
-
- Hour of the day, 24-hour clock, zero-padded from the post’s |
-
-
|
-
-
- Minute of the hour from the post’s |
-
-
|
-
-
- Second of the minute from the post’s |
-
-
|
-
-
- Title from the document’s filename. May be overridden via
- the document’s |
-
-
|
-
-
- Slugified title from the document’s filename ( any character
- except numbers and letters is replaced as hyphen ). May be
- overridden via the document’s |
-
-
|
-
-
- The specified categories for this Post. If a post has multiple
- categories, Jekyll will create a hierarchy (e.g. |
-
Permalink Style | -URL Template | -
---|---|
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
URL Template | -Resulting Permalink URL | -
---|---|
- None specified, or |
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
|
-
-
See extensionless permalinks for details. - |
-
-
|
-
+ Built-in permalink styles are not recognized in YAML Front Matter. So
+ permalink: pretty
will not work, but the equivalent
+ /:categories/:year/:month/:day/:title/
+ using template variables will.
+
Variable | +Description | +
---|---|
+
|
+
+ Year from the Post’s filename + |
+
+
|
+
+ Month from the Post’s filename + |
+
+
|
+
+ Month from the Post’s filename without leading zeros. + |
+
+
|
+
+ Day from the Post’s filename + |
+
+
|
+
+ Day from the Post’s filename without leading zeros. + |
+
+
|
+
+ Year from the Post’s filename without the century. + |
+
+
|
+
+
+ Hour of the day, 24-hour clock, zero-padded from the post’s |
+
+
|
+
+
+ Minute of the hour from the post’s |
+
+
|
+
+
+ Second of the minute from the post’s |
+
+
|
+
+
+ Title from the document’s filename. May be overridden via
+ the document’s |
+
+
|
+
+
+ Slugified title from the document’s filename ( any character
+ except numbers and letters is replaced as hyphen ). May be
+ overridden via the document’s |
+
+
|
+
+
+ The specified categories for this Post. If a post has multiple
+ categories, Jekyll will create a hierarchy (e.g. |
+
Permalink Style | +URL Template | +
---|---|
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
URL Template | +Resulting Permalink URL | +
---|---|
+ None specified, or |
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
|
+
+
See extensionless permalinks for details. + |
+
+
|
+