All original content is created in Ukrainian. Not all content has been translated yet. Some posts may only be available in Ukrainian.Learn more

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

Post cover: module_function у Ruby: коли методи модуля доступні як модульні та як функції
Table of contentsClick link to navigate to the desired location
This content has not been translated yet.We're showing the original Ukrainian content below.
У Ruby модулі дозволяють організовувати код, але іноді потрібно, щоб метод був доступний як для екземплярів модуля, так і безпосередньо з модуля (як функція). Для цього використовується module_function.

Як працює module_function

  • Робить метод приватним для екземплярів модуля (про private читайте тут).
  • Додає також "модульну копію" методу, яку можна викликати без створення об’єкта.
module MathHelper
  def square(x)
    x * x
  end

  module_function :square
end
Тепер можна викликати метод безпосередньо через модуль:
MathHelper.square(5) # => 25
Або використовувати його всередині інших методів модуля (як приватний):
module MathHelper
  def cube(x)
    square(x) * x
  end

  module_function :cube
end

MathHelper.cube(3) # => 27

Особливості

Приватний для інстансів модуля:
include MathHelper
square(5) # => NoMethodError (бо square став приватним)
Підходить для утиліт
module_function часто використовують у "статичних утилітах", щоб не створювати об’єкт модуля для виклику функцій.
Якщо коротко:
  • module_function робить метод одночасно:
    • Приватним для інстансів (через include)
    • Доступним як функцію через модуль
MathHelper.square(5)  # працює
include MathHelper
square(5)             # помилка
Це зручно для модулів, які мають набір утиліт, як у стандартних бібліотеках Ruby (Math, Enumerable для прикладу).
Але якщо звернете увагу на пункт - приватним для інстансів (через include), то можете спитати, а що з extend та prepend (про ці методи писав тут)? 
  • Метод модуля стає приватним для екземплярів і доступним через сам модуль.
  • Виклик через include не працює напряму (метод приватний).
  • Виклик через extend працює як класовий метод.
  • Виклик через prepend не працює на об’єкті (метод приватний).
Все ще важко зрозуміти? Давайте розглянемо більш детально:
module_function робить дві речі одночасно:
  1. Приватним для екземплярів
    • Якщо ти включаєш модуль (include) або робиш prepend, метод стає приватним для всіх об’єктів, тобто ти не можеш викликати його просто так: obj.method - буде помилка.
    • Ruby так робить, щоб ви не змогли випадково викликати цей метод на екземплярі.
  2. Доступним через сам модуль
    • Ruby створює копію методу на рівні модуля.
    • Тому можна викликати: ModuleName.method - це працює як "статична функція".
Простий приклад:
module Utils
  def greet
    "Hello"
  end
  module_function :greet
end

# Через модуль можна
Utils.greet  # => "Hello"

# Через include — не можна, бо приватний
include Utils
greet        # => помилка NoMethodError
  • Чому extend працює?
    extend додає методи модуля у singleton class класу або об’єкта. Там метод викликається через клас/об’єкт, а не через екземпляр, тобто працює.
  • Чому prepend не працює?
    prepend вставляє метод у ланцюжок предків, але оригінальний метод залишається приватним -> об’єкт не може викликати його напряму.

This post doesn't have any additions from the author yet.

28 Oct 14:42

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

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

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

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що відбувається, якщо викликати [1, 2, 3].map(&Person)
29 Oct 17:54

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

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

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

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

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

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

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

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

Що таке memoization в Ruby?

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

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

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
&& vs and — різниця в Ruby, яка може зламати ваш код
30 Oct 20:23

&& vs and — різниця в Ruby, яка може зламати ваш код

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Змінні у Ruby: @, @@ та class instance variable
30 Oct 20:54

Змінні у Ruby: @, @@ та class instance variable

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Різниця між blank?, present?, empty? та nil? у Ruby
30 Oct 21:06

Різниця між blank?, present?, empty? та nil? у Ruby

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке Middleware у Ruby on Rails і коли воно використовується
04 Nov 10:39

Що таке Middleware у Ruby on Rails і коли воно використовується

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