Определение методов и аргументы

Метод — это именованный, переиспользуемый кусок кода. Освоив методы, вы перестаёте копировать логику и начинаете её называть.
Суть: метод объявляется через def; он может принимать позиционные и ключевые аргументы, давать им значения по умолчанию и неявно возвращает значение последнего выражения — без слова return.

Методы — основной способ структурировать программу. Главная рубишная особенность: значение возвращается автоматически — то, что вычислила последняя строка тела, и становится результатом. Явный return нужен лишь для раннего выхода.

def square(x)
  x * x        # неявный возврат — return не нужен
end
puts square(5)   # => 25

def greet(name, greeting = "Привет")  # значение по умолчанию
  "#{greeting}, #{name}!"
end
puts greet("Аня")              # => Привет, Аня!
puts greet("Иван", "Здравствуй")  # => Здравствуй, Иван!

Разбор: ключевые аргументы

Когда у метода много параметров, позиционные аргументы становятся загадкой: что значит true на третьем месте? Ключевые аргументы решают это — каждый параметр называется явно. Это современный рекомендуемый стиль.

def create_user(name:, role: :guest, active: true)
  "#{name} (#{role}), активен: #{active}"
end

puts create_user(name: "Аня", role: :admin)
# => Аня (admin), активен: true
puts create_user(name: "Гость")
# => Гость (guest), активен: true

Как работает под капотом

Когда вы вызываете метод, Ruby ищет его в объекте-получателе и его «цепочке предков» (об этом — в разделе ООП). Аргументы связываются с параметрами по правилам: сначала позиционные по порядку, затем ключевые по именам. Метод можно вызывать на любом объекте — даже на числе, потому что число тоже объект.

   square(5)
       |
       v
   связывание: x = 5
       |
       v
   тело: x * x  --> 25
       |
       v
   неявный возврат последнего выражения --> 25

   greet("Аня")
       |
   name = "Аня", greeting = "Привет" (дефолт)

Та же логика «функция с дефолтами и именованными аргументами» на Python:

# Та же логика на Python ▶
def create_user(name, role="guest", active=True):
    return f"{name} ({role}), активен: {active}"

print(create_user("Аня", role="admin"))
# Аня (admin), активен: True

Частые ошибки

  • Лишний return. Писать return x * x в конце метода — не ошибка, но не по-рубишному. Последнее выражение возвращается само.
  • Путать позиционные и ключевые. Если параметр объявлен как name:, вызывать нужно name: "Аня", а не просто "Аня".
  • Изменяемый объект как дефолт. Дефолт вычисляется при каждом вызове, так что в Ruby это менее опасно, чем в Python, но всё равно держите дефолты простыми.

Best practices

  • Когда параметров больше двух — переходите на ключевые аргументы: вызовы становятся самодокументированными.
  • Методы-предикаты (возвращающие true/false) называйте с ?: valid?, empty?.
  • Держите методы короткими — один метод, одна задача. Если метод не помещается на экран, его пора разбить.

Глубже: splat-операторы и гибкость аргументов

Система аргументов в Ruby гибче, чем кажется на первый взгляд, и стоит хотя бы узнать о её возможностях. Оператор-звёздочка *args собирает произвольное число позиционных аргументов в массив — так пишут методы, принимающие сколько угодно значений. Двойная звёздочка **opts делает то же самое с ключевыми аргументами, складывая их в хэш. Есть и оператор для блока — &block, который ловит переданный блок в переменную (об этом подробнее в теме блоков). Комбинируя их, можно написать «прозрачную обёртку», которая принимает любые аргументы и передаёт их дальше нетронутыми — для этого в современном Ruby есть даже специальный оператор «передать всё» (...). Знать эти инструменты на старте необязательно, но полезно понимать: когда вы видите в чужом коде * и ** в сигнатуре метода — это не магия, а способ принимать переменное число аргументов. По мере роста ваших программ вы сами начнёте к ним тянуться, особенно когда будете писать методы, оборачивающие другие методы.

Итог. Методы объявляются через def и неявно возвращают последнее выражение. Ключевые аргументы делают вызовы читаемыми и являются современным стандартом, а имя с ? сигнализирует о предикате.

Проверьте себя
1. Что возвращает метод в Ruby, если в нём нет слова return?
Anil
BЗначение последнего вычисленного выражения
CОшибку
DИмя метода
2. Как объявить ключевой (именованный) аргумент с дефолтом в Ruby?
Adef m(role = :guest)
Bdef m(role: :guest)
Cdef m(:role)
Ddef m(role => :guest)