sort and sort_natural in Jekyll Liquid seem to produce different results

65 Views Asked by At

I’ve been struggling with sorting categories in Jekyll case-insensitively. Writing the following Liquid template works well, except it’s not sorted case-insensitively:

As near as I can tell, sort and sort_natural have identical implementations, except for the compare (listings below).

{% assign categories = site.categories | sort %}
{% for cat in categories %}
    {{ cat | first }} /
{% endfor %}

This gives output like this (notice how the last two start with a lower-case letter and aren’t naturally sorted):

Apple / Aviation / Vapor / macOS / visionOS

site.categories is a hash with the name of the category as the key, and an array of document objects as the value:

{"Misc"=>[#<Jekyll::Document _posts/2015-02-17-burningman-solar-power.html collection=posts>, …], …}

Passing that to sort gives an array of arrays, where the inner array has two items: the name of the category, and the array of documents. This is the structure I want:

{{ site.categories | sort | inspect }}

[["Apple", [#<Jekyll::Document _posts/2024-02-09-AVP-Blender-Workflow.md collection=posts>, …]], …]

sort_natural doesn’t process the hash the same way:

{{ site.categories | sort_natural | inspect }}

[{"Misc"=>[#<Jekyll::Document _posts/2015-02-17-burningman-solar-power.html collection=posts>, …], …}]

Basically packaging up the hash into an array of one element.

sort and sort_natural are implemented like this. As far as I can see, they are identical except for the comparison function.

    # Sort elements of the array
    # provide optional property with which to sort an array of hashes or drops
    def sort(input, property = nil)
      ary = InputIterator.new(input)

      return [] if ary.empty?

      if property.nil?
        ary.sort do |a, b|
          nil_safe_compare(a, b)
        end
      elsif ary.all? { |el| el.respond_to?(:[]) }
        begin
          ary.sort { |a, b| nil_safe_compare(a[property], b[property]) }
        rescue TypeError
          raise_property_error(property)
        end
      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)

      return [] if ary.empty?

      if property.nil?
        ary.sort do |a, b|
          nil_safe_casecmp(a, b)
        end
      elsif ary.all? { |el| el.respond_to?(:[]) }
        begin
          ary.sort { |a, b| nil_safe_casecmp(a[property], b[property]) }
        rescue TypeError
          raise_property_error(property)
        end
      end
    end

I’m a fairly expert developer, but have very little experience with Ruby (or Liquid).

Why do these two Liquid template tags behave differently?

0

There are 0 best solutions below