Could somebody please explain this piece of Ruby code:
def add_spec_path_to(args) # :nodoc: args << {} unless Hash === args.last args.last[:spec_path] ||= caller(0)[2] end
I have seen the << operator used for concatenation strings or as a bitwise operator in other languages but could somebody explain it in this context. Is it somehow appending a blank lamda onto args or am I totally wrong?
I can also see it used like this:
before_parts(*args) << block
Is the Hash a keyword?
I am also unsure of what the ||= operator is saying.
I am equally in the dark as to what caller(0)[2] is.
||= is a common Ruby idiom: it assigns the value only if it is not already set. The effect is the same as code like
or
===, when not overridden, compares two objects for identity. In the case of
Hash === args.last, Hash (which is an object of type Class) is checking to see if it matches the class of the last item in the args Array. The code is making use of the apparent fact that the implementation of Class#=== forces a check on the class of the compared object.It doesn’t work the other way around, for example:
The trailing arguments to a method may be supplied as the contents of a hash without needing to provide the {}
So you can do this:
It’s often used to provide a variable-length list of optional parameters to the function.
Are you sure you transcribed the original code precisely, btw? In order to get an array of arguments, you would normally add an * to the argument as declared, otherwise args would have to be input as an array, whcih would rather defeat the object.
EDIT: Expanding further on the *args thing, try this:
… using *args causes args to be presented to the method as an array. If I don’t use the *, like this, for example:
… then args has to be an array before I call the method, or I’ll get an ‘ArgumentError: wrong number of arguments’ for anything but one thing passed. So it has to look like this:
…with the Hash explicitly created with {}. And it’s ugly.
All the above tested with MRI 1.8.6, btw.