代码:
嗨,大家好,我一直在尽自己的绵薄之力为社区搬砖,这一次我来说说我熟悉的 Windows 上的 Ruby,以及我带给大家的 rbenv for Windows.
我最开始学习 Ruby 的时候,就是在 Windows 上,然而很多人说在 Windows 上使用 Ruby 就是浪费时间。其实到我学的那段时间,这种情形已经不那么明显了。因为 社区在发展,用爱发电的人们在前进。人们并没有因为困难,就直接放弃对 Windows 平台的支持,而是一朝一夕的不断改进。
RubyInstaller 从 2009 年开始开发,到 2017 年左右切换到 RubyInstaller2 (下文我们直接称 RubyInstaller 来指代 RubyInstaller2). 后者以 @larskanis 为主要开发人员,成为了 Windows 上安装 Ruby 的事实标准。该项目 5 年多几乎只有他一人在做实际的维护工作,仅有少数的爱好者在一起帮忙解决问题。我对这位来自德国的工程师,Ruby 爱好者,感到敬佩。除了琐碎的用户不清楚的内部维护细节之外,最明显的一个改进是:
曾经我们在 Windows 上安装 Rails 的时候,很容易就卡在 gem install sqlite3,然而这个还不是令人无语的网络问题,而是一个编译选项问题。当时的网上的帖子都不管用,对于刚学习 Ruby 的人更是一头雾水。我当时花了好几天才找到解决方案,心里也默默的来了句 "真是浪费时间。。。" . 然而你现在再使用 RubyInstaller,你会发现这一步已经被自动化解决了,即 SQLite3 其实会被 pacman (对,这个就是 Arch Linux 社区中最骄傲的软件 — 包管理工具) 自动安装,这在 macOS 和 Linux 上的同学都没有这样的特殊待遇。
国内现在安装 Ruby 就只有一个问题,那就是网络。不过,在 2021 年 2 月,我们在上海交通大学镜像站的帮助下创建了 https://rubyinstaller.cn/ (代码在Gitee 这) ,这个迟来的站点也许已经服务了不少新手老手了吧。
作为 Ruby 爱好者,你的电脑上一定少不了 rbenv 或 rvm,以供你在不同 Ruby 版本中做各种有趣的语言功能实验。然而 rbenv 的安装也会让人遇到烦人的网络问题,对此,我又创建了 rbenv-cn 来完全的解决它(感谢 uzxmx 对 ruby-build 的补丁,不知道您是否在社区里),而不是部分解决它(有些前辈把解决方案代码放在 Github 上,却不在意用户是否能拉下来 Github 的代码)
由于与 rbenv 的不解之缘,我了解了一部分 rbenv 的工作原理,不过也就是知道个大概,噢,用 Bash 实现的代码,真的有人在它能正常工作的时候费心思去阅读它吗?
在 Linux 上待久了,回到 Windows 上工作,觉得最缺的就是它了,于是我想尝试在 Windows 上使用它。我尝试直接在 MSYS2 中使用 rbenv,经过一番小小的修改,很可惜还是工作不了。然后我突然发现,RubyInstaller 自带的工具 ridk 其实已经实现了 ridk use 来管理多版本。嗯,不错,不过它是以 Ruby 实现的,因此有非常多的缺点,比如,你对 Ruby 版本的切换只能在本次生效。另外,你得自己手动安装很多个版本,对于不了解 RubyInstaller 内部工作的人来说,将会很头疼,比如要不要安装 MSYS2? 需不需要更新?安装在哪个目录?为什么它的官网给了那么多可下载的链接?(这就是为什么我在 https://rubyinstaller.cn/ 中的下载区域只提供了几个链接的原因,其他那些让高级用户自己去存档里找吧)
我决定实现一个 rbenv ,然而我还是太自信了,我之前的了解 rbenv 原理其实就是读了几篇已有的文章,再加上写 rbenv-cn 的时候与之打交道了一部分而已,其实你随便问一个问题,我就支支吾吾了,比如 rehash 到底是啥?生成 Bash 脚本?生成 Bash 脚本用来干嘛?不知道。
于是我决定耐下心来,研究清楚 rbenv 在 Windows 上的可能性。我搞清楚了大部分 RubyInstaller 的工作原理(这次是真的绝大部分了,毕竟也没有人写它的文章,无从参考)。这个时候我自己就有一套实现 rbenv 的方案了。而且,我一上来想到的就和 rbenv 的实现不同,是利用 Windows 文件系统的 junction 来处理(然而,最后我还是另外实现了 shims)。至于语言,当然是用 Windows 上的原生语言 PowerShell 写,使用 PowerShell 开发的舒适度远远远超过于令人发指,令人气愤的 Zsh, Bash. 刚才我们提到的 rbenv 网络问题,我记得在看它的 issues 时,有人就提到了用 Bash 实现太混乱,不好修改代码的问题。
尽管 PowerShell 也有非常多脚本语言存在的弊端,不过代码的清晰度,可维护性,都非常地高了,运行速度也非常快,所以你最终会发现我实现的 shims 仅有 8ms ~ 20ms 的延迟,这个已经可以达到 rbenv 的效果了。
实现效果如何?使用 rbenv install head 来直接体验正在开发的 Ruby-dev 吧!

国内用户优先考虑,我直接将镜像内置了。也就是说,以后几乎不需要再去 https://rubyinstalelr.org 或者 https://rubyinstaller.cn 了。完全用命令行来下来安装管理多 Ruby 吧。
<2023-04-12> 更新:在这里我只提供国内用户使用的方式(通过 Gitee)
# 自定义你想安装到的位置,最好不要有空格,因为没有测试过
$env:RBENV_ROOT = "C:\Ruby-on-Windows"
$s = (iwr -useb "https://gitee.com/RubyMetric/rbenv-for-windows/raw/main/tool/install.ps1")
icm -sc ([scriptblock]::Create($s.Content)) -arg "install", "cn"
然后在你的 $profile 里添加
# rbenv for Windows
$env:RBENV_ROOT = "C:\Ruby-on-Windows"
# 这个变量一定要放在 init 之前
$env:RBENV_USE_MIRROR = "CN" # For Chinese users
& "$env:RBENV_ROOT\rbenv\bin\rbenv.ps1" init
rbenv 更快,因为直接使用 RubyInstaller2 经过测试打包好的二进制,意味着所有人使用经过测试的统一版本,也不需要编译,非常节省时间。scoop 代码,整个框架非常清晰。想了解 rbenv 原理,不如直接来看本项目是怎么实现的。