Що таке attr_accessor, attr_reader та attr_writer у Ruby? Для чого вони потрібні?

У Ruby attr_accessor є макросом (або методом) для автоматичного створення геттера (методу доступу до значення) та сеттера (методу встановлення значення) для інстансних змінних (instance variables) в класі.

Наприклад:

class Cat
end

cat = Cat.new
cat.name # => no method error

Ми не маємо методу name у класі Cat. Вочевидь ми отримуємо no method error.

Спробуємо додати геттер:

class Cat
  def name
    @name # повертає змінну екземпляра @name
  end
end

cat = Cat.new
cat.name # => nil

Здається, що щось пішло не так. Але все правильно. Геттер cat.name повертає nil. Вже немає помилки 'no method error', тобто метод існує, та повертає змінну @name екземпляра Cat. Але ця змінна пуста. nil - це очікуємий результат.

У Ruby геттер є методом, який дозволяє отримати значення інстансної змінної (instance variable) в класі. Геттери називаються так, оскільки вони дозволяють "отримувати" (get) значення змінної.

У Ruby геттери зазвичай використовуються для забезпечення доступу до значень змінних ззовні класу, оскільки змінні зазвичай є приватними (private) і недоступними безпосередньо. Геттери дозволяють забезпечити контрольований доступ до цих значень.

Cпроба використати сеттер видає помилку no method error:

cat.name = 'Ruby'# => no method error

Це теж очікуємий результат. Ми не маємо сеттер методу для name.

У Ruby сеттер є методом, який дозволяє встановити значення інстансної змінної (instance variable) в класі. Сеттери називаються так, оскільки вони дозволяють "встановлювати" (set) (або змінювати існуючі) значення змінної.

У Ruby сеттери використовуються для контрольованого змінювання значень змінних ззовні класу. 

class Cat
  def name
    @name # повертає змінну екземпляра @name
  end

  def name=(str)
    @name = str
  end
end

Cтворимо екземпляр Cat та викличемо метод name (геттер):

cat = Cat.new
cat.name # => nil

Тут все правильно. Наш екземпляр наразі пустий. Треба передати значення за допомогою нашого нового методу (сеттер).

cat.name = 'Ruby'

Ми не бачимо ніякої помилки. Тож спробуємо за допомого гетер методу витягнути значення:

cat.name # => Ruby

Все працює. Але уявіть, що у вашого класу не тільки name, а десятки різних атрібутів (вік, колір та інше). Кожного разу писати геттер та сеттер методи не дуже зручно.

Тож в Ruby є такі собі скорочення (attr_reader та attr_writer):

class Cat
  attr_reader :name
  attr_writer :name
end
 
:name - назва атрібуту, для якого створюється метод.

attr_reader - це скорочення для геттер методу:

def name
  @name # повертає змінну екземпляра @name
end

attr_writer - це скорочення для сеттер методу:

def name=(str)
  @name = str
end

Але коли нам потрібні обидва методи - сеттер та геттер, attr_reader та attr_writer треба дублювати їх для кожного атрібуту:

class Cat
  attr_reader :name
  attr_writer :name
  attr_reader :color
  attr_writer :color
end

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

class Cat
  attr_accessor :name
  attr_accessor :color
end

Рівноцінно запису:

class Cat
  attr_reader :name
  attr_writer :name
  attr_reader :color
  attr_writer :color
end

Використання attr_accessor, attr_reader та attr_writer спрощує створення методів доступу до змінних у класах, і це особливо зручно, коли вам потрібно лише просто отримати або встановити значення змінної, без додаткової логіки.

Ruby дозволяє скоротити вже те, що здається ти вже скоротив. Ось варіант скороченного запису атрибутів через кому:

attr_reader :name, :color
📝 Більше публікацій: