【问题标题】:Fetch, manipulate and sort hash object values with Liquid使用 Liquid 获取、操作和排序哈希对象值
【发布时间】:2016-11-12 07:30:45
【问题描述】:

我正在为部署在 Github 页面上的 Jekyll 网站制作词汇表模板。
条目是从 _data/glossary.yml 文件中提取的。
我希望模板按字母顺序排列条目,而不管glossary.yml 中的数据顺序如何。

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

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

我的问题是我该怎么做:

  1. 在 Liquid 模板中获取 site.data.glossary?
  2. 操作每个条目的第一个映射的字符串值?
    • (即使用capitalize 字符串过滤器消除大小写差异)
  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 对象变量?:

  • 苹果
    • 篮子
    • 塑料
  • 香蕉
    • 篮子
  • 领结
    • 壁橱
    • 外面

【问题讨论】:

    标签: ruby jekyll liquid


    【解决方案1】:

    唯一的方法是使用一个过滤器插件来实现液体 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>
    

    【讨论】:

    • 欣赏答案,但自定义插件不适用于我的用例(在 Github 页面上部署和生成)。
    • 我敢肯定你不能用液体做这个。您将不得不等待液体 4 ;-)
    猜你喜欢
    • 2014-10-28
    • 2012-08-17
    • 2010-10-20
    • 1970-01-01
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 2012-05-01
    相关资源
    最近更新 更多