mam dwa modele, Gallery może mieć przypisany katalog obrazków PicsDir.
PicsDir został stworzony żeby odseparować kod odpowiedzialny za operacje na plikach zdjęć.
Kod symulujący powiązanie w uproszczeniu wygląda tak:
def pics_dir
# tutaj nie trzeba self
return unless pics_dir_name
PicsDir.new(pics_dir_name)
end
def pics_dir= pics_dir_obj
# tutaj trzeba self
self.pics_dir_name= pics_dir_obj.name
end
end[/code]
pics_dir.rb
[code]class PicsDir
attr_reader :name
def initialize name @name = name
end
end[/code]
I w zasadzie już nie ma problemu, bo po dopisaniu selfa do metody “pics_dir=” wszystko działa.
Nie działało w postaci:
def pics_dir= pics_dir_obj
pics_dir_name= pics_dir_obj.name
end
Chciałbym to jednak zrozumieć Czy ktoś może mi wytłumaczyć dlaczego muszę używać self razem z “pics_dir_name=” (wewnątrz “def pics_dir=”) a nie muszę używać z “pics_dir_name” (wewnątrz “def pics_dir”)?
Dlatego, że pics_dir_name = ...
wygląda dla Rubiego na przypisanie do zmiennej lokalnej pics_dir_name
.
Natomiast w kodzie pics_dir
odwołujesz się do zmiennej lub metody, a ponieważ taka zmienna lokalna nie była zadeklarowana, to odszukuje on metodą pics_dir_name
.
Inna sprawa, że chyba sensowniej w obu przypadkach byłoby użyć @pics_dir_name.
Przy przypisaniu wartości nie możesz pominąć self, tak jak powiedział apohllo. Wiąże się to z tym, że nie byłoby to jednoznaczne dla interpretera co zrobić: wysłać wiadomość do bieżącego obiektu czy ustawić zmienną lokalną. W przypadku wywołania metody nie będącej setterem, sprawa jest łatwiejsza: najpierw sprawdzane jest czy nie ma zmiennej lokalnej, jeśli nie ma, wywoływana wysyłana jest wiadomość do obiektu.
Gwoli czystości kodu: sensownie jest pomijać self. wszędzie gdzie jest to możliwe. Czyli stosować tylko przy wywołaniu setterów, albo w sytuacjach niejasnych, gdzie masz zmienną lokalną o takiej samej nazwie (chociaż jak głupie to jest to już pominę).
Rozwinę też drugą kwestię wspomnianą przez apohllo: raczej można ominąć tu attr_accessor i dobrać się do zmiennych instancji bezpośrednio, przez @zmienna. Dlaczego? Bo do tego są zmienne instancji aby bieżący obiekt z nich mógł korzystać swobodnie. Są 2 wyjątki: a) kiedy chcesz umożliwić ustawianie / pobieranie wartości zmiennej przez inne obiekty (wtedy używasz attr_accessor), b) jeśli pobieranie/ustawianie wartości wiąże się z dodatkowymi czynnościami, typu konwersja typów czy logowanie danych (wtedy piszesz własne gettery/settery).
Dopisując: Jeśli przy przypisaniu nie użyjesz self, to Ruby uzna, tak jak napisał apohllo, że jest to przypisanie zmiennej lokalnej - i jeśli w tym samym scope będziesz chciał użyć pics_dir_name, Ruby zwróci Ci świeżo przypisaną zmienną lokalną, a do “prawdziwej” metody pics_dir_name będziesz musiał odwoływać się również za pomocą self, co rodzi jeszcze większy chaos jeśli ta metoda jest prywatna…
Generalnie zatem należy unikać takiego bałaganu w nazwach.
uświadomiłem sobie, że w modelach ActiveRecord używałem zawsze akcesorów zamiast prostszej notacji z małpą.
Chyba oczekiwałem, że oprócz zwykłego podstawiania wartości dzieje się też jakaś magia :).