编程语言之Ruby
2010-08-19 08:47:31 阿炯

Ruby,一种为简单快捷的面向对象编程(面向对象程序设计)而创的脚本语言,在20世纪90年代由日本人松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)开发,遵守GPL协议和Ruby License。其灵感与特性来自于 Perl、Smalltalk、Eiffel、Ada 以及 Lisp 语言。由 Ruby 语言本身还发展出了JRuby(Java 平台)、IronRuby(.NET 平台)等其他平台的 Ruby 语言替代品。一种跨平台、面向对象的动态类型编程语言,Ruby 体现了表达的一致性和简单性,它不仅是一门编程语言,更是表达想法的一种简练方式。


Ruby的作者于1993年2月24日开始编写Ruby,直至1995年12月才正式公开发布于fj(新闻组)。之所以称为Ruby,是因为Perl的发音与6月的诞生石pearl(珍珠)相同,因此Ruby以7月的诞生石ruby(红宝石)命名。Ruby明显比其他类似的编程语言(如Perl或Python)年轻,又因为Ruby是日本人发明的,所以早期的非日文资料和程序都比较贫乏,所以现在在网上仍然可以找到Ruby的资料太少之类的批评。约于2000年,Ruby开始进入美国,英文的资料开始发展。

减少编程时候的不必要的琐碎时间,令编写程序的人高兴,是设计 Ruby 语言的 Matz 的一个首要的考虑;其次是良好的界面设计。他强调系统设计必须强调人性化,而不是一味从机器的角度设想。“ 人们特别是电脑工程师们,常常从机器着想。他们认为:“这样做,机器就能运行的更快;这样做,机器运行效率更高;这样做,机器就会怎样怎样怎样。”实际上,我们需要从人的角度考虑问题,人们怎样编写程序或者怎样使用机器上应用程序。我们是主人,他们是仆人。 ”

遵循上述的理念,Ruby 语言通常非常直观,按照编程人认为它应该的方式运行。Ruby 是完全面向对象的:任何一点数据都是对象,包括在其他语言中的基本类型(比如:整数,布尔逻辑值),每个过程或函数都是方法。

特点
完全面向对象
在Ruby语言中,任何东西都是对象,包括其他语言中的基本数据类型,比如整数
变量没有类型:Ruby的变量可以保有任何类型的数据
任何东西都有值:不管是数学或者逻辑表达式还是一个语句,都有值

命名规则
Ruby的变量有一定的规则,以$开头的一定是全局变量,以@开头的都是实例变量,而以@@开头的是类变量。常数则以大写字母开头;这种方法,对文本编辑器的命令补全很有帮助,如在vim下先键入$及开头字母,再敲击Ctrl+p,则可专门补全本文件以及关联文件中的全局变量,perl与php亦有此优点。

已经定义的类可以在运行时修改
Ruby是动态语言,你可以在程序中修改先前定义过的类。 也可以在某个类的实例中定义该实例特有的方法,这叫做单立方法。
class MyClass
def the_method
"general method"
end
end
mc = MyClass.new
def mc.the_method
"special for this instance."
end
mc.the_method #special for this instance

使用Ruby可以写出简短而有功能强大的代码
#下面的方法用来完成两个矩阵的乘积
def matrix_mul(matrix1,matrix2)
result=Array.new
(0...matrix1.length).each {|i| temp=Array.new;(0...matrix2.length).each{|j| tmp=0; (0...matrix1[0].length).each {|k| matrix1[k].to_f*matrix2[k][j].to_f }; temp< return result
end

概述
Ruby是一种功能强大的面向对象的脚本语言,它可以使您方便快捷地进行面向对象编程.有时使用像Smalltalk、Eiffel或C++这样正式的面向对象语言来开发一些小项目显得有点"小题大做",而Ruby刚好可以满足这些面向对象编程的需求.当然了,您也可以使用Ruby进行普通的面向过程编程。Ruby的文本处理能力极强,与Perl不分伯仲。同时,Ruby的语法简单,还有异常处理以及迭代器等构造,使编程变得简单明了,简而言之,您可以像使用Perl一样方便快捷地进行面向对象的开发.怎么样?赶紧试一试吧!Ruby是由松本行弘开发的免费软件。

Ruby的优点:
语法简单
普通的面向对象功能(类,方法调用等)
特殊的面向对象功能(Mixin,特殊方法等)
操作符重载
错误处理功能
迭代器和闭包
垃圾回收
动态载入(取决于系统架构)
可移植性高.不仅可以运行在多数UNIX上,还可以运行在DOS,Windows,Mac,BeOS等平台上

Ruby的作者
松本行弘"Matz"[matz@netlab.jp](Matsumoto Yukihiro)是Ruby语言的发明人,他从1993年起便开始着手Ruby的研发工作。他一直想发明一种语言,使你既能进行高效开发又能享受编程的快乐。1993年2月24日Ruby诞生了,1995年12月Matz推出了Ruby的第一个版本Ruby 0.95。不久Ruby便凭借其独特的魅力横扫日本,相信在不久的将来,Ruby将走向世界。


最新版本:1.9.2
该版本包含了一个新的支持 IPv6 的套接字 API、新的随机数生成器以及一个重新实现的时间模块,不会有 2038 年问题;当然还包括很多其他的新方法。

最新版本:2.0
Ruby 编程语言的创建者和首席设计师 Yukihiro Matsumoto(松本行弘)表示 Ruby 3.0 将在2020年12月25日这天发布,现在根据官方信息,该版本如约而至。松本表示,Ruby 3 比 Ruby 2 快 3 倍。此版本主要目标包括:
性能:MJIT
并发:Ractor、Fiber Scheduler
类型(静态分析):RBS、TypeProf

RBS:这是一种描述 Ruby 程序类型的语言。类型检查器(包括类型分析器和其他支持 RBS 的工具)将通过 RBS 定义更好地理解 Ruby 程序。开发者可以写下类和模块的定义:类中定义的方法、实例变量及其类型以及继承/混合关系。RBS 的目标是支持 Ruby 程序中常见的模式,它允许编写高级类型,包括联合类型、方法重载和泛型。它还支持带有接口类型的 duck typing。

Ractor(实验阶段):是类似于并发抽象的 Actor 模型,旨在提供并行执行功能而无需担心线程安全。为了限制共享对象,Ractor 对 Ruby 的语法引入了一些限制。

Scheduler
引入Thread#scheduler用于拦截阻塞操作,允许轻量级的并发,而无需更改现有代码。当前支持的类/方法:
Mutex#lock, Mutex#unlock, Mutex#sleep
ConditionVariable#wait
Queue#pop, SizedQueue#push
Thread#join
Kernel#sleep
IO#wait, IO#read, IO#write 与相关方法如 #wait_readable, #gets, #puts
不支持 IO#select

Ruby 3 还重新设计了单行匹配模式:
添加了 =>:
0 => a
p a #=> 0
{b: 0, c: 1} => {b:}
p b #=> 0

in 用于返回 true/false:
# version 3.0
0 in 1 #=> false

# version 2.7
0 in 1 #=> raise NoMatchingPatternError

最新版本:3.1
Ruby 3.1.0 于2021年12月下旬发布,它保持与 Ruby 3.0 的兼容性,并添加了许多功能。

YJIT:新的实验性进程内 JIT 编译器
Ruby 3.1 合并了 YJIT,这是 Shopify 开发的一种新的进程内 JIT 编译器。自从2018年Ruby 2.6 引入了 MJIT 后,它的性能有了很大的提升,最终我们在去年实现了 Ruby3x3。但是,尽管 Optcarrot 已经显示出令人印象深刻的加速,但 JIT 并没有使现实世界的业务应用程序受益。最近 Shopify 贡献了许多 Ruby 改进来加速他们的 Rails 应用程序。YJIT 是一个重要的贡献,旨在提高 Rails 应用程序的性能。尽管 MJIT 是基于方法的 JIT 编译器并使用外部 C 编译器,但 YJIT 使用基本块版本控制并在其中包含 JIT 编译器。使用 Lazy Basic Block Versioning (LBBV),它首先编译方法的开头,并在动态确定参数和变量的类型时增量编译其余部分。有关详细介绍,请参阅YJIT:用于 CRuby 的基本块版本控制 JIT 编译器。通过这项技术,YJIT 在大多数现实世界的软件上实现了快速预热时间和性能改进,在 railsbench 上高达 22%,在液体渲染上高达 39%。YJIT 仍然是一个实验性功能,因此默认情况下它是禁用的。如果要使用它,请指定--yjit命令行选项以启用 YJIT。目前它也仅限于类 Unix 的 x86-64 平台。

debug gem:一个新的调试器
捆绑了一个完全重写的调试器debug.gem。debug.gem 有以下特点:
提高调试性能(即使使用调试器也不会减慢应用程序的速度)
支持远程调试
支持丰富的调试前端(现在支持VSCode和Chrome浏览器)
支持多进程/多线程调试
多彩的REPL
以及其他有用的功能,如记录和重放功能、跟踪功能等。

Ruby 捆绑了 lib/debug.rb,但它没有得到很好的维护,并且在性能和特性方面存在问题。debug.gem 完全取代了 lib/debug.rb。已引入内置 gem error_highlight。它包括回溯中的细粒度错误位置,目前,仅NameError支持。默认情况下启用此 gem。您可以使用命令行选项禁用它--disable-error_highlight。详细查看存储库。

IRB 自动完成和文档显示
IRB 现在具有自动完成功能,您只需在其中输入代码,就会出现完成候选对话框。您可以使用 Tab 和 Shift+Tab 上下移动。如果在选择完成候选时安装了文档,则完成候选对话框旁边将出现文档对话框,显示部分内容。您可以按 Alt+d 阅读完整文档。

其他值得注意的新功能

语法改进
哈希文字和关键字参数中的值可以省略。
    {x:, y:}是 的语法糖{x: x, y: y}。
    foo(x:, y:)是 的语法糖foo(x: x, y: y)。
模式匹配中的 Pin 运算符现在采用表达式。
单行模式匹配中可以省略括号。

RBS
RBS 是一种描述 Ruby 程序结构的语言。有关详细信息,请参阅存储库,自 Ruby 3.0.0 以来的更新:
泛型类型参数可以是有界的。
支持通用类型别名。
rbs collection已被引入管理 gems 的 RBS。
添加/更新了许多内置和标准库的签名。
它还包括许多错误修复和性能改进。

TypeProf
TypeProf 是 Ruby 的静态类型分析器。它从非类型注释的 Ruby 代码生成 RBS 的原型。有关详细信息,请参阅文档。自 Ruby 3.0.0 以来的主要更新是一个名为“TypeProf for IDE”的实验性 IDE 支持。vscode 扩展在每个方法定义上方显示一个猜测的(或明确写在 RBS 文件中的)方法签名,在可能导致名称错误或类型错误的代码下画一个红色下划线,并完成方法名称(即显示方法候选) . 详细看文档。此外,该版本还包括许多错误修复和性能改进。

性能改进

MJIT:对于 Rails 等工作负载,默认值--jit-max-cache从 100 更改为 10000。JIT 编译器不再跳过长度超过 1000 条指令的方法的编译。为了支持 Rails 的 Zeitwerk,当启用类事件的 TracePoint 时,不再取消 JIT-ed 代码。

自 3.0 以来的其他显着变化
单行模式匹配,例如 ,ary => [x, y, z]不再是实验性的。
多重分配评估顺序略有变化。
可变宽度分配:字符串(实验性)
Psych 4.0 更改Psych.load为safe_load默认设置,可能需要使用 Psych 3.3.2 才能迁移到此行为。

最新版本:3.2
Ruby 3.2.0 现已于2022年12月下旬发布,该版本添加了许多功能和性能改进。具体更新内容如下:

基于 WASI 的 WebAssembly 支持:初始移植,此项特性使得 CRuby 二进制文件可在 Web 浏览器、Serverless Edge 环境和其他 WebAssembly/WASI 嵌入器上使用。目前此移植可在不使用 Thread API 的前提下通过基本和引导测试套件的测试。

生产就绪的 YJIT
YJIT 不再是实验性的,已经在生产工作负载上进行了一年多的测试,证明非常稳定。
YJIT 现在支持 Linux、MacOS、BSD 和其他 UNIX 平台上的 x86-64 和 arm64/aarch64 CPU。
此版本支持 Apple M1/M2、AWS Graviton、Raspberry Pi 4 等。
构建 YJIT 现在需要 Rust 1.58.0+。[Feature #18481 ]
为了确保 CRuby 是使用 YJIT 构建的,请在运行./configure 脚本之前安装 rustc>= 1.58.0 。
YJIT 3.2 版本比 3.1 更快,内存开销大约是 3.1 的 1/3。
总体而言,YJIT 比 yjit-bench 上的 Ruby 解释器快 41%(几何平均值)。
JIT 代码的物理内存是延迟分配的。与 Ruby 3.1 不同,Ruby 进程的 RSS 被最小化,因为 --yjit-exec-mem-size 分配的虚拟内存页在 JIT 代码实际使用之前不会映射到物理内存页。
引入 Code GC,当 JIT 代码的内存消耗达到 --yjit-exec-mem-size 时,释放所有代码页。
RubyVM::YJIT.runtime_stats 在现有的 inline_code_size 和 outlined_code_sizekeys 之外,还返回 Code GC metrics: code_gc_count、live_page_count、freed_page_count 和 freed_code_size。
由 RubyVM::YJIT.runtime_stats 生成的大部分统计数据现在都可以在发布版本中使用。
只需使用 --yjit-stats​​运行 ruby 来计算和转储统计信息(会产生一些运行时开销)。
YJIT 现在经过优化以利用 object shapes。
在定义新常量时,利用更细粒度的常量失效来减少代码的无效化。
默认 --yjit-exec-mem-size 更改为 64 (MiB)。
默认 --yjit-call-threshold 更改为 30。

针对 ReDoS 的正则表达式改进:由于正则表达式匹配会耗费不少时间,当代码试图向不受信任的输入匹配低效的正则表达式时,攻击者可能会利用它进行 DoS 攻击(即正则表达式 DoS,或称作 ReDoS)。因此新版本引入了两项可显着缓解 ReDoS 攻击的改进。

改进的正则表达式匹配算法:从 Ruby 3.2 开始,Regexp 的匹配算法通过使用记忆技术得到了极大的改进。改进后的匹配算法使得大多数 Regexp 匹配(实验中大约为 90%)在线性时间内完成。对于 3.2.0 预览版本的用户:此优化可能会消耗与每个匹配的输入长度成比例的内存。预计不会出现实际问题,因为此内存分配通常会延迟,并且正常的 Regexp 匹配最多应消耗 10 倍的内存输入长度。该功能最初的提议在此。https://bugs.ruby-lang.org/issues/19104

正则表达式超时退出机制:此版本引入了正则表达式超时退出机制。
Regexp.timeout = 1.0
Regexp.timeout 根据 Ruby 应用程序的要求进行配置,可以防止或显着降低 DoS 的风险。请注意,Regexp.timeout 是全局配置项,如果希望对某些特殊的正则表达式使用不同的超时设置,需要使用 timeout 关键字 Regexp.new。此项特性的最初提案在此。https://bugs.ruby-lang.org/issues/17837

其他值得注意的新功能
语法建议:syntax_suggest(以前的 dead_end)的功能已集成到 Ruby 中,可以帮助找到错误的位置,例如丢失或多余的 end 。

错误高亮:现在它指向 TypeError 和 ArgumentError 的相关参数。

语言:匿名 rest 和关键字 rest 参数可以作为参数传递,而不仅仅是在方法参数中使用。

更多详情可查看官方公告

最新版本:3.3
3.3.0 现已于2023年12月下旬正式发布。新版本添加了一个名为 Prism 的新解析器,使用 Lrama 作为解析器生成器,添加了一个名为 RJIT 的新纯 Ruby JIT 编译器,以及许多性能改进,尤其是 YJIT。具体更新内容如下:

Prism
引入 Prism 解析器作为默认 gem
Prism 是一个可移植、容错且可维护的 Ruby 语言递归下降解析器
Prism 已做好生产准备并积极维护,用户可以使用它代替 Ripper
具体介绍可查看 Prism 的文档。
Prism 既是一个由 CRuby 内部使用的 C 库,又是一个可供任何需要解析 Ruby 代码的工具使用的 Ruby gem
Prism API 中值得注意的方法有:
Prism.parse(source) 返回 AST 作为解析结果对象的一部分
Prism.parse_comments(source) 返回 comments
Prism.parse_success?(source) 如果没有错误,则返回 true
现在可以使用 ruby --parser=prism 或 RUBYOPT="--parser=prism" 尝试使用  Prism 编译器。值得注意的是,该 flag 仅用于调试。

使用 Lrama 代替 Bison
用 Lrama LALR 解析器生成器替换 Bison [Feature #19637]
更多详情可参阅 Ruby Parser 的未来愿景
为了便于维护,Lrama 内部解析器被替换为 Racc 生成的 LR 解析器
支持参数化规则 (?, *, +),将在 Ruby parse.y 中使用

YJIT
相对 Ruby 3.2 的主要性能改进
对 splat 和 rest 参数的支持已得到改进。
为虚拟机的堆栈操作分配了寄存器。
编译更多带有可选参数的调用,异常处理程序也被编译。
不支持的调用类型和复态调用点不再退出到解释器。
Rails #blank? 和 specialized#present?等基本方法都是内联的。
对 Integer#*、Integer#!=、String#!=、String#getbyte、 Kernel#block_given?、Kernel#is_a?、Kernel#instance_of? 和 Module#=== 进行了特别优化。
编译速度现在比 Ruby 3.2 稍快。
现在比 Optcarrot 上的解释器快 3 倍以上
与 Ruby 3.2 相比显着提高了内存使用率
编译代码的元数据占用内存更少。
当应用程序的 ISEQ 超过 40,000 个时,--yjit-call-threshold 会自动从 30 提高到 120。
添加 --yjit-cold-threshold 以跳过编译 cold ISEQ。
在 Arm64 上生成更紧凑的代码。
Code GC 现在默认禁用
--yjit-exec-mem-size 被视为新代码编译停止的硬限制。
不会因 Code GC 导致性能突然下降。使用 Pitchfork 重新分叉的服务器上有更好的 copy-on-write 行为 。
如果需要,仍然可以使用 --yjit-code-gc 启用 code GC
添加 RubyVM::YJIT.enable 以便在运行时启用 YJIT
无需修改​​命令行参数或环境变量即可启动 YJIT。Rails 7.2 将使用此方法默认启用 YJIT 。
这也可用于仅在应用程序完成启动后启用 YJIT。如果想在启动时禁用 YJIT 的同时使用其他 YJIT 选项,可以使用 --yjit-disable。
默认情况下提供更多 YJIT stats
现在默认情况下还提供了 yjit_alloc_size 和更多与元数据相关的统计信息。
由 --yjit-stats 生成的 ratio_in_yjitstat 现在可在发行版中使用,不再需要特殊的 stats 或 dev 版本才能访问大多数统计信息。
添加更多 profiling 功能
添加 --yjit-perf 以方便使用 Linux perf 进行分析。
--yjit-trace-exits 现在支持使用 --yjit-trace-exits-sample-rate=N 进行采样
更全面的测试和多个错误修复

RJIT
引入了纯 Ruby JIT 编译器 RJIT 并取代了 MJIT。
RJIT 仅支持 Unix 平台上的 x86-64 架构。
与 MJIT 不同,它在运行时不需要 C 编译器。
RJIT 的存在仅用于实验目的。
建议用户在生产环境中继续使用 YJIT。
如果对为开发 JIT for Ruby 感兴趣,可查看 k0kubun 在 RubyKaigi 第 3 天的演示。

M:N 线程调度器
引入了 M:N 线程调度程序。
M 个 Ruby 线程由 N 个本机线程(操作系统线程)管理,因此减少了线程创建和管理成本。
它可能会破坏 C 扩展兼容性,因此默认情况下会在主 Ractor 上禁用 M:N 线程调度程序。
RUBY_MN_THREADS=1 环境变量可在主 Ractor 上启用 M:N 线程。
M:N 线程始终在非主 Ractor 上启用。
RUBY_MAX_CPU=n 环境变量用于设置 N(本地线程的最大数量)的最大值。默认值为 8。
由于每个 Ractor 只能同时运行一个 Ruby 线程,因此将使用的本地线程数是 RUBY_MAX_CPU 中指定的线程数和正在运行的 Ractor 数量中较小的一个。因此,单 Ractor 应用程序(大多数应用程序)将只使用 1 个本地线程。
为了支持阻塞操作,可以使用 N 个以上的本地线程。

更多详情可查看官方公告


官方主页:http://www.ruby-lang.org/zh_cn/

该文章最后由 阿炯 于 2023-12-26 10:23:53 更新,目前是第 2 版。