T‑Ruby:在 Ruby 中添加静态类型而不产生运行时开销
Source: Dev.to

介绍
静态类型是一种强大的工具,为各种规模的代码库带来巨大的价值。从小脚本到庞大的单体应用,这些好处不容忽视:你可以获得始终保持最新的实时文档、提升的可读性,以及显著提升代码可靠性的可靠安全网。
不同的动态语言走了各自的道路来解决类型难题。Python 引入了原生但可选的类型提示,而 JavaScript 生态系统则完全转向了独立语言 TypeScript。在 Ruby 社区,我们看到了 RBS 和 Sorbet 两种不同的实现,最近由于 RBS inline 的引入以及 Sorbet 对其的支持,这两者开始趋于融合。
然而,当前的 Ruby 方案并非毫无摩擦。对许多开发者而言,类型仍然更像是个人偏好,而非核心需求。由于类型检查常被视为“额外”的东西,静态检查很容易被忽视或完全遗忘。
什么是 T‑Ruby?
一个正在获得关注的突破性实验是 T‑Ruby。与标准的运行时类型检查系统不同,T‑Ruby 将带类型的代码编译为纯粹、未装饰的 Ruby,且没有任何运行时开销。简而言之,T‑Ruby 本质上是 Ruby 语言的 TypeScript:你编写受 RBS 启发的代码,最终会被编译成普通的标准 Ruby。
虽然有些人可能会建议使用 Crystal,但两者在理念上有根本区别。Crystal 是一种独立的、类似 Ruby 的语言,拥有自己的生态系统。而 T‑Ruby 则是一个额外的层,旨在保持与我们已经熟悉的 Ruby 紧密相连。就像 TypeScript 最终会输出纯 JavaScript,T‑Ruby 确保你的最终产物仍然是纯 Ruby。
示例:带类型的 HTTP 客户端
下面是一个简单的 HTTP 客户端,它从 GitHub 获取最新的 Ruby 发布标签。使用 T‑Ruby,类型直接嵌入到类结构中。
require "httparty"
require "json"
require "time"
class RubyVersion
API_URL = "https://api.github.com/repos/ruby/ruby/releases/latest"
class Response
attr_reader :code: Integer
attr_reader :json: Hash
def initialize(code: Integer, json: Hash): nil
@code = code
@json = json
end
def success?: Boolean
(200..299).include?(@code)
end
end
def fetch_response: Response
http = HTTParty.get(API_URL, headers: { 'User-Agent' => 'static-typing-demo' })
Response.new(http.code.to_i, JSON.parse(http.body))
end
def self.fetch(printer: Proc<[String, String, Time], nil]): nil
resp = new.fetch_response
raise "HTTP #{resp.code}" unless (200..299).include?(resp.code)
data = resp.json
published = Time.parse((data['published_at'] || Time.now.utc.iso8601).to_s)
printer.call((data['tag_name'] || data['name']).to_s, data['html_url'], published)
end
end
通过添加这些类型,我们可以严格定义 Proc 的结构,并确保系统中传递的数据是有效的。在标准 Ruby 中,我们通常依赖文档或手动的守卫子句来实现这种确定性。
设置 T‑Ruby
-
安装 gem:
gem install t-ruby -
初始化配置文件:
trc --init
生成的配置允许您指定 *.trb 文件的源文件夹、编译后 Ruby 的输出位置,以及诸如自动运行 RSpec 或 Minitest 的编译后命令。
Rails Integration (Experimental)
Rails 依赖特定的文件夹结构,因此最简洁的方法是将整个 app 文件夹存放在你的 T‑Ruby 源代码目录中。那些不包含 T‑Ruby 语法的文件会直接原样复制到目标文件夹。这与现代 JavaScript 框架(如 Next.js)中常见的 /src / /dist 工作流相呼应。
当前状态与展望
T‑Ruby 仍处于 技术预览 阶段。网站和文档看起来很精致,但实现可能不太稳定——官方示例在安装后可能会立即失败。
尽管有这些粗糙之处,但其潜力不可否认。在一个小型 Rails 应用中使用 T‑Ruby,省去了单独维护 RBS 文件的需求。将类型与业务逻辑一起编写感觉很自然,并且在编译时知道代码是“类型正确”的,这带来了独特的安心感。这是 Ruby 生态系统的一大进步,即使它尚未完全准备好用于生产环境。
最初发布于我的博客.