Статьи

Инста-блок с символом # to_proc

То, что могло бы подсунуть ваш радар в ваших чтениях на Ruby, это Symbol#to_proc , то, что было в Rails с 0.14.4.

Используя этот приятный маленький кусочек Ruby tricky, вы можете упростить код, такой как:

 articles.collect { |a| a.title } articles.sort { |a| a.created_at } 

в

 articles.collect(&:title) articles.sort(&:created_at) 

… и на тот случай, если вам интересно, почему &:ruby_is_the_new_black не работает в прекрасном сценарии оболочки ruby, который вы только что написали, потому что Symbol#to_proc не является стандартным Symbol#to_proc Ruby. Процитирую Маурисио Фернандеса, который отметил, что он недавно включен в готовящийся Ruby 1.9 :

Символ # to_proc: впервые обнаружен неким анонимным японским Rubyist (довольно уверенным), вновь обнаруженным Флорианом Гроссом (я видел это, когда я тратил свое время на # ruby-lang), затем популяцией, разгромленной Pragdave и Rails, наконец, официально принятой. Это был долгий путь.

«Это хорошо, — говорите вы, — но я до сих пор не совсем понимаю, о чем весь этот Proc и блочные вещи». Что ж, позвольте мне побаловать вас некоторыми бормотаниями в Ruby.

Я думаю, что лучший способ описать блок, если вы пришли из web-design-land — это думать о нем как о анонимной функции в Javascript.

Например, следующий кусок Ruby:

 socceroos.each do |s| s.congratulate end 

эквивалентно следующему Javascript:

 socceroos.each(function(s) { s.congratulate(); }) 

Блок, переданный функции, обозначается амперсандом:

 class Team def each(&block) for player in @players block.call(player) end end end 

Фактически, вышеописанный шаблон вызова блока настолько распространен, что Ruby делает еще один шаг вперед, позволяя просто написать:

 class MyTeam def each for member in @members yield member end end end 

yield member — это еще один способ сказать «вызвать связанный блок, передав ему член». Вам даже не нужно добавлять &block список параметров.

Вы бы видели этот шаблон при работе с ActiveRecord. Класс ActiveRecord::Base позволяет вам указать блок при создании новых экземпляров. Например, если Player был подклассом ActiveRecord, вы можете сделать следующее:

 @player = Player.new do |p| p.name = "Ronaldo" p.nickname = "Porky" end 

Как ActiveRecord предоставляет этот аккуратный API? Легко! Он просто проверяет, был ли указан блок, и, если это так, вызывает блок, передавая ему новый объект Player.

Минимальная логика для достижения этой цели:

 class ActiveRecord::Base def initialize yield self if block_given? end end