Ruby 混淆艺术巅峰:TRICK 2018 获奖作品源码解析
【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby
TRICK(Transcendental Ruby Imbroglio Contest)是 rubyKaigi 举办的 Ruby 混淆代码大赛,本文基于 sample/trick2018 目录,逐项解析第三届(TRICK 2018)五项获奖作品的运行方式、实现原理与代码技巧。通过阅读本文,你将了解 Ruby 保留字如何被"合法滥用"、quine 如何与动画结合、源码如何自我转化为 PNG 查看器与 3D 建模器,从而深入理解 Ruby 语法解析器与对象模型的边界能力。
⚠️ 警告:本目录中所有作品均为反面教材(BAD EXAMPLES),README 明确声明"绝不能将其当作示例代码使用"。它们展示的是语言边界的极限探索,而非工程实践范式。
目录结构与参赛规则
sample/trick2018/README.md 记录了全部五个获奖条目,每个条目包含三个文件:entry.rb(参赛源码)、remarks.markdown(作者的思路与使用说明)、authors.markdown(作者信息)。获奖名单如下:
| 目录 | 奖项 | 主题 |
|---|---|---|
| 01-kinaba/entry.rb | 金奖(Gold) | Most reserved(保留字最多) |
| 02-mame/entry.rb | 银奖(Silver) | Best spiral(最佳螺旋) |
| 03-tompng/entry.rb | 铜奖(Bronze) | Best png viewer(最佳 PNG 查看器) |
| 04-colin/entry.rb | 4 等奖 | Best one-liner(最佳单行程序) |
| 05-tompng/entry.rb | 5 等奖 | Most three-dimensional(最具三维感) |
所有条目均以 MIT 许可证发布。值得注意的细节是,README 特别强调这些文件"是坏例子,绝不能用作示例代码"——它们的存在价值在于展示 Ruby 语法与语义的边界,而非作为编码规范参考。
金奖 01-kinaba:由纯保留字构成的合法程序
运行与验证
01-kinaba/remarks.markdown 说明该程序无需任何参数直接运行:
ruby entry.rb它本质上是一个"无操作(no-op)"程序,上述命令的唯一作用是验证entry.rb是一个语法合法的 Ruby 程序。作者在 ruby 2.5.0p0(x64-mingw32)上完成验证。
程序源码
查看 01-kinaba/entry.rb,源码全文共 8 行,看起来只是一堆词语的排列:
alias BEGIN for unless def class super true or return defined? next break while begin undef do end rescue then retry else undef module nil ensure case if yield __LINE__ self and redo elsif not __FILE__ alias END in end when __ENCODING__ end until false end核心技巧
作者指出,这个程序由Ruby 保留字(reserved words)组成且用尽了全部保留字,同时保证编译无错、无警告、无运行时错误。其实现难点与技巧在于:
- 结构型保留字无法独立使用:
retry必须位于rescue块内,break/next/redo必须位于循环结构内;跳转类语句还不能出现在要求返回值的位置——if return then true end会触发 "void value expression" 语法错误。 def/alias/undef可以接受保留字作为参数:即def class ... end会定义一个名为class的方法。这一特性至关重要,否则BEGIN等关键字必然引入{}之类的非保留字 token。defined?也能接受部分保留字:作者坦言"直到写这个程序时才知道"。- 用
or/and规避 void value expression:if begin return end then true end是语法错误,但if begin false or return end then true end合法。 - 每 6 个词换行是为了与官方规格文档(lexical 章节的 reserved words 表格)排版对齐,而 Ruby 对换行敏感,这本身就是额外的挑战。
局限
作者诚实指出这并非"完美的全字母短句(pangram)":alias与undef各用了两次,end使用了 4 次。正是这种坦诚记录"未完成目标"的态度,使作品的技术叙述更具参考价值。
银奖 02-mame:带动画的螺旋 quine
运行与验证
02-mame/remarks.markdown 给出了两层用法:
ruby entry.rb # 运行,输出动画 ruby entry.rb > output # 输出重定向后仍是可执行程序 ruby output # 再次运行,程序文本已按螺旋顺序重排双模式设计
这是一个带动画的 quine(自复制程序)。作者特别声明"我们没有作弊":程序只使用转义序列来移动光标,不使用属性变更或覆盖写入来隐藏任何代码。
从 02-mame/entry.rb 的源码可以看到精巧的架构:程序被设计成两种形态都能运行——既可作为普通程序文本执行,也可在按螺旋顺序重排后执行。源码中如r<<r[i+=(1.-n&2)*(32-n%2*31)]这样的螺旋索引计算、?与?\0之类的字符常量、以及%q字符串字面量的嵌套使用,共同实现了"代码的一部分实际是重叠的"这一效果。eval与字符串插值#{}的组合是 quine 类程序的标准骨架,而螺旋重排的加入则让它在 TRICK 中脱颖而出。
铜奖 03-tompng:自身即是输出的 PNG 查看器
运行与验证
03-tompng/remarks.markdown 说明该程序依赖chunky_pnggem,需先安装依赖:
bundle install bundle exec ruby entry.rb trick.png bundle exec ruby entry.rb [other png file]作者在 ruby 2.5.0p0 与 2.4.0p0(x86_64-darwin16)上验证通过。目录中提供了 Gemfile 与 Gemfile.lock 锁定依赖版本。
双重身份的实现
这个程序是一个 PNG 图片查看器:输出是对给定 PNG 文件的 asciiart 呈现,而且这段输出本身就是 PNG 查看器的源码。也就是说,运行它一次,你得到的是"打印出来的自己"。
从 03-tompng/entry.rb 的源码结构可以清晰看出这一机制:
- 第一行的
X=[]; class String def -@ ... def -a ...利用一元与二元运算符重载收集字符数据; def method_missing n; (X<<n.to_s)[-1] end让所有未定义的方法调用都变成"数据累积";- 结尾的
at_exit{ eval C=(Zlib.inflate(...)) }在程序退出时执行:把收集到的字母序列用tr(?-,'')去掉连字符、tr('q-z','0-9')映射为数字、to_i(26)以 26 进制转整数、digits(0x100)转回字节序列,最后pack'C*'并Zlib.inflate解压得到真实程序。
运行示例输入图片为 03-tompng/trick.png,程序输出的 asciiart 同时携带了"可执行"属性——这是"输出即可运行"类作品中的又一代表。
4 等奖 04-colin:68 字符的微型测试框架
运行与验证
04-colin/remarks.markdown 说明了用法:创建一个 Ruby 测试文件,require该 entry,然后直接运行:
ruby name_of_test_file.rb68 字符的完整实现
04-colin/entry.rb 全文只有一行、68 个字符,却实现了带缩进层级、分组、断言与失败标记的完整测试 DSL:
# Copyright 2018. Available for use under the terms of the MIT License. $🚀=0;def 🤔 🏷,🤔=0,&b;puts ' '*$🚀+(🤔 ?"":"🚫 ")+🏷;$🚀+=4;b&.[];$🚀-=4;end设计解读
作者的目标是:"测试文件看起来美观、输出看起来美观,且字符数尽可能少,最终用 68 字符 + 一个方法处理一切。"
- emoji 方法名与变量名:
🤔是唯一的方法名("think" 的表情符号),🚀是缩进计数器,🚫是失败前缀——Ruby 允许 UTF-8 标识符在此成为核心武器; - 参数省略技巧:
def 🤔 🏷, 🤔=0, &b中,第二个参数故意与全局变量同名($🚀之外的新局部🤔),省略实参时默认为 0(假值)表示"这是条断言而非分组"; b&.[]:Safe navigation 运算符调用 block 的[]方法执行分组内测试,仅在 block 存在时生效;- 缩进管理:
$🚀+=4/$🚀-=4在进入与离开分组时增减,' '*$🚀生成前缀空格。
使用示例
require './entry' 🤔 "Math" do 🤔 "Addition" do 🤔 "One plus one equals two.", 1+1 == 2 🤔 "One plus one equals eleven. (This should fail.)", 1+1 == 11 end 🤔 "Subtraction" do 🤔 "One minus one equals zero.", 1-1 == 0 🤔 "Ten minus one equal nine.", 10-1 == 9 end end断言为真则测试通过,为假则测试失败(输出带 🚫 前缀)。作者在 ruby 2.5.1p57 与 2.3.0p0 上验证通过,并指出若将b&.[]替换为b&&b[]还可兼容 ruby 2.0.0——代价是长度增加 1 字符,这正体现了"最小化"竞赛的权衡思维。
局限
终端必须支持 Unicode 字符,测试输出才能正确显示;若终端不支持,可将🚫替换为任意字符作为失败前缀。
5 等奖 05-tompng:用文本 DSL 生成 3D 酒杯模型
运行与验证
05-tompng/remarks.markdown 说明同样直接运行:
ruby entry.rb程序会生成wine_glass.stl——一份 STL 格式的 3D 酒杯数据文件。作者在 ruby 2.5.0p0、2.4.0p0、2.3.1p112(x86_64-darwin16)上验证通过。
文本即模型的 DSL
从 05-tompng/entry.rb 的源码可以看到,程序主体是一个用字符画定义三维形状的 DSL:
gen3d 'ochoko.stl' do l------------------------l l-ww------------------ww-l l-ww------------------ww-l l-ww++++++++++++++++++ww-l l-ww++++++++++++++++++ww-l l--ww++++++++++++++++ww--l l---wwww++++++++++wwww---l l----wwwwwwwwwwwwwwww----l l----www----------www----l end其中w字符代表"存在几何体"的体素,-、+、|仅用于外观美化(+与-语义相同),可以通过修改这段 DSL 改变生成形状(如将酒杯改为 sake 杯)。
底层几何原理
源码中的method_missing与运算符重载把l行对象和字符序列拼接成体素矩阵;gen3d遍历体素矩阵,对每个边界体素调用a=->r,z,dr,dz{...}描述的匿名递归函数,将二维轮廓绕轴旋转:
16.times{|i| ... t=i*p ...}以 16 段绕轴采样,p=Math::PI/8即 22.5° 步长;- 每段用三角函数
m.cos(t)/m.sin(t)计算圆周上相邻两点,组合出两个三角形面片([[0,1,2],[0,2,3]]两组顶点索引); - 最后按 STL 格式拼装
facet normal/outer loop/vertex/endloop/endfacet结构,File.write输出文件,b=['solid obj']开头、'end'+b[0]收尾。
程序输出的 3D 模型预览见 05-tompng/preview_of_output.png。从源码结构看,其核心是把"文本字符画"这一最直观的 DSL 与"旋转体三角网格化"这一最基础的 3D 几何算法无缝结合——无需任何 3D 库,纯 Ruby 标准库即可产出可被 3D 打印/切片软件读取的 STL 文件。
从获奖作品看 Ruby 语言边界
综合五项作品,可以归纳出 TRICK 2018 所展示的 Ruby 能力边界:
- 语法层面:
def/alias/undef接受保留字(01-kinaba)、or/and规避 void value expression(01-kinaba)、Unicode 标识符(04-colin)、运算符重载(03/05); - 语义层面:
method_missing驱动的 DSL(03、05)、at_exit钩子延迟执行(03)、Safe navigation&.(04)、quine 与字符串自求值(02、03); - 运行时层面:面向对象模型下"一切皆可重载"的设计,使字符画、测试 DSL、3D 模型都能以 Ruby 语法直接表达。
正如 README 反复强调的,这些作品是"坏例子"——但它们精确地测绘了 Ruby 这门语言"能够做到什么"的边界,对理解 Ruby 解析器、对象模型与求值模型具有独特的教学价值。若希望深入学习,可继续阅读各条目的 authors.markdown 与 remarks.markdown 了解作者的设计决策与验证环境。
【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考