diff --git a/lib/liquid/standardfilters.rb b/lib/liquid/standardfilters.rb index a244cc5a..0a956fbf 100644 --- a/lib/liquid/standardfilters.rb +++ b/lib/liquid/standardfilters.rb @@ -92,16 +92,16 @@ module Liquid # Join elements of the array with certain character between them def join(input, glue = ' '.freeze) - [input].flatten.join(glue) + InputIterator.new(input).join(glue) end # Sort elements of the array # provide optional property with which to sort an array of hashes or drops def sort(input, property = nil) - ary = flatten_if_necessary(input) + ary = InputIterator.new(input) if property.nil? ary.sort - elsif ary.first.respond_to?('[]'.freeze) and !ary.first[property].nil? + elsif ary.first.respond_to?('[]'.freeze) && !ary.first[property].nil? ary.sort {|a,b| a[property] <=> b[property] } elsif ary.first.respond_to?(property) ary.sort {|a,b| a.send(property) <=> b.send(property) } @@ -110,13 +110,13 @@ module Liquid # Reverse the elements of an array def reverse(input) - ary = [input].flatten + ary = InputIterator.new(input) ary.reverse end # map/collect on a given property def map(input, property) - flatten_if_necessary(input).map do |e| + InputIterator.new(input).map do |e| e = e.call if e.is_a?(Proc) if property == "to_liquid".freeze @@ -265,17 +265,6 @@ module Liquid private - def flatten_if_necessary(input) - ary = if input.is_a?(Array) - input.flatten - elsif input.is_a?(Enumerable) && !input.is_a?(Hash) - input - else - [input].flatten - end - ary.map{ |e| e.respond_to?(:to_liquid) ? e.to_liquid : e } - end - def to_number(obj) case obj when Float @@ -310,6 +299,36 @@ module Liquid result = to_number(input).send(operation, to_number(operand)) result.is_a?(BigDecimal) ? result.to_f : result end + + class InputIterator + include Enumerable + + def initialize(input) + @input = if input.is_a?(Array) + input.flatten + elsif input.is_a?(Hash) + [input] + elsif input.is_a?(Enumerable) + input + else + Array(input) + end + end + + def join(glue) + to_a.join(glue) + end + + def reverse + reverse_each.to_a + end + + def each + @input.each do |e| + yield(e.respond_to?(:to_liquid) ? e.to_liquid : e) + end + end + end end Template.register_filter(StandardFilters) diff --git a/test/integration/filter_test.rb b/test/integration/filter_test.rb index 58c92513..b6d1d4bf 100644 --- a/test/integration/filter_test.rb +++ b/test/integration/filter_test.rb @@ -67,12 +67,12 @@ class FiltersTest < Test::Unit::TestCase @context['value'] = 3 @context['numbers'] = [2,1,4,3] @context['words'] = ['expected', 'as', 'alphabetic'] - @context['arrays'] = [['flattened'], ['are']] + @context['arrays'] = ['flower', 'are'] assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context) assert_equal ['alphabetic', 'as', 'expected'], Variable.new("words | sort").render(@context) assert_equal [3], Variable.new("value | sort").render(@context) - assert_equal ['are', 'flattened'], Variable.new("arrays | sort").render(@context) + assert_equal ['are', 'flower'], Variable.new("arrays | sort").render(@context) end def test_strip_html diff --git a/test/integration/standard_filter_test.rb b/test/integration/standard_filter_test.rb index 9486ff6f..dc223d53 100644 --- a/test/integration/standard_filter_test.rb +++ b/test/integration/standard_filter_test.rb @@ -7,6 +7,8 @@ class Filters end class TestThing + attr_reader :foo + def initialize @foo = 0 end @@ -115,6 +117,10 @@ class StandardFiltersTest < Test::Unit::TestCase assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a") end + def test_legacy_sort_hash + assert_equal [{a:1, b:2}], @filters.sort({a:1, b:2}) + end + def test_numerical_vs_lexicographical_sort assert_equal [2, 10], @filters.sort([10, 2]) assert_equal [{"a" => 2}, {"a" => 10}], @filters.sort([{"a" => 10}, {"a" => 2}], "a") @@ -126,6 +132,10 @@ class StandardFiltersTest < Test::Unit::TestCase assert_equal [4,3,2,1], @filters.reverse([1,2,3,4]) end + def test_legacy_reverse_hash + assert_equal [{a:1, b:2}], @filters.reverse(a:1, b:2) + end + def test_map assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a') assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}", @@ -147,9 +157,16 @@ class StandardFiltersTest < Test::Unit::TestCase "thing" => { "foo" => [ { "bar" => 42 }, { "bar" => 17 } ] } end + def test_legacy_map_on_hashes_with_dynamic_key + template = "{% assign key = 'foo' %}{{ thing | map: key | map: 'bar' }}" + hash = { "foo" => { "bar" => 42 } } + assert_template_result "42", template, "thing" => hash + end + def test_sort_calls_to_liquid t = TestThing.new - assert_template_result "woot: 1", '{{ foo | sort: "whatever" }}', "foo" => [t] + Liquid::Template.parse('{{ foo | sort: "whatever" }}').render("foo" => [t]) + assert t.foo > 0 end def test_map_over_proc