Няколко полезни линка:
"You can convert a different class to a proc (if it supports it) by calling the to_proc method. If you use & on an object that is not a proc, Ruby will try to coerce that object into a block by calling the to_proc method."
"proc is a function that creates a new Proc object"
"If you put & in front of a Proc instance in the argument position, that will be interpreted as a block. If you combine something other than a Proc instance with &, then implicit class casting will try to convert that to a Proc instance using to_proc method defined on that object if there is any."
Подобни обяснения има и в Programming Ruby, която силно препоръчвам. :)
Иначе за да примера ти - ти подаваш на map
-а символ :Kon
, и руби "търси" такъв метод Kon
, но няма такъв - ти имаш клас Кон -> следователно излиза и грешката "undefined method 'Kon' for 1:Fixnum"
. И ако искаш все пак да заработи, to_proc
трябва да се извика на класа Kon
-> [1,2,3].map(&Kon)
, следователно самият ти клас Kon
трябва да има метод to_proc
:
class Kon
def self.to_proc
Proc.new { |x| puts "obicham kone #{x}" }
end
end
Така на Kon
се извиква to_proc
, а не на инстация от Kon
.
Резултатът е:
[1,2,3].map(&Kon)
obicham kone 1
obicham kone 2
obicham kone 3
# => [nil, nil, nil]
защото в крайна сметка блока за map-a принтира някакви неща и стойността на крайния израз е nil
.
И за край - аз най-просто го разбирам така - to_proc
кара нещо да се превърне/ да върне блок, за да може този блок да се използва от друг метод. Блокът, който връща to_proc
, е логично да приема някакви стойности, да прави нещо с тях и да връща резултат - и отделно този блок пък го подаваме на пример на map
. При Symbol
така е имплементирано, че когато напишем:
&:метод
, to_proc
връща Proc
, който приема обект obj
, аргументи **args
и на този обект му "изпраща" :метод
- obj.send(:метод, **args)
ПП. чак сега видях, че си направил инстанция на Kon
- moq_kon
, тогава за да работи map-ът трябва само да напишеш:
[1,2,3].map(&moq_kon)
и да не променяш to_proc
в класа.