随着Ruby 1.9.2版的发布,现在是让开发人员对Ruby 1.9感到兴奋的时候了。你可以在Ruby 1.9中用Ruby 1.8做些什么好事?
答案 0 :(得分:31)
我无法相信这还没有被提及:Ruby 1.9.2+的最大特点是,17年来Ruby第一次有了规范。
您可能听说过Ruby 1.9.2的所有发布时间表(本应该在2010年春季发布)has been canceled,这就是原因:首先,Ruby 1.9的完整规范。 2将在RubySpec项目中开发,然后将发布Ruby 1.9.2(编程语言),然后才会发布YARV 1.9.2,在之后通过RubySpec测试套件。
这完全取决于以前的工作原理:首先发布了MRI,然后所有其他实现者都读取了(不是很好设计,通常记录很差)的C源代码,试图弄清楚到底是什么这个新功能本应该做的,然后他们尝试编写可执行的规范,然后他们才有了实际兼容性的远程机会。但到那个时候,一般来说,YARV的新版本已经发布,并且周期重新开始......更不用说MRI和YARV的维护者甚至没有运行RubySpec。
这有巨大的分支。例如,尽管目前有十几种不同的Ruby实现正在积极开发中,并且多年来它已经有超过30种不同的Ruby编程语言实现,但这个事实不是得到了Ruby编程语言的维护者的认可。对于他们来说,Ruby和MRI(或者更近期的Ruby和YARV)一直都是同一件事:MRI既是语言又是执行引擎,Ruby既是执行引擎又是语言。 Ruby编程语言的“规范”是MRI的C源代码。
截至五周前,这已经发生了变化:现在,Ruby编程语言的官方规范(至少版本1.9.2及更高版本)是RubySpec项目的可执行测试套件。而YARV只是另一个Ruby实现,完全等同于MacRuby,IronRuby,JRuby,Cardinal,tinyrb,SmallRuby,BlueRuby,MagLev等等。
这意味着所谓的“备用”实现(现在因为YARV已经失去其特殊状态而不再被称为“备用”)现在有机会实际上赶上YARV中实现的最新语言功能。事实上,由于大多数其他实现实际上都比YARV更好地设计和实现了更好的语言(这基本上是一个巨大的意大利面C),加上拥有更多的人力,其他实现实际上是完全合理的 YARV之前符合Ruby 1.9.2 。
答案 1 :(得分:16)
我个人喜欢新的哈希语法:{:a => 1}
变为{a:1}
答案 2 :(得分:13)
枚举。
["a", "b", "c"].map {|elem, i| "#{elem} - #{i}" }
# => ["a - ", "b - ", "c - "]
["a", "b", "c"].each_with_index.map {|elem, i| "#{elem} - #{i}" }
# => ["a - 1", "b - 2", "c - 3"]
当没有传递块时, Enumerable
方法返回Enumerator
的实例。在这种情况下,它用于从map
获取index
each_with_index
个参数。
这也被反向移植到1.8.7。
答案 3 :(得分:11)
Ruby 1.9具有不同的阻止行为:
块参数始终是其块的本地参数,块的调用永远不会为现有变量赋值:
块语法已扩展为允许您声明保证为本地的块局部变量,即使封闭范围中已存在同名变量。
主题也不同:
Ruby 1.8只使用一个本机线程,并在该一个本机线程中运行所有Ruby线程。这意味着线程非常轻量级但它们从不并行运行。
Ruby 1.9不同,它为每个Ruby线程分配一个本机线程。但是因为使用的某些C库本身不是线程安全的,所以Ruby非常保守,并且永远不会允许多个本机线程同时运行(这种限制可能会在以后的版本中放宽)
其他一些小改动是在加载路径中包含 RubyGems ,不再需要require "rubygems"
。
答案 4 :(得分:10)
我非常喜欢枚举器 - 不仅仅是针对现有类型,而是将我自己的集合编写为Enumerator类。自从切换到1.9以来,我有两次不得不为外部Web服务构建API适配器,从而提取大型JSON或XML结果集。有时我会被限制在一次可以检索多少条记录,这意味着我需要做多个请求。 (获得前500,然后获得记录501到1000,等等)
我已经处理过的“旧”方法是抓住第一批,用.each
或.collect
一次性迭代它,然后创建一个相等大小的数组Ruby对象。如果我无法在一个请求中获取所有记录,我也会循环访问API请求,每次都添加到数组中。这意味着所有的时间都是前载的,被认为是慢速检索,而我正在咀嚼 很多 的内存:对于源数据,对于相同的数字Ruby对象,有时用于中间数组操作。当我可能一次只操作一个物体时,这很浪费。
使用枚举器,我可以获取第一批,将源数据保存为我的“权威”集合,并在我进入它时处理并生成每个Ruby对象 。当我传递最后一个元素时,如果我知道要从源中提取更多数据,那么我可以进行下一个API调用。 (即,延迟加载。)这意味着检索方法调用的返回速度要快得多,内存使用情况要好得多。我完成后,每个Ruby对象都有资格进行垃圾收集,并且已经移动到下一个。
这个想法的抽象实现如下:
class ThingyCollection < Enumerator
attr_reader :total
# Returns a new collection of thingies.
def initialize(options={})
# Make the request for the first batch
response = ThingyAPIClient.get_thingies(options)
@total = response.total # Number of ALL thingies, not just first batch
records = response.data # Some array of JSON/XML/etc. from the API
# Create a closure which serves as our enumerator code
enum = Proc.new do |yielder|
counter = 0 # Initialize our iterator
while counter < @total
# If we're at the end of this batch, get more records
if counter == records.length
more = ThingyAPIClient.get_next_thingies(counter, options)
records += more.data
end
# Return a Ruby object for the current record
yielder.yield Thingy.new(records[counter])
counter += 1
end
end
# Pass that closure to the Enumerator class
super(&enum)
end
end
一旦你拥有了它,你可以像:
一样走过它们thingies = ThingyCollection.new(foo: bar) # Whatever search options are relevant
puts "Our first thingy is #{thingies.next}"
puts "Our second thingy is #{thingies.next}"
thingies.rewind
thingies.each do |thingy|
do_stuff(thingy)
end
你输了什么?主要是通过引用轻松跳转到特定元素的能力。 (这意味着你也失去了“最后”,排序等等)只是获得.next
和几个.each
变体并不像数组功能那样丰富,但对于我最常见的用例,它就是我的全部需要。
是的,由于backporting,您可以使用Ruby 1.8.7执行此操作。但由于内部使用纤维,1.9的速度要快得多。如果它不是1.9,那么就不会有1.8.7,所以我认为它仍然是我最喜欢的1.9功能。
答案 5 :(得分:9)
Ruby 1.9.2支持获取有关方法参数的信息。您可以获取参数的名称以及有关它们的信息,例如optional,required或block。
查看Method#params示例。
答案 6 :(得分:9)
哈希在ruby 1.9中订购。它在实现某些算法时非常有用。您必须依赖gem或在ruby 1.8中编写自己的有序哈希。
答案 7 :(得分:6)
对多字节字符编码的完全原生支持,尤其是Unicode。
答案 8 :(得分:5)
instance_exec和class_exec是很棒的新功能,但对我来说主要是小的变化(已经被反向移植到1.8.7)。像Method#owner这样的东西很棒 - 曾经想知道在继承链中确切定义了一个特定的方法? my_object.method(:blah).owner会告诉你:)
我喜欢1.9的其他事情是更一致的范围规则,尤其是。在eval上下文中。这是一个愚蠢的遗漏(IMO),常量和类变量没有在instance_eval中查找,1.9解决了这个问题:)
答案 9 :(得分:5)
我喜欢Symbol#to_proc
,这样每次使用高阶函数时都可以省去写一个lambda。因此,虽然将数组求和为arr.inject(0) {|memo, val| memo + val}
,但现在只需编写arr.inject(&:+)
,而不是houses.collect {|house| house.price}
,您可以编写houses.collect(&:price)
。
有些库(例如ActiveSupport)在1.8下提供了相同的功能,但将它作为核心语言的一部分仍然很好,并且1.9实现比库方法更优化。
答案 10 :(得分:3)
哦,而且:它快了两倍多。如果您正在构建具有大量I / O延迟的多线程应用程序,则会更快。由于仍然所做的所有工作试图从1.8中提取更多性能,或者修复其线程等,令人惊讶的是人们对1.9的速度并没有更加兴奋或其原生线程。
答案 11 :(得分:3)
YARV。 1.9中的新Ruby VM提供了一种新的现代VM,速度更快。
答案 12 :(得分:3)
改进了正则表达式支持。 Ruby 1.9支持命名的正则表达式组 - 在许多其他改进中 - 您可以在后面的正则表达式中回忆起来。戴夫托马斯给了一个伟大的example。
答案 13 :(得分:2)
Ruby 1.9 Fibers提供了一个强大的新并发构造。 Ruby Fibers: 8 Useful Reads On Ruby’s New Concurrency Feature有与纤维相关文章的链接。
答案 14 :(得分:2)
1.8中的Unicode支持是通过额外的宝石,并且让我感到痛苦 - 为此获得全面的语言支持会很棒。有些人抱怨实现的复杂性,但我猜他们从未在C ++中使用ICU!
另外能够做"Hello"[3]
并获得一个角色会很好。
有些benchmarks显示significant improvements over 1.8.6, with 1.9.1 - 由于Matz Ruby中的新VM(YARV)
如果您有Dave Thomas的“Programming Ruby”(AKA The Pick-ax书)的副本,那么关于内置类和方法的部分可以很好地标记从1.8到1.9的变化
怎么样:
(a)新的哈希语法:{:hello =&gt; “world”}可缩短为{:hello:“world”}
(b)订购哈希!!
答案 15 :(得分:1)
在Ruby 1.9。+中,也可以将方法链接到多行。 这似乎不是一个疯狂的功能,但它允许你的代码更具可读性,这是Ruby的一个关键概念。
例如:
@results = Clients
.from_category(current_category)
.selected_by(current_user.id)
.activated
.order("created ASC")
.limit(1000)
.map{ |e| "#{e.id} - {e.fullname}" }