|| = является распространенной идиомой 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
Он часто используется для предоставления списку необязательных параметров переменной длины для функции.
Вы уверены, что точно расшифровали исходный код, кстати? Чтобы получить массив аргументов, вы обычно добавляете * к аргументу, как объявлено, в противном случае аргументы должны быть введены как массив, который скорее победит объект.
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 приводит к тому, что аргументы представляются методу в виде массива. Если я не использую *, например, вот так:
def y(args)
puts args.join(',')
puts args.map{|a| a.class }.join(',')
end
... тогда аргументы args должны быть массивом, прежде чем я вызову метод, или я получу «ArgumentError: неверное количество аргументов» для всего, кроме одной пройденной вещи. Так это должно выглядеть так:
y [1,2,{:c=>3,:d=>4}]
... с хешем, явно созданным с помощью {}. И это безобразно.
Все вышеперечисленное проверено с помощью МРТ 1.8.6, кстати.