Include, extend і prepend у Ruby

текст перекладу
Є три способи додавання методів з модуля до класу в Ruby.

Include

Цей метод додає методи як методи екземплярів

module Swimmable  
 def swim  
 "I can swim!"  
 end  
end  

class Fish  
 include Swimmable  
end  

fish = Fish.new  
puts fish.swim # => "I can swim!"  
puts Fish.ancestors # => [Fish, Swimmable, Object, Kernel, BasicObject]

Extend

Цей метод додає методи як методи класу

module Flyable  
 def fly  
 "I can fly!"  
 end  
end  

class Bird  
 extend Flyable  
end  

puts Bird.fly # => "I can fly!"  
puts Bird.ancestors # => [Bird, Object, Kernel, BasicObject]

Prepend

Цей метод додає методи як методи екземплярів, але з вищим пріоритетом.

module Logger  
 def log_action  
 "Logged: #{super}"  
 end  
end  

class Action  
 prepend Logger  

 def log_action  
 "Some action"  
 end  
end  

action = Action.new  
puts action.log_action # => "Logged: Some action"  
puts Action.ancestors # => [Logger, Action, Object, Kernel, BasicObject]

Зазвичай, prepend визначається в кінці визначення класу.

Ви також можете prepend модуль поза визначенням класу

Action.prepend(Logger)

Послідовні prepend

module Formatter  
 def display  
 "Formatted: #{super}"  
 end  
end  

module Validator  
 def display  
 "Validated: #{super}"  
 end  
end  

class Report  
 prepend Formatter  
 prepend Validator  

 def display  
 "Report content"  
 end  
end  

report = Report.new  
puts report.display # => "Validated: Formatted: Report content"  
puts Report.ancestors # => [Validator, Formatter, Report, Object, Kernel, BasicObject]

Коли є кілька prepend, перший пошук здійснюється від останнього prepend.

Тому потік пошуку виглядатиме наступним чином.
prepend(n) -> prepend(n-1) -> class -> include(n) -> include(n-1)

Prepend використовується для вставки методів модуля на початку ланцюга пошуку методів класу, до методів самого класу. Це означає, що коли викликається метод, Ruby спочатку шукає його в препендованому модулі, а потім у самому класі.

Обгортка/Декорація методів

  • Ідеально підходить для додавання поведінки перед/після існуючих методів
  • Зазвичай використовується для логування, валідації, форматування тощо.
  • Препендований метод може отримати доступ до оригінального методу через super

Перевизначення методу з доступом до оригіналу

  • На відміну від звичайного перевизначення методу, prepend дозволяє вам перевизначити метод і водночас отримати доступ до оригінального методу
  • Корисно для модифікації значень, що повертаються, при збереженні оригінальної логіки

Множинна обробка шарів

  • Можна ланцюжити кілька препендованих модулів
  • Кожен модуль може обробляти результат наступного в ланцюгу
  • Чудово підходить для побудови конвеєрів обробки

Налагодження та моніторинг

  • Можна вставити код для налагодження без змін оригінальних класів
  • Корисно для моніторингу продуктивності, відстеження викликів методів

Розширення фреймворків

  • Дозволяє фреймворкам змінювати основну поведінку, зберігаючи доступ до оригінальних методів
  • Може використовуватися для безпечного додавання функціональності до сторонніх гемів

Перекладено з: Include, extend and prepend in Ruby

Leave a Reply

Your email address will not be published. Required fields are marked *