Merge pull request #5513 from thiagoarrais/5415-group_by_exp-filter
Merge pull request 5513
This commit is contained in:
commit
8ed324007a
|
@ -147,6 +147,22 @@ common tasks easier.
|
|||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p class="name"><strong>Group By Expression</strong></p>
|
||||
<p>Group an array's items using a Liquid expression.</p>
|
||||
</td>
|
||||
<td class="align-center">
|
||||
<p>
|
||||
<code class="filter">{% raw %}{{ site.members | group_by_exp:"item",
|
||||
"item.graduation_year | truncate: 3, \"\"" }}{% endraw %}</code>
|
||||
</p>
|
||||
<p>
|
||||
<code class="output">[{"name"=>"201...", "items"=>[...]},
|
||||
{"name"=>"200...", "items"=>[...]}]</code>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p class="name"><strong>XML Escape</strong></p>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
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 }
|
||||
grouped_array(groups)
|
||||
else
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# Group an array of items by an expression
|
||||
#
|
||||
# input - the object array
|
||||
# variable - the variable to assign each item to in the expression
|
||||
# expression -a Liquid comparison expression passed in as a string
|
||||
#
|
||||
# Returns the filtered array of objects
|
||||
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
|
||||
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 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
|
|
@ -756,6 +756,91 @@ 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."
|
||||
)
|
||||
# adjust array.size to ignore symlinked page in Windows
|
||||
qty = Utils::Platforms.really_windows? ? 4 : 5
|
||||
assert_equal qty, 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."
|
||||
)
|
||||
# adjust array.size to ignore symlinked page in Windows
|
||||
qty = Utils::Platforms.really_windows? ? 14 : 15
|
||||
assert_equal qty, 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|
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue