使用 Liquid 获取、操作和排序哈希对象值

Fetch, manipulate and sort hash object values with Liquid

我正在为部署在 Github 页面上的 Jekyll 站点制作词汇表模板。
条目来自 _data/glossary.yml 文件。
我希望模板按字母顺序排列条目,而不考虑 glossary.yml.

中数据的顺序

使用 {% assign glossary = site.data.glossary | sort 'term' %} 可以 return 一个按字母顺序排序的对象,我可以用 for 循环对其进行迭代。
但是 sort 过滤器区分大小写 - 小写条目排在所有大写或大写术语之后。

Liquid 4.0.0 添加了一个 sort_natural 过滤器来满足我的要求,但是 Github Pages 目前运行的是 3.0.6,所以我需要一个解决方法。

我的问题是我怎样才能:

  1. 在 Liquid 模板中获取 site.data.glossary?
  2. 操作每个条目的第一个映射的字符串值?
    • (即使用 capitalize 字符串过滤器消除 uppercase/lowercase 差异)
  3. 使用本地字符串过滤值对整个地图进行排序?
  4. 奖励:如果我仍然可以使用保留原始大小写的源字符串值,以便在生成的 html 中进行最终显示。

例如,给定以下 data/glossary.yml

- term: apricot
  loc: plastic

- term: Apple
  loc: basket

- term: Banana
  loc: basket

- term: bowtie
  loc: closet

- term: Cat
  loc: outside

如何创建一个本地 Liquid 对象变量来排序和显示以下内容?:

唯一的方法是使用将实现 liquid 4 的过滤器插件natural_sort

一些剪切和过去之后你有 _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)

这个新过滤器可以这样使用:

{% assign glossary = site.data.glossary | sort_natural: 'term' %}
<ul>
{% for item in glossary %}
  <li>{{ item.term }} - {{ item.loc }}</li>
{% endfor %}
</ul>