Merge pull request #4478 from edgemaster/where-exp
Merge pull request 4478
This commit is contained in:
commit
fc0d440201
|
@ -1,6 +1,7 @@
|
|||
require 'uri'
|
||||
require 'json'
|
||||
require 'date'
|
||||
require 'liquid'
|
||||
|
||||
module Jekyll
|
||||
module Filters
|
||||
|
@ -225,6 +226,26 @@ module Jekyll
|
|||
input.select { |object| Array(item_property(object, property)).map(&:to_s).include?(value.to_s) }
|
||||
end
|
||||
|
||||
# Filters an array of objects against 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 where_exp(input, variable, expression)
|
||||
return input unless input.is_a?(Enumerable)
|
||||
input = input.values if input.is_a?(Hash) # FIXME
|
||||
|
||||
condition = parse_condition(expression)
|
||||
@context.stack do
|
||||
input.select do |object|
|
||||
@context[variable] = object
|
||||
condition.evaluate(@context)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sort an array of objects
|
||||
#
|
||||
# input - the object array
|
||||
|
@ -363,5 +384,21 @@ module Jekyll
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Parse a string to a Liquid Condition
|
||||
def parse_condition(exp)
|
||||
parser = Liquid::Parser.new(exp)
|
||||
left_expr = parser.expression
|
||||
operator = parser.consume?(:comparison)
|
||||
condition =
|
||||
if operator
|
||||
Liquid::Condition.new(left_expr, operator, parser.expression)
|
||||
else
|
||||
Liquid::Condition.new(left_expr)
|
||||
end
|
||||
parser.consume(:end_of_string)
|
||||
|
||||
condition
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -88,6 +88,22 @@ common tasks easier.
|
|||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p class="name"><strong>Where Expression</strong></p>
|
||||
<p>Select all the objects in an array where the expression is true.</p>
|
||||
</td>
|
||||
<td class="align-center">
|
||||
<p>
|
||||
<code class="filter">{% raw %}{{ site.members | where_exp:"item",
|
||||
"item.graduation_year == 2014" }}{% endraw %}</code>
|
||||
<code class="filter">{% raw %}{{ site.members | where_exp:"item",
|
||||
"item.graduation_year < 2014" }}{% endraw %}</code>
|
||||
<code class="filter">{% raw %}{{ site.members | where_exp:"item",
|
||||
"item.projects contains 'foo'" }}{% endraw %}</code>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p class="name"><strong>Group By</strong></p>
|
||||
|
|
|
@ -354,6 +354,64 @@ class TestFilters < JekyllUnitTest
|
|||
end
|
||||
end
|
||||
|
||||
context "where_exp filter" do
|
||||
should "return any input that is not an array" do
|
||||
assert_equal "some string", @filter.where_exp("some string", "la", "le")
|
||||
end
|
||||
|
||||
should "filter objects in a hash appropriately" do
|
||||
hash = {"a"=>{"color"=>"red"}, "b"=>{"color"=>"blue"}}
|
||||
assert_equal 1, @filter.where_exp(hash, "item", "item.color == 'red'").length
|
||||
assert_equal [{"color"=>"red"}], @filter.where_exp(hash, "item", "item.color == 'red'")
|
||||
end
|
||||
|
||||
should "filter objects appropriately" do
|
||||
assert_equal 2, @filter.where_exp(@array_of_objects, "item", "item.color == 'red'").length
|
||||
end
|
||||
|
||||
should "stringify during comparison for compatibility with liquid parsing" do
|
||||
hash = {
|
||||
"The Words" => {"rating" => 1.2, "featured" => false},
|
||||
"Limitless" => {"rating" => 9.2, "featured" => true},
|
||||
"Hustle" => {"rating" => 4.7, "featured" => true},
|
||||
}
|
||||
|
||||
results = @filter.where_exp(hash, "item", "item.featured == true")
|
||||
assert_equal 2, results.length
|
||||
assert_equal 9.2, results[0]["rating"]
|
||||
assert_equal 4.7, results[1]["rating"]
|
||||
|
||||
results = @filter.where_exp(hash, "item", "item.rating == 4.7")
|
||||
assert_equal 1, results.length
|
||||
assert_equal 4.7, results[0]["rating"]
|
||||
end
|
||||
|
||||
should "filter with other operators" do
|
||||
assert_equal [3, 4, 5], @filter.where_exp([ 1, 2, 3, 4, 5 ], "n", "n >= 3")
|
||||
end
|
||||
|
||||
objects = [
|
||||
{ "id" => "a", "groups" => [1, 2] },
|
||||
{ "id" => "b", "groups" => [2, 3] },
|
||||
{ "id" => "c" },
|
||||
{ "id" => "d", "groups" => [1, 3] }
|
||||
]
|
||||
should "filter with the contains operator over arrays" do
|
||||
results = @filter.where_exp(objects, "obj", "obj.groups contains 1")
|
||||
assert_equal 2, results.length
|
||||
assert_equal "a", results[0]["id"]
|
||||
assert_equal "d", results[1]["id"]
|
||||
end
|
||||
|
||||
should "filter with the contains operator over hash keys" do
|
||||
results = @filter.where_exp(objects, "obj", "obj contains 'groups'")
|
||||
assert_equal 3, results.length
|
||||
assert_equal "a", results[0]["id"]
|
||||
assert_equal "b", results[1]["id"]
|
||||
assert_equal "d", results[2]["id"]
|
||||
end
|
||||
end
|
||||
|
||||
context "sort filter" do
|
||||
should "raise Exception when input is nil" do
|
||||
err = assert_raises ArgumentError do
|
||||
|
|
Loading…
Reference in New Issue