Jekyll 3.4.0 版本解析:`group_by_exp` 分组过滤器与 Windows 时区管理的实战指南
2026/9/19 22:56:39 网站建设 项目流程

Jekyll 3.4.0 版本解析:group_by_exp分组过滤器与 Windows 时区管理的实战指南

【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyll

Jekyll 3.4.0 是 2017 年 1 月发布的一个以修复为主、同时带来三项关键变化的版本:新增按表达式分组的内置 Liquid 过滤器group_by_exp、在 Windows 平台上实现对 IANA 时区代码的准确支持,以及一批主题、includes、permalinks 相关文档的改进。本文以官方发布公告为骨架,结合当前仓库中的过滤器实现、配置解析与测试用例源码,完整讲解这两项核心能力的用法、底层原理与注意事项,帮助你升级到 3.4.0 后立刻上手。

一、版本定位:一次小而精的更新

Jekyll 3.4.0(发布公告见 docs/_posts/2017-01-18-jekyll-3-4-0-released.markdown)延续了 3.x 系列「bug fixes + 增量特性」的节奏。公告将本次更新概括为三点:

  1. 新增group_by_exp过滤器,与已有的where_by_exp形成「筛选 / 分组」两套表达式驱动的组合拳;
  2. Windows 用户可以使用 IANA 时区代码(如Asia/Shanghai)在_config.yml中准确设置timezone
  3. 官方文档围绕 themes、includes、permalinks 进行了改进,并同步补充了历史变更记录。

其余大量工作是社区贡献的常规 bug 修复。升级方式与平常一致:gem update jekyll或修改Gemfile中的版本约束后bundle update jekyll

二、核心新特性:group_by_exp表达式分组过滤器

1. 与group_by/where_by_exp的关系

在 Jekyll 中,group_by过滤器负责「按某个属性值分组」,而where_by_exp负责「按表达式筛选」。3.4.0 新增的group_by_exp则是「按 Liquid 表达式的结果分组」,它把group_by的分组能力和where_by_exp的表达式灵活性结合到了一起。

三者的分工可以这样理解:

过滤器能力典型场景
where/where_exp按属性或表达式筛选数组,返回子集只保留某类文章
group_by按属性值分组按标签、年份归类
group_by_exp(3.4.0 新增)按表达式计算结果分组按年份截断后的值、大写后的值等派生值归类

2. 基本用法与官方示例

group_by_exp的签名是三个参数:输入数组、循环变量名、表达式字符串。

{{ site.members | group_by_exp: "item", "item.graduation_year | truncate: 3, ''" }}

这段示例来自官方过滤器文档数据 docs/_data/jekyll_filters.yml:对site.members中每个成员的graduation_year先做truncate: 3, ''(截取前 3 位且不追加省略号),再按截取结果分组,例如把20132014归入"201",把2009归入"200"。输出是形如{"name"=>"201", "items"=>[...]}的分组数组,每组都带有nameitemssize三个键。

对照源码 lib/jekyll/filters/grouping_filters.rb 可以看到实现逻辑:

def group_by_exp(input, variable, expression) return input unless groupable?(input) parsed_expr = parse_expression(expression) @context.stack do groups = input.group_by do |item| @context[variable] = item parsed_expr.render(@context) end grouped_array(groups) end end

关键点在于:

  • 表达式是运行时解析的parse_expression把传入的字符串封装成Liquid::Variable,在遍历每个元素时把元素赋给循环变量并渲染表达式,因此表达式可以任意复杂——调用过滤器、拼接字符串、比较日期都行;
  • 支持任意可枚举对象groupable?只要求输入响应group_by,数组、Hash 均可;
  • 分组结果统一结构grouped_array将 Ruby 的Hash#group_by结果转换为{"name" => ..., "items" => [...], "size" => ...}的数组,方便模板中直接用group.namegroup.itemsgroup.size渲染。

3. 对比group_by的异同

group_by(input, property)的实现(lib/jekyll/filters/grouping_filters.rb)等价于把表达式固定为「读取某个属性」。测试用例 test/test_filters.rb 专门验证了这一点:

should "be equivalent of group_by" do actual = @filter.group_by_exp(@filter.site.pages, "page", "page.layout") expected = @filter.group_by(@filter.site.pages, "layout") assert_equal expected, actual end

也就是说,group_by_exp: "item", "item.layout"group_by: "layout"结果完全一致,前者只是更通用的超集。

4. 更多实战示例

按表达式派生值分组(例如按版本号主版本归类):

{% assign groups = site.data.versions | group_by_exp: "item", "item.version | split: '.' | first" %}

该用法在 test/test_filters.rb 中有对应的测试数据与断言。

直接按整个元素分组(表达式为变量本身):

{{ "a,b,c,d" | split: "," | group_by_exp: "item", "item" }}

测试 test/test_filters.rb 验证了这种写法按元素本身分组,每个元素自成一组。

配合数组与 Hash 输入均可工作;对非数组输入(如字符串)则原样返回,测试 test/test_filters.rb 确认了这一兜底行为。

5. 与where_by_exp的组合应用

where_by_exp负责按表达式筛选,group_by_exp负责按表达式分组,二者可串联使用。例如先筛选出未归档的文章,再按「文章标题首字母大写后的年份」分组:

{% assign active = site.posts | where_exp: "post", "post.published == true" %} {% assign groups = active | group_by_exp: "post", "post.title | truncate: 4, ''" %}

在 3.4.0 时代,where_exp的表达式支持已相当完整,后续版本(4.0)进一步加入了and/or二元运算符支持(见 docs/_docs/liquid/filters.md),但分组能力从 3.4.0 起就已具备group_by_exp这一通用形态。

三、Windows 时区管理:IANA 时区代码的准确支持

1. 背景:Windows 上时区为何一直是痛点

Windows 没有原生 zoneinfo 数据,Ruby 解释器无法理解 IANA 时区名(如Asia/Shanghai)。此前在 Windows 上使用自定义时区,TZ环境变量会退化为 UTC/GMT 00:00;虽然也可以用 POSIX 格式(如EST+5)手动定义,但处理夏令时(DST)规则变化时既不直观也不可靠。

3.4.0 的解决方案是:借助tzinfogem 按 IANA 时区数据库计算偏移量,并在内部换算成 Windows 可识别的 POSIX 风格定义。

2. 配置方式

_config.yml中照常设置timezone(该键的默认值为nil,表示使用本地时区,见 lib/jekyll/configuration.rb):

timezone: Asia/Shanghai

Windows 用户需要确保Gemfile中包含tzinfotzinfo-data。3.4.0 起新建的站点会在Gemfile中默认写入以下内容(见 docs/_docs/installation/windows.md),老站点需要手动补充:

# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem # and associated library. platforms :mingw, :x64_mingw, :mswin, :jruby do gem "tzinfo", ">= 1", "< 3" gem "tzinfo-data" end

注意:platforms声明只在 Windows(及 JRuby)环境下才安装这些 gem,不影响 Linux/macOS 的依赖树。

3. 底层实现原理

核心逻辑位于 lib/jekyll/utils/win_tz.rb 的WinTZ.calculate方法:

def calculate(timezone, now = Time.now) External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo) tz = TZInfo::Timezone.get(timezone) offset = tz.period_for_utc(now.getutc).utc_total_offset # POSIX style definition reverses the offset sign. sign = offset.positive? ? "-" : "+" ... "WTZ#{sign}#{time}" end

关键步骤:

  • 通过TZInfo::Timezone.get(timezone)加载 IANA 时区定义;
  • period_for_utcutc_total_offset获取当前时刻相对 UTC 的总偏移(含 DST 调整),注意源码注释说明这是为了兼容 tzinfo v1;
  • POSIX 时区符号约定与直觉相反:西半球时区(如美国东部 EST,UTC-5)表示为EST+5,因此代码在偏移为正时输出-、偏移为负时输出+
  • 支持非整小时偏移,例如Australia/Eucla(UTC+8:45)换算为WTZ-08:45
  • 返回的WTZ...字符串最终用于重新定义ENV["TZ"],使 Jekyll 在 Windows 上按真实时区处理文章日期。

测试 test/test_win_tz.rb 系统验证了这一点:

IANA 时区冬季(1 月)夏季(7 月)
America/New_YorkWTZ+05:00WTZ+04:00(DST 生效)
Europe/ParisWTZ-01:00WTZ-02:00(DST 生效)
Australia/EuclaWTZ-08:45
UTCWTZ+00:00

可以看到 DST 被正确计入:纽约冬季 UTC-5、夏季 UTC-4;巴黎冬季 UTC+1、夏季 UTC+2。

4. 适用前提与限制

  • 该能力面向Windows 与 JRuby 平台;Linux/macOS 自带 zoneinfo,无需此机制;
  • 必须安装tzinfo(且tzinfo-data提供时区数据库),否则会通过require_with_graceful_fail优雅降级并给出提示;
  • timezone配置值必须是 IANA 数据库中的合法代码(如Asia/ShanghaiAmerica/New_York)。

四、3.4.0 配套文档更新与升级建议

公告同时提到文档在 themes、includes、permalinks 方面得到改进。本仓库的对应文档包括:

  • 过滤器参考:docs/_docs/liquid/filters.md(group_by_exp从 3.4.0 起在 docs/_data/jekyll_filters.yml 中带版本徽标展示);
  • Windows 安装与时区管理:docs/_docs/installation/windows.md;
  • 完整变更历史可查阅仓库 History.markdown 中 v3.4.0 一节。

升级到 3.4.0 的建议顺序:

  1. 更新Gemfile版本约束并执行bundle update jekyll
  2. Windows 用户检查并补齐tzinfo/tzinfo-data依赖;
  3. _config.yml中确认timezone使用 IANA 代码;
  4. 将手写循环分组的模板改为group_by_exp,简化维护。

五、小结

Jekyll 3.4.0 用两个精准的特性解决了实际问题:group_by_exp让模板作者可以用任意 Liquid 表达式分组数据(源码 lib/jekyll/filters/grouping_filters.rb 与测试 test/test_filters.rb 提供了完整的实现与验证),而 Windows 时区支持让跨平台站点的日期显示不再漂移(源码 lib/jekyll/utils/win_tz.rb 与测试 test/test_win_tz.rb 覆盖了含 DST 与奇数偏移量的全部情形)。对升级用户而言,这两项能力立即可用,也是 3.x 系列在模板表达能力与平台健壮性上继续演进的重要一步。

【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyll

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询