Reputation: 824
I'm making a glossary template for a Jekyll site deployed on Github Pages.
Entries are pulled from a _data/glossary.yml
file.
I want the template to arrange the entries alphabetically regardless of the order of the data in glossary.yml
.
Using {% assign glossary = site.data.glossary | sort 'term' %}
does return an alphabetically sorted object that I can iterate over with a for
loop.
However the sort
filter is case sensitive - lowercase entries are sorted after all of the capitalized or uppercase terms.
Liquid 4.0.0 adds a sort_natural
filter that does what I want, but Github Pages currently runs 3.0.6, so I need a workaround.
My question is how can I:
capitalize
string filter to get rid of the uppercase/lowercase discrepancies) For example, given the following data/glossary.yml
:
- term: apricot
loc: plastic
- term: Apple
loc: basket
- term: Banana
loc: basket
- term: bowtie
loc: closet
- term: Cat
loc: outside
How do I create a local Liquid object variable that sorts and displays the following?:
Upvotes: 3
Views: 930
Reputation: 52809
The only way is to use a filter plugin that will implement liquid 4 natural_sort.
Some cut and past later you have _plugins/natural_sort_filter.rb :
module Jekyll
module SortNatural
# 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)
if property.nil?
ary.sort { |a, b| a.casecmp(b) }
elsif ary.empty? # The next two cases assume a non-empty array.
[]
elsif ary.first.respond_to?(:[]) && !ary.first[property].nil?
ary.sort { |a, b| a[property].casecmp(b[property]) }
end
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 concat(args)
to_a.concat(args)
end
def reverse
reverse_each.to_a
end
def uniq(&block)
to_a.uniq(&block)
end
def compact
to_a.compact
end
def empty?
@input.each { return false }
true
end
def each
@input.each do |e|
yield(e.respond_to?(:to_liquid) ? e.to_liquid : e)
end
end
end
end
end
Liquid::Template.register_filter(Jekyll::SortNatural)
This new filter can be used like this :
{% assign glossary = site.data.glossary | sort_natural: 'term' %}
<ul>
{% for item in glossary %}
<li>{{ item.term }} - {{ item.loc }}</li>
{% endfor %}
</ul>
Upvotes: 3