Resolves #529. Resolves #404. Added natural sorting filter and tests.

This commit is contained in:
Martin Hanzel
2015-05-03 20:55:28 -04:00
parent 251ce7483c
commit 03b3446119
2 changed files with 57 additions and 0 deletions
+21
View File
@@ -122,6 +122,27 @@ module Liquid
end
end
# Sort elements of an array ignoring case if strings
# provide optional property with which to sort an array of hashes or drops
def sort_natural(input, property = nil)
ary = InputIterator.new(input)
# Quick function that returns the downcased object if it has a downcase,
# otherwise it returns the object itself.
insensitive = lambda do |obj|
obj = obj.downcase if obj.respond_to? :downcase
obj
end
if property.nil?
ary.sort {|a,b| insensitive.call(a) <=> insensitive.call(b) }
elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
ary.sort {|a,b| insensitive.call(a[property]) <=> insensitive.call(b[property]) }
elsif ary.first.respond_to?(property)
ary.sort {|a,b| insensitive.call(a.send(property)) <=> insensitive.call(b.send(property)) }
end
end
# Remove duplicate elements from an array
# provide optional property with which to determine uniqueness
def uniq(input, property = nil)
+36
View File
@@ -74,11 +74,38 @@ class FiltersTest < Minitest::Test
@context['numbers'] = [2,1,4,3]
@context['words'] = ['expected', 'as', 'alphabetic']
@context['arrays'] = ['flower', 'are']
@context['case_sensitive'] = ['sensitive', 'Expected', 'case']
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', 'flower'], Variable.new("arrays | sort").render(@context)
assert_equal ['Expected', 'case', 'sensitive'], Variable.new("case_sensitive | sort").render(@context)
end
def test_sort_natural
@context['value'] = 3
@context['numbers'] = [2,1,4,3]
@context['words'] = ['case', 'Assert', 'Insensitive']
# This specific syntax forces hashes to have string keys. Colons won't work.
@context['hashes'] = [{ 'a' => 'A'}, { 'a' => 'b'}, { 'a' => 'C' }]
@context['objects'] = [TestObject.new('A'), TestObject.new('b'), TestObject.new('C')]
assert_equal [1,2,3,4], Variable.new("numbers | sort_natural").render(@context)
assert_equal ['Assert', 'case', 'Insensitive'], Variable.new("words | sort_natural").render(@context)
assert_equal [3], Variable.new("value | sort_natural").render(@context)
# Test hashes
sorted = Variable.new("hashes | sort_natural: 'a'").render(@context)
assert_equal sorted[0]['a'], 'A'
assert_equal sorted[1]['a'], 'b'
assert_equal sorted[2]['a'], 'C'
# Test objects
sorted = Variable.new("objects | sort_natural: 'a'").render(@context)
assert_equal sorted[0].a, 'A'
assert_equal sorted[1].a, 'b'
assert_equal sorted[2].a, 'C'
end
def test_strip_html
@@ -136,3 +163,12 @@ class FiltersInTemplate < Minitest::Test
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render!(nil, [CanadianMoneyFilter])
end
end # FiltersTest
# Simple object that may be passed into a filter.
# Note to test subjects: do not smuggle test objects out of the testing area.
class TestObject
attr_accessor :a
def initialize(a)
@a = a
end
end