diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index 808c93c2d..4bf8cb788 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -414,6 +414,29 @@ def where(input, property, target_value = nil) end end + # Reject the elements of an array to those with a certain property value. + # By default the target is any falsy value. + def reject(input, properties, target_value = nil) + raise_property_error(properties) unless properties.is_a?(String) + + properties = properties.to_s.split('.') + ary = InputIterator.new(input, context) + + ary.reject do |item| + if item.is_a?(Hash) + value = item.dig(*properties) + + if target_value.nil? + !value + else + value == target_value + end + else + true + end + end + end + # @liquid_public_docs # @liquid_type filter # @liquid_category array diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index f413e6f99..b9cc1ead1 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -864,6 +864,81 @@ def test_where_array_of_only_unindexable_values assert_nil(@filters.where([nil], "ok")) end + def test_reject + input = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "beta", "ok" => false }, + { "handle" => "gamma", "ok" => false }, + { "handle" => "delta", "ok" => true }, + ] + + expectation = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "delta", "ok" => true }, + ] + + assert_equal(expectation, @filters.reject(input, "ok", false)) + assert_equal(expectation, @filters.reject(input, "ok")) + end + + def test_reject_no_key_set + input = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "beta" }, + { "handle" => "gamma" }, + { "handle" => "delta", "ok" => true }, + ] + + expectation = [ + { "handle" => "alpha", "ok" => true }, + { "handle" => "delta", "ok" => true }, + ] + + assert_equal(expectation, @filters.reject(input, "ok")) + end + + def test_reject_non_array_map_input + assert_equal([], @filters.reject({ "foo" => "bar" }, "foo", "bar")) + assert_equal([{ "foo" => "baz" }], @filters.reject({ "foo" => "baz" }, "foo", "bar")) + end + + def test_reject_indexable_but_non_map_value + assert_equal([], @filters.reject(1, "ok", true)) + assert_equal([], @filters.reject(1, "ok")) + end + + def test_reject_non_boolean_value + input = [ + { "message" => "Bonjour!", "language" => "French" }, + { "message" => "Hello!", "language" => "English" }, + ] + + assert_equal([{ "message" => "Hello!", "language" => "English" }], @filters.reject(input, "language", "French")) + assert_equal([{ "message" => "Bonjour!", "language" => "French" }], @filters.reject(input, "language", "English")) + end + + def test_reject_array_of_only_unindexable_values + assert_equal([], @filters.reject([nil, nil], "ok", true)) + assert_equal([], @filters.reject([nil, nil], "ok")) + end + + def test_reject_deep + input = [ + { "item" => { "handle" => "alpha", "ok" => true } }, + { "item" => { "handle" => "beta", "ok" => false } }, + { "item" => { "handle" => "gamma", "ok" => false } }, + { "item" => { "handle" => "delta", "ok" => true } }, + ] + + expectation = [ + { "item" => { "handle" => "alpha", "ok" => true } }, + { "item" => { "handle" => "delta", "ok" => true } }, + ] + + assert_equal(expectation, @filters.reject(input, "item.ok", false)) + assert_equal(expectation, @filters.reject(input, "item.ok")) + end + def test_all_filters_never_raise_non_liquid_exception test_drop = TestDrop.new(value: "test") test_drop.context = Context.new