Ruby Code解释道

有人可以解释这段Ruby代码:

def add_spec_path_to(args) # :nodoc: args << {} unless Hash === args.last args.last[:spec_path] ||= caller(0)[2] end 

我已经看到<<运算符用于连接字符串或者作为其他语言的按位运算符,但是有人可以在这种情况下解释它。 它是以某种方式将空白的lamda附加到args上还是我完全错了?

我也可以看到它像这样使用:

 before_parts(*args) << block 

Hash是关键字吗?

我也不确定||=运算符在说什么。

对于caller(0)[2]来说,我同样处于黑暗中。

|| =是一种常见的Ruby习语:只有在尚未设置值时才分配值。 效果和代码一样

 if some_variable == nil some_variable = some_value end 

要么

 some_variable= some_value unless some_variable 

===,当没有被覆盖时,比较两个对象的身份。 在Hash === args.last的情况下,Hash(它是Class类型的对象)正在检查它是否与args数组中最后一项的类相匹配。 代码利用了一个明显的事实,即Class#===的实现强制检查比较对象的类。

它反过来不起作用,例如:

 a = [{}] Hash === a.last #=> true a.last === Hash #=> false 

方法的尾随参数可以作为哈希的内容提供,而无需提供{}

所以你可以这样做:

 def hello(arg1, arg2, arg3) puts [arg1.class, arg2.class, arg3.class].join(',') end hello 1,2,3 #=> Fixnum,Fixnum,Fixnum hello :a, "b", :c => 1, :d => 99 #=> Symbol,String,Hash 

它通常用于为函数提供可变参数的可变参数列表。

你确定你准确地转录了原始代码,顺便问一下? 为了获得一个参数数组,你通常会在声明的参数中添加一个*,否则args必须作为一个数组输入,而不是打败对象。

 def add_spec_path_to(*args) # now args is an array args << {} unless Hash === args.last # if trailing arguments cannot be # interpreted as a Hash, add an empty # Hash here so that following code will # not fail args.last[:spec_path] ||= caller(0)[2] # Set the spec_path option if it's not # already set end 

编辑:进一步扩展* args的事情,试试这个:

 def x(*args) puts args.join(',') puts args.map{|a| a.class }.join(',') end x 1,2,:a=>5,:b=>6 1,2,a5b6 Fixnum,Fixnum,Hash 

...使用* args会导致args作为数组呈现给方法。 如果我不使用*,就像这样,例如:

 def y(args) puts args.join(',') puts args.map{|a| a.class }.join(',') end 

...然后在调用方法之前args必须是一个数组,否则我会得到一个“ArgumentError:错误的参数数量”,除了一件事情。 所以它必须看起来像这样:

 y [1,2,{:c=>3,:d=>4}] 

...使用{}显式创建的Hash。 它很难看。

所有上述测试均采用MRI 1.8.6,顺便说一句。

我假设args是一个Array

Hash是类的名称 – 第一行将空哈希{}推送到args 除非 args的最后一个元素已经是Hash (类的===运算符测试对象是否属于某个类)。

||=运算符类似于+=运算符:它或多或少等同于:

 args.last[:spec_path] = args.last[:spec_path] || caller(0)[2] 

因此,当且仅当它args.last[:spec_path]设置时,它将设置args.last[:spec_path]

caller方法返回有关调用方法的信息。

以更短的方式:

 def add_spec_path_to(args) # :nodoc: ... # Append an empty hash to args UNLESS the last arg is a hash.. in which case do nothing args << {} unless Hash === args.last # so we need a hash. If it is not there, make an empty one and put it there. ... #if args.last[:spec_path] equals nil or false, set it to caller(0)[2]... #so inside that hash from the first part, if :spec_path is not there, create it by using caller(0)[2]. args.last[:spec_path] ||= caller(0)[2] ... end