|| = is a common Ruby idiom: it only assigns a value if it is not already set. The effect is the same as the type code
if some_variable == nil some_variable = some_value end
or
some_variable= some_value unless some_variable
=== when not redefined, two objects are compared for identification. In the case of Hash === args.last , Hash (which is an object of type Class) checks to see if it matches the class of the last element of the args array. The code uses the obvious fact that the implementation of the class # === forces us to check the class of the compared object.
This does not work the other way around, for example:
a = [{}] Hash === a.last #=> true a.last === Hash #=> false
Returned arguments to the method can be provided as hash contents without the need to provide {}
So you can do this:
def hello(arg1, arg2, arg3) puts [arg1.class, arg2.class, arg3.class].join(',') end hello 1,2,3
It is often used to provide optional variable-length parameters for a function.
Are you sure that you have exactly rewritten the source code, by the way? To get an array of arguments, you usually add * to the argument, as declared, otherwise the arguments must be entered as an array, which is more likely to defeat the object.
def add_spec_path_to(*args)
EDIT: Extending further in the * args argument, try the following:
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
... using * args causes args to be presented to the method as an array. If I do not use * like this, for example:
def y(args) puts args.join(',') puts args.map{|a| a.class }.join(',') end
... then args must be an array before I call the method, or I get "ArgumentError: wrong number of arguments" for anything but one. Therefore, it should look like this:
y [1,2,{:c=>3,:d=>4}]
... with a Hash explicitly created using {}. And it is ugly.
All of the above were tested using MRI 1.8.6, btw.