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 'uri'
|
||||||
require 'json'
|
require 'json'
|
||||||
require 'date'
|
require 'date'
|
||||||
|
require 'liquid'
|
||||||
|
|
||||||
module Jekyll
|
module Jekyll
|
||||||
module Filters
|
module Filters
|
||||||
|
@ -225,6 +226,26 @@ module Jekyll
|
||||||
input.select { |object| Array(item_property(object, property)).map(&:to_s).include?(value.to_s) }
|
input.select { |object| Array(item_property(object, property)).map(&:to_s).include?(value.to_s) }
|
||||||
end
|
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
|
# Sort an array of objects
|
||||||
#
|
#
|
||||||
# input - the object array
|
# input - the object array
|
||||||
|
@ -363,5 +384,21 @@ module Jekyll
|
||||||
end
|
end
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -88,6 +88,22 @@ common tasks easier.
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<p class="name"><strong>Group By</strong></p>
|
<p class="name"><strong>Group By</strong></p>
|
||||||
|
|
|
@ -354,6 +354,64 @@ class TestFilters < JekyllUnitTest
|
||||||
end
|
end
|
||||||
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
|
context "sort filter" do
|
||||||
should "raise Exception when input is nil" do
|
should "raise Exception when input is nil" do
|
||||||
err = assert_raises ArgumentError do
|
err = assert_raises ArgumentError do
|
||||||
|
|
Loading…
Reference in New Issue