|| = - обычная идиома Ruby: она присваивает значение только в том случае, если оно еще не установлено. Эффект такой же, как код, как
if some_variable == nil
some_variable = some_value
end
или
some_variable= some_value unless some_variable
===, когда он не переопределен, сравнивает два объекта идентичности. В случае Hash === args.last
, Hash (который является объектом типа Class) проверяет, соответствует ли он классу последнего элемента массива args. В коде используется очевидный факт, что реализация класса # === заставляет проверять класс сравниваемого объекта.
Это не работает наоборот, например:
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
EDIT: Расширение далее на * 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
... с помощью * арг вызывает арг быть представлен метод как массив. Если я не использую *, как это, например:
def y(args)
puts args.join(',')
puts args.map{|a| a.class }.join(',')
end
... то арг должен быть массив, прежде чем я называю метод, или я получаю «ArgumentError: неверное число аргументы "за что-то, кроме одного. Так что это должно выглядеть так:
y [1,2,{:c=>3,:d=>4}]
... с Хэшем, явно созданным с помощью {}. И это уродливо.
Все вышеперечисленное тестировалось с помощью МРТ 1.8.6, кстати.
Нет, проходя в массиве имеет смысл, так как арг не возвращается, так что в противном случае, добавочный Hash будет потерян. – rampion
Я не уверен, что понимаю: вы бы назвали метод следующим: some_method ([arg1, arg2, arg3], options_hash)? Это ужасно: см. Отредактированный ответ выше ... –
Отличное объяснение, Майк. –