Що відбувається, якщо викликати [1, 2, 3].map(&Person)

Обкладинка допису: Що відбувається, якщо викликати [1, 2, 3].map(&Person)
ЗмістНатисність на посилання, щоб перейти до потрібного місця
На перший погляд, такий код здається дивним - ми ж зазвичай пишемо map(&:to_s) або map { |x| ... }. Але Ruby дозволяє передавати не тільки символи, а й будь-які об’єкти після &, якщо вони можуть перетворитися на Proc через метод to_proc.
Коли Ruby бачить &Person, він викликає: Person.to_proc
Тобто намагається перетворити Person на об’єкт Proc.
Отриманий об’єкт Proc використовується як блок для методу map.
Далі Ruby для кожного елемента масиву викликає цей Proc - proc.call(element)
Приклад
class Person
  def initialize(name)
    @name = name
  end

  def self.to_proc
    ->(name) { new(name) }
  end
end

people = ["Bant", "Yuki", "Beanie"].map(&Person)
p people
Результат:
[#<Person:0x0000000103f2b3a8 @name="Bant">,
 #<Person:0x0000000103f2b0b0 @name="Yuki">,
 #<Person:0x0000000103f2adb8 @name="Beanie">]
Що реально відбувається під капотом?
Ruby викликає ваш Person.to_proc, який повертає лямбду:
->(name) { Person.new(name) } # зверніть увагу, що в методі ми пропустили Person (не обов'язково вказувати))
І потім фактично виконує те саме, що:
["Oleh", "Ira", "Marta"].map { |name| Person.new(name) }

Як працює .call?

Кожен Proc або lambda має метод .call, який запускає збережений всередині код. Тобто коли Ruby робить proc.call(element), він фактично виконує ваш блок:
my_proc = ->(x) { puts "Hello, #{x}" }
my_proc.call("Ruby")  # => "Hello, Ruby"
Якщо коротко:
  • &obj у Ruby → викликає obj.to_proc.
  • Результат має бути Proc або lambda.
  • Потім Ruby викликає proc.call(x) для кожного елемента.
  • Тому map(&Person) працює, якщо клас має метод self.to_proc.
Останній пункт розглянемо трохи детальніше. Якщо клас немає методу .to_proc - очікуйте на помилку. Чому?
[1, 2, 3].map(&123)
Що робить Ruby:
  1. бачить &123
  2. думає: “ага, треба викликати 123.to_proc”
  3. але в числа (Integer) немає методу to_proc
  4. отже - помилка
irb(main):001> 123.to_proc
(irb):1:in `<main>': undefined method `to_proc' for 123:Integer (NoMethodError)

123.to_proc
   ^^^^^^^^
Did you mean?  to_r
	from /Users/mykyta/.rbenv/versions/3.2.1/lib/ruby/gems/3.2.0/gems/irb-1.15.2/exe/irb:9:in `<top (required)>'
	from /Users/mykyta/.rbenv/versions/3.2.1/bin/irb:25:in `load'
	from /Users/mykyta/.rbenv/versions/3.2.1/bin/irb:25:in `<main>'
irb(main):002> 

Цей допис поки що не має жодних доповнень від автора/ки.

Як працюють масиви в Ruby: практичні приклади each, map, select, inject, reduce, filter_map
28 жовт., 10:38

Як працюють масиви в Ruby: практичні приклади each, map, select, inject, reduce, filter_map

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Як працює self, protected і private (Ruby)
28 жовт., 13:52

Як працює self, protected і private (Ruby)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1
28 жовт., 14:10

Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
28 жовт., 14:42

Як працює &:to_s у Ruby і що таке Symbol#to_proc

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке Proc і Lambda в Ruby?
28 жовт., 15:57

Що таке Proc і Lambda в Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Singleton class (eigenclass) у Ruby: що це і навіщо потрібно
29 жовт., 18:29

Singleton class (eigenclass) у Ruby: що це і навіщо потрібно

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати
29 жовт., 20:47

==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця
29 жовт., 21:20

Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
module_function у Ruby: коли методи модуля доступні як модульні та як функції
29 жовт., 21:53

module_function у Ruby: коли методи модуля доступні як модульні та як функції

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке memoization в Ruby?
30 жовт., 10:17

Що таке memoization в Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
is_a?, kind_of?, instance_of? — як Ruby перевіряє тип об’єкта?
30 жовт., 19:55

is_a?, kind_of?, instance_of? — як Ruby перевіряє тип об’єкта?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska