이들은 인스턴스 변수의 getter 및/또는 setter 메서드를 자동으로 생성하는 Ruby 메서드입니다 — 상용구를 없앱니다. 인스턴스 변수(@name)는 비공개라서 외부에서 직접 접근할 수 없으므로, 이를 읽고 쓰려면 접근자 메서드가 필요하며, attr_*는 이를 간결하게 생성합니다.
해결하는 문제
()
= name
()
= value
class Person
attr_reader :name # getter만 생성 (읽기 전용): person.name
attr_writer :email # setter만 생성 (쓰기 전용): person.email = ...
attr_accessor :age # getter와 setter 모두 생성: person.age / person.age = ...
def initialize(name, age)
@name = name
@age = age
end
end
person = Person.new("Ann", 30)
person.name # "Ann" — reader
person.age = 31 # writer
person.age # 31 — reader
person.name = "X" # ❌ NoMethodError — name은 읽기 전용 (attr_reader, setter 없음)
attr_reader → getter만 (읽기 전용 접근).attr_writer → setter만 (쓰기 전용).attr_accessor → getter와 setter 모두 (읽기-쓰기).각각은 인스턴스 변수를 명명하는 symbol을 받아 해당 메서드를 자동 생성합니다 — 한 줄이 여러 수동 메서드 정의를 대체합니다.
class BankAccount
attr_reader :balance # ✅ balance는 읽을 수 있지만 직접 설정은 불가 (보호)
def initialize
@balance = 0
end
def deposit(amount) # 변경은 원시 setter가 아닌 제어된 메서드를 통함
@balance += amount if amount > 0
end
end
임의로 설정되어선 안 되는 필드에 (attr_accessor 대신) attr_reader를 선택하는 것은 좋은 캡슐화입니다 — 의도한 접근만 노출합니다.
attr_accessor/attr_reader/attr_writer를 이해하는 것은 기본적인 일상 Ruby 지식입니다. 이들은 거의 모든 Ruby 클래스에 등장하기 때문입니다.
이들이 존재하는 핵심 이유: 인스턴스 변수(@name)는 비공개이며 외부에서 직접 접근할 수 없으므로, 이를 읽거나 쓰려면 접근자 메서드가 필요한데 — 모든 속성에 대해 이 getter/setter를 수동으로 작성하는 것은 지루한 상용구입니다.
이 메서드들은 접근자를 자동으로 생성(attr_reader는 읽기 전용, attr_writer는 쓰기 전용, attr_accessor는 둘 다)하여, 여러 메서드 정의를 한 줄의 간결한 코드로 대체합니다 — Ruby의 우아함과 간결함을 상징합니다.
각각이 무엇을 생성하는지 이해하고 적절한 것을 선택하는 것은 좋은 캡슐화의 문제이기도 합니다: 외부에서 임의로 설정되어선 안 되는 필드에는 attr_reader(읽기 전용)를, 읽기-쓰기 접근이 진정으로 의도된 곳에만 attr_accessor를 사용하여 객체 상태가 어떻게 노출되는지를 제어합니다(예: 은행 잔액을 읽을 수는 있지만 제어된 메서드를 통해서만 변경 가능하게 만들기).
이 접근자들은 Ruby 클래스(그리고 Rails 모델)에 어디에나 있으므로, 동작 방식·각각의 생성물·적절한 캡슐화를 위한 선택법을 아는 것은 Ruby 클래스를 작성하고 읽는 데 필수적이고 반드시 알아야 할 지식입니다 — Ruby 클래스를 정의할 때 가장 먼저 접하게 되는 것 중 하나이며, 흔한 요구(객체 상태에 대한 제어된 접근)에 대한 이 언어의 간결하고 표현력 있는 접근법을 반영합니다.