我覺得 Ruby 最優秀的地方(RSpec)

2025 年 8 月 20 日
 mizuhashi

看隔壁關於 ORM 的討論說 Ruby/Rails 的長處都被其他語言學走了,但我覺得至少 RSpec 在 JS 世界還沒有替代。以下是一個用 RSpec 寫測試的例子:

require 'rspec'
require 'matrix'

RSpec.describe 'numbers' do
  # 描述加法的性質
  shared_examples 'addition' do
    # 加法滿足交換律
    # a 和 b 會在實際的 context 裏注入
    it 'has commutativity' do
      expect(a + b).to eq(b + a)
    end
  end

  context 'for number' do
    # 令 a 和 b 為兩個隨機數,並調用加法的測試用例
    let(:a) { Random.rand }
    let(:b) { Random.rand }

    it_behaves_like 'addition'
  end

  context 'for vector' do
    # a 和 b 可以是向量,也滿足加法的性質
    let(:a) { Vector[Random.rand, Random.rand] }
    let(:b) { Vector[Random.rand, Random.rand] }

    it_behaves_like 'addition'
  end

end

如果要用 js 寫,至少所有的 a 和 b 都要換成類似context.a context.b,因為 ruby 有 self ,而 js 只有詞法作用域,這導致 js 的 dsl 表達力很受限。

另外在 ruby 裏也可以很輕易做 mock ,例如這個例子修改了Date.today來返回我們測試用的日期:

require 'rspec'
require 'date'

RSpec.describe 'Date' do
  # 選定一個測試用的日期,一般來說實際會使用隨機的
  let(:date) { Date.parse('1970-01-01') }

  before do
    # Date.today 本身是標準庫定義好的,但我們可以覆寫它來返回我們的日期
    allow(Date).to receive(:today).and_return(date)
  end

  describe '.today' do
    it 'is the mocked date' do
      # Date.today 現在會是我們 mock 的日期 1970-01-01
      expect(Date.today).to eq(date)
    end
  end
end
4484 次点击
所在节点    程序员
33 条回复
cloudzhou
2025 年 8 月 21 日
@zpvip 别名就算了,那肯定不是解决之道,清晰是第一位

我在想,是否有个语言,有 ror 的开发舒适度,同时具备静态编译过程(可选),然后还能编译成为一个独立 bin (类似 Go )
也就是你在开发阶段,ror 现有开发方式;又是严格类型和语法,ide 完全可解析,比如变量名方法名错误及时提示(加个运行参数)

那就完美了
xgdgsc
2025 年 8 月 21 日
@cloudzhou https://github.com/erikedin/Behavior.jl?tab=readme-ov-file 可以试试 Julia ,就是目前编译独立 bin 在实现进程中,编译出比较大的一坨 dll 目前就可以,1.12rc 在测试编译出小体积的 dll 了。
doraemon0711
2025 年 8 月 22 日
我是力挺 rspec 的一派,因为我认为 rspec 完全发挥了 ruby 的高度定制 DSL 的能力,让写测试就像写文章一样顺畅
但我也充分理解一个对 ruby 不熟悉的人,或者母语非英语的人看到这些代码会一脸懵的情况,因为我刚开始用 rspec 是就是这样的

说回 ruby ,我认为其最显著的特点,是用**最简洁**的方式把面向对象发挥到了极致,当意识到 ruby 中任何定义的 class 都是 Class 的实例、`1+1`实际上是`1.+(1)`时,我才意识到什么叫完全面向对象的编程语言,你或许可以指责 ruby 性能不行,但了解过 ruby 的人一定不应该指责其语法不优雅
flyqie
2025 年 8 月 22 日
说起来,有点好奇,ruby 很多设计确实不错,但现在用的似乎并不算多,为什么呢?
mizuhashi
2025 年 8 月 22 日
@flyqie 我覺得這兩者是沒有關係的,像 react 的設計非常落伍但是用的人卻很多。從個人的角度我只知道自己很喜歡 ruby ,14 年的時候我要在 ruby python node 裏面選一個學,然後看了作者 matz 的書,很欣賞這個人,就堅定使用 ruby 了,後來也遇到了很多用 ruby 的有趣的人(當時在 qq 群裏的老師是一位寫 rpgmaker 腳本的)。我覺得技術背後的人/人文是很重要的,如果要為用的人少找個原因,大概就是有類似想法的人不是多數
mizuhashi
2025 年 8 月 22 日
@razertory 應該是的,在 ruby 裏的實現方式是,給定一個代碼塊,如 { a },我們可以自由決定這個 a 的解讀方式。實際上這個 a 代表的 self.a ,然後 ruby 可以在執行每個代碼塊的時候指定 self 是什麼,再找到對應的 a 方法,只要具備類似的特性就能實現差不多的東西
cloudzhou
2025 年 8 月 22 日
@flyqie 工业化和艺术品的区别,我是个艺术家,要把这个碗做的美的不可方物,耐摔实用一点不在乎;我要生产日用碗,耐摔可靠,最好一天批量生产 1 万个
kneo
2025 年 8 月 22 日
有没有可能,别人没有,是因为嫌弃?
AV1
2025 年 8 月 22 日
@mizuhashi
a 自动绑定到 self.a ,JS 曾经有类似的语法,也就是 with 块。
动态绑定 self ,在 JS 里也有类似的 call/apply/bind 。
还有 eval 、new Function ,可以玩各种很骚的操作。
但这些特性在 JS 里,通常不被视为优秀,而是糟粕,遭到唾弃。
或许这就是从“精致的小众玩意”转变到“流水线的大众工具”的代价吧
qiumaoyuan
2025 年 8 月 22 日
@flyqie 语言优秀不优秀,跟用的人多不多没有太大关系。我觉得以逻辑严谨著称的群体,应该要看得清楚这点。

很多时候反而设计得很糟糕的东西更流行,每当有人谈到排行榜、流行程度,我就总是联想到 MooTools 和 jQuery 。MooTools 设计得十分优秀,无论是源码(喏,你真要看每个函数/方法 10 行左右的代码,MooTools 相当多时候都是),还是暴露出来的接口,都简洁得不像话,但受众就是少得可怜。

而 jQuery 满世界闻名,流行程度我就不用多说了。但如果你想要复用代码,它就一个插件机制可选,写出来的代码总是又臭又长。反观 MooTools 本身基于对象的设计,OOP 当中那么多的复用手段,它都完全可以利用。

jQuery 流行的原因是啥?我觉得就是看起来上手简单。但工具这东西,上手难度和往深了用之后的趁手程度往往是两回事。

另外,如果看排行榜的话,以前 C 和 C++ 一直是老大,这两年 AI 火了,Python 一下窜到第一,所以 Python 突然变成最优秀的语言了吗?明显不是这个原因,对吧?
qiumaoyuan
2025 年 8 月 22 日
说话 RSpec 这东西,我特别喜欢的是它的 context (以及它的各种别名:describe ,example_group 等),这玩意可以把测试场景划分得很细,可以无限层级地复用上下文,简直就是为测试时遇到的各种场景细微区别时,最大限度复用代码而生的。

当然 TestUnit 和 MiniTest 本身利用好 OOP 也可以做到一样的效果,就是要求使用者熟练掌握 OOP 各项特性。
mizuhashi
2025 年 8 月 22 日
@DOLLOR 有道理,用 with this 加 bind 可以實現類似的
mizuhashi
2025 年 8 月 22 日
@qiumaoyuan rspec 寫起來很快樂,跑起來也很快樂,免費的快樂

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1153819

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX