W Ruby
attr_accessor jest makrem (lub metodą) do automatycznego tworzenia getterów (metod dostępu do wartości) oraz setterów (metod ustawiających wartość) dla zmiennych instancji (instance variables) w klasie.
Na przykład:
class Cat
end
cat = Cat.new
cat.name # => no method error
Nie mamy metody
name w klasie
Cat. Oczywiście otrzymujemy no method error.
Spróbujmy dodać getter:
class Cat
def name
@name # zwraca zmienną instancji @name
end
end
cat = Cat.new
cat.name # => nil
Wygląda na to, że coś poszło nie tak. Ale wszystko jest w porządku. Getter cat.name zwraca nil. Już nie ma błędu 'no method error', czyli metoda istnieje i zwraca zmienną @name instancji Cat. Ale ta zmienna jest pusta. nil to oczekiwany wynik.
W Ruby
getter jest metodą, która pozwala uzyskać wartość zmiennej instancji (instance variable) w klasie. Gettery nazywają się tak, ponieważ pozwalają "uzyskiwać" (
get) wartość zmiennej.
W Ruby gettery są zazwyczaj używane do zapewnienia dostępu do wartości zmiennych z zewnątrz klasy, ponieważ zmienne są zazwyczaj prywatne (private) i niedostępne bezpośrednio. Gettery pozwalają zapewnić kontrolowany dostęp do tych wartości.
Próba użycia settera zwraca błąd no method error:
cat.name = 'Ruby'# => no method error
To też jest oczekiwany wynik. Nie mamy metody setter dla name.
W Ruby setter jest metodą, która pozwala ustawić wartość zmiennej instancji (instance variable) w klasie. Settery nazywają się tak, ponieważ pozwalają "ustawiać" (
set) (lub zmieniać istniejące) wartości zmiennej.
W Ruby settery są używane do kontrolowanego zmieniania wartości zmiennych z zewnątrz klasy.
class Cat
def name
@name # zwraca zmienną instancji @name
end
def name=(str)
@name = str
end
end
Stwórzmy instancję Cat i wywołajmy metodę name (getter):
cat = Cat.new
cat.name # => nil
Tu wszystko jest w porządku. Nasza instancja jest obecnie pusta. Musimy przekazać wartość za pomocą naszej nowej metody (settera).
cat.name = 'Ruby'
Nie widzimy żadnego błędu. Spróbujmy więc za pomocą getter metody wyciągnąć wartość:
cat.name # => Ruby
Wszystko działa. Ale wyobraź sobie, że twoja klasa ma nie tylko name, ale dziesiątki różnych atrybutów (wiek, kolor itd.). Pisanie getterów i setterów za każdym razem nie jest zbyt wygodne.
Dlatego w Ruby istnieją takie skróty (attr_reader i attr_writer):
class Cat
attr_reader :name
attr_writer :name
end
:name - nazwa atrybutu, dla którego tworzony jest metod.
attr_reader - to skrót dla metody getter:
def name
@name # zwraca zmienną instancji @name
end
attr_writer - to skrót dla metody setter:
def name=(str)
@name = str
end
Jednak gdy potrzebujemy obu metod - settera i gettera, attr_reader i attr_writer musimy powtarzać dla każdego atrybutu:
class Cat
attr_reader :name
attr_writer :name
attr_reader :color
attr_writer :color
end
To jest bardziej zwięzłe niż pisanie metod w całości, ale Ruby pozwala jeszcze bardziej skrócić ten kod. Tutaj potrzebujemy
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
Użycie
attr_accessor, attr_reader i attr_writer upraszcza tworzenie metod dostępu do zmiennych w klasach, co jest szczególnie wygodne, gdy potrzebujesz tylko po prostu uzyskać lub ustawić wartość zmiennej, bez dodatkowej logiki.
Ruby pozwala skrócić już to, co wydaje się, że już skróciłeś. Oto wersja skróconego zapisu atrybutów przez przecinek:
attr_reader :name, :color