jekyll 是一个简单的静态博客生成器,通过 Liquid 处理模版文件,将 Markdown 文件转换成网页。通过 Liquid 提供的语法,可以实现相对简单的功能实现。
Liquid
首先介绍一下 Liquid ,Liquid 是一门开源的模板语言,由 Shopify 创造并用 Ruby 实现。
虽然 Liquid 提供了许多内置语法,但还是无法满足实际的使用需求,在近半个月的使用中,Liquid 对常见的数组存储修改操作的缺失几乎让我抓狂。不过好在对于字符串和列表的简单操作是可行的,只需要把它们组合使用同样能达到想要的效果,这里记录下我仅使用字符串对数组存储操作的完整实现。
聊胜于无,先来看看 Liquid 提供的最基础的数组迭代操作。
Liquid 语法下的数组存储
Liquid 语法中通过 for 语句迭代出来的 Markdown 文本基本会存储在两三层的数组中,要取出所有数据必须逐层迭代取出数据。
{% for posts in site.posts %}
{% for post in posts %}
{{ post.title }}
{% endfor %}
{% endfor %}
如果单独取出多纬数组中的数组变量,可以使用 map 过滤语句。
{% assign categories = site.pages | map: "category" %}
有一点需要知道的是,Liquid 提供了使用|
过滤器的方式对变量进行操作类似 first,last, uniq等方式对字符串过滤,且筛选的语句可以多次使用。
只要对迭代中的处理的数据进行修改,数组的其他操作是完全可能的。
数组元素增加
Liquid 无法直接操作数组,但是对字符串提供了很多可选的过滤操作,将数组直接转换为字符串操作,最后再转换回数组既可。
将数组转换字符串使用 array_to_sentence_string 语句过滤,同时使用 prepend 过滤语法的拼接为新的字符串
{{ assign str = page.categories | reverse | array_to_sentence_string }}
=> python,jekyl,liquid,...
{% assign new_str = str | prepend: "," | prepend: str %}
{% assign list_new_str = new_str | split: "," | reverse %}
#{% assign list_new_str = str | prepend: "," | prepend: str | split: "," | reverse %}
数组的修改
对于数组的修改,将数组转换为字符串后使用 replace 过滤语句替换,再使用 split 过滤语句转换为数组既可。
{% assign str_list = "python, java, str" | split: ", " | array_to_sentence_string %}
{% assign list_new = str_list | replace:"java", "ruby" | split: "," %}
数组元素删除
数组的删除,同理转换为字符串操作 首尾的字符使用 slice 过滤语句进行反向切割,记得加上逗号计数 位于中间的字符,使用 replace 过滤语句进行替换
{% assign str_list = "python, java, str" | split: ", " | array_to_sentence_string %}
#字符在开头
{% assign list_new = str_list | slice: 6, str_list.size %}
#字符在中间
{% assign list_new = str_list | replace:"java", str_list.first | split: "," | uniq %}
#字符在末尾
{% assign str_size = str_list.size | minus: 4 %}
{% assign list_new = str_list | slice: 0, str_list.size %}
数组合并
合并两个原有的数组,使用 concat 过滤语句,如果针对字符串和数组的拼接,请先使用 split 过滤语句转为数组
{% assign old = "python, java" | split: ", " %}
{% assign new = "jekyll,liquid" | split: ", " %}
{% assign all = new | concat: old %}
注 concat 语句的对象必须是数组,如果是单个字符串,可以拼接自身作为假数组,再分割得到一个为数组,合并数组后使用 uniq 过滤语句去除假数据,例如
{% assign list = "jekyll" | split: ", " %}
{% assign str = "liquid" %}
{% assign list_fake_str = str | prepend: "," | prepend: str | split: ", " %} # => [liquid, liquid]
{% assign last_list = list | concat: list_fake_str | uniq %} # => [jekyll, liquid]
数组储存 for 循环中的值
在数组 for 循环迭代加入为字符串,同时加入特定符号,这里使用逗号间隔字符,split 进行分割,最后形成反序成新的数组。
下面以取出所有 Markdown 中去重后得到唯一年份为示例:
{% assign dateList = site.posts | group_by_exp:"post", "post.date" %}
{% for date in dateList %}
{% assign year = date.name | date: "%Y" %}
{% assign yearList = yearList | prepend:year | prepend:"," %}
{% endfor %}
{% assign years = yearList | remove_first: "," | split:"," | uniq | reverse %}
取出的数组是反序的,根据需求,使用reverse进行反序。
最后对取出的数组迭代,使用语法 {{ }}
取出既可。
探讨
习惯了语言原生 API 支持现在,已经很少有机会去思考实现的方法了。大多时候情况下,我们对这些方法只是拿来即用,探索底层功能的实现方式这对我们来说确实太过复杂了,但是需要去实现特定功能的时候应该学会发散思维,原有的方法不一定是最优解。