5 przykładów najlepszego wykorzystania Rubiego
Czy kiedykolwiek zastanawiałeś się, co możemy zrobić z Ruby? Cóż, niebo jest prawdopodobnie granicą, ale chętnie porozmawiamy o kilku mniej lub bardziej znanych przypadkach...
Zanim zaczniemy tworzyć metodę bang, dowiedzmy się czym dokładnie jest tego typu metoda i jakie są jej cechy charakterystyczne. Zacznijmy od tego, że nie ma jednoznacznej definicji tego typu metod. Mówiąc najprościej, metoda bang to metoda z wykrzyknikiem na końcu.
Często możemy spotkać się ze stwierdzeniem, że metoda bang jest w pewnym sensie metodą niebezpieczną, a wykrzyknik na końcu jej definicji każe nam zachować czujność podczas korzystania z tej metody. Zobaczmy: czym dokładnie jest to zagrożenie, jeśli chodzi o te metody i jakie są ich cechy?
Jedną z najpopularniejszych cech tego typu metod jest to, że zazwyczaj zmieniają one swoich odbiorców. Przyjrzyjmy się metodzie map! jako przykładowi. Zgodnie z dokumentacją, metoda map! wywołuje podany blok raz dla każdego elementu self, zastępując element wartością zwróconą przez blok, a jeśli nie podano bloku, zamiast niego zwracany jest enumerator.
arry = [1, 2, 3, 4, 5]
arry.object_id => 280
arry.map! {|num| num**num } => [1, 4, 27, 256, 3125]
arry.map! => #
arry.map! {|n| n } => [1, 4, 27, 256, 3125]
arry.object_id => 280
Jak widzimy, object_id pozostaje niezmieniony. Niebezpieczeństwo korzystania z takiej metody wydaje się więc oczywiste. Jeśli w naszym kod użyliśmy zmiennej arry gdziekolwiek indziej, to map! ją zmieni. Może to doprowadzić do tego, że nasz program będzie działał w niepożądany sposób lub nawet się zawiesi.
Istnieją obiekty w Ruby których nie można zmienić, takich jak instancje klas Integer, Float i Symbol. Podczas pracy nad klasą projektMożna również spotkać się z tak zwanym magicznym komentarzem, który brzmi następująco:
frozenstringliteral: true
Próba zmiany odbiorcy String w kodzie, w którym użyto takiego komentarza, spowodowałaby błąd taki jak ten:
'abc'.upcase!
FrozenError (nie można modyfikować zamrożonego ciągu)
Co ciekawe, istniały plany wprowadzenia niezmiennego Stringa w Ruby 3.0ale postanowiono nie wprowadzać tej zmiany. Należy jednak pamiętać, że nie wszystkie metody bang zmieniają odbiorcę, więc zawsze należy sprawdzić w dokumentacji, jakiego rodzaju niebezpieczeństwa należy się spodziewać w przypadku konkretnej metody.
Inną charakterystyczną cechą tych metod jest to, że dla wielu z nich zgłaszany jest wyjątek. Przykładem takiej metody jest ActiveRecord::FinderMethods#first! Zgodnie z dokumentacją, metoda first! jest taka sama jak first, ale zgłasza ActiveRecord::RecordNotFound, jeśli nie znaleziono żadnego rekordu. Zauważ, że first! nie przyjmuje żadnych argumentów.
Plik activerecord/lib/activerecord/relation/findermethods.rb, linia 128
def first!
first || raiserecordnotfoundexception!
end
Jednak metoda ActiveRecord::FinderMethods#first, która jest używana powyżej, wygląda następująco:
Plik activerecord/lib/activerecord/relation/findermethods.rb, linia 116
def first(limit = nil)
checkreorderdeprecation unless loaded?
if limit
findnthwithlimit(0, limit)
else
findnth 0
end
end
Dzięki powyższym przykładom widzimy niebezpieczeństwo korzystania z tego pierwszego. Jeśli użyjemy ActiveRecord::FinderMethods#find! i nie znajdzie on odpowiedniego rekordu w bazie danych, to zwróci ActiveRecord::RecordNotFound, co może spowodować, że nasz program przestanie działać.
Musimy jednak pamiętać, że nie oznacza to, że jeśli metoda nie ma wykrzyknika na końcu, to jest bezpieczna i nie zgłosi wyjątku ani nie zmieni odbiorcy.
Nowa para metod została wprowadzona w Ruby on Rails 6.0: ActiveRecord::Persistence::ClassMethods#insert_all
i ActiveRecord::Persistence::ClassMethods#insert_all!
Już pierwsza z tych metod wskazuje na pewien stopień niebezpieczeństwa. Otóż, zgodnie z dokumentacją, insertwstawia wiele rekordów do bazy danych w pojedynczej instrukcji SQL INSERT. Nie tworzy instancji żadnych modeli ani nie uruchamia wywołań zwrotnych ActiveRecord ani walidacji. Jednak instrukcja insertall! dodatkowo zgłasza ActiveRecord::RecordNotUnique, jeśli jakiekolwiek wiersze naruszają unikalny indeks tabeli. W takim przypadku żadne wiersze nie zostaną wstawione. Oznacza to, że pierwsza z tych metod zapisze wszystkie rekordy z wyjątkiem tych, które naruszają unikalny indeks, podczas gdy druga (bardziej niebezpieczna) metoda zgłosi wyjątek i nie zapisze żadnego z rekordów do bazy danych.
Wiele metod, nawet jeśli nie mają wykrzyknika na końcu, jest niebezpiecznych w użyciu. Na przykład ActiveRecord::FinderMethods#find. Zgodnie z dokumentacją, jeśli nie można znaleźć jednego lub więcej rekordów dla żądanych identyfikatorów, zostanie wyświetlony komunikat ActiveRecord::RecordNotFound.
Widzimy, że chociaż ta metoda ma taki sam stopień zagrożenia jak ActiveRecord::FinderMethods#first!, nie ma wykrzyknika.
To samo dotyczy modyfikowania odbiorcy. Na przykład, Array.delete (zgodnie z dokumentacją) usuwa wszystkie elementy z self, które są równe object i zwraca ostatni usunięty element lub nil, jeśli nie znaleziono pasujących elementów.
a = [1, 2, 3, 4, 5]
a.object_id #=> 320
a.delete(2) #=> 2
a #=> [1, 3, 4, 5]
a.delete(6) #=> nil
a.object_id #=> 320
Widać wyraźnie, że obiekt został zmodyfikowany. Wspólną cechą obu metod jest to, że nie mają one odpowiednika w postaci wykrzyknika. Dlatego też, jeśli metoda, którą chcemy utworzyć, miałaby tego rodzaju zagrożenia, o których wspomniałem powyżej, nie musi od razu mieć wykrzyknika na końcu. Co więcej, zaleca się utworzenie metody bang, jeśli istnieje już metoda o tej samej nazwie, która jest mniej niebezpieczna niż metoda, którą chcemy utworzyć.
Można się zastanawiać, po co w ogóle używać tych niebezpiecznych metod, zwłaszcza że zazwyczaj mamy mniej niebezpieczne odpowiedniki. Jedną z zalet może być na przykład poprawa wydajności kodu dzięki zmniejszeniu liczby tworzonych obiektów. Tutaj możesz przeczytać więcej o zwiększaniu wydajności Railsów.
Jeśli chodzi o zgłaszanie wyjątków, to użycie metody create zamiast niebezpiecznej create! może doprowadzić do sytuacji, w której błąd w naszej aplikacji będzie trudny do wykrycia, ponieważ rekordy nie zostaną zapisane w bazie danych. Jeśli więc jesteśmy pewni, że parametry, które przekazujemy do tej metody są poprawne, powinniśmy użyć metody create!, która zgłosi wyjątek, jeśli z jakiegoś powodu rekord nie zostanie zapisany w bazie danych.
Wniosek jest prosty i brzmi następująco: rozważne korzystanie z takich metod może poprawić wydajność i jakość naszego kodu. Musimy jednak zawsze pamiętać, że ich niewłaściwe użycie może uniemożliwić poprawne działanie kodu.
Jeśli chcesz stworzyć własną niebezpieczną metodę, musisz przejść przez pewien proces decyzyjny. Po pierwsze, należy zadać sobie pytanie, czy istnieje już metoda o takiej samej nazwie jak ta, którą chcemy stworzyć, ale mniej niebezpieczna. Można również rozważyć utworzenie pary metod, w której jedna z nich jest równoważna drugiej, tylko bardziej niebezpieczna.
Nie ma sensu tworzyć metody bang, jeśli jej odpowiednik bez wykrzyknika nie istnieje. Istnieją metody, które są niebezpieczne, ponieważ zmieniają obiekt lub podnoszą wyjątek, a mimo to nie mają wykrzyknika na końcu nazwy. Stworzenie metody bang bez odpowiednika zmyliłoby programistę korzystającego z kodu. Osoba ta nie byłaby w stanie powiedzieć, na czym polega niebezpieczeństwo tej metody i dlaczego zasługuje ona na wykrzyknik na końcu nazwy.
Po drugie, powinniśmy zastanowić się, o jakiego rodzaju zagrożeniach mówimy. Z powyższych przykładów możemy wywnioskować, że najczęstszym typem zagrożenia jest zmiana samego obiektu (zamiast tworzenia jego kopii) lub podniesienie wyjątku. Oczywiście nie jest to reguła, a raczej wynik analizy metod, które zostały zdefiniowane w Ruby i Ruby on Rails. Dla przykładu, możemy rozważyć implementację pary metod, w której metoda bez znaku wykrzyknik zapisałaby rekord w bazie danych, podczas gdy metoda z wykrzyknikiem pominęłaby walidację tego rekordu. W tym przypadku jasne jest, gdzie leży potencjalne niebezpieczeństwo korzystania z takich metod.
Podsumowanie wiedzy na temat metod hakerskich prowadzi do następujących wniosków: 1. metoda z wykrzyknikiem ma mniej groźny
po drugie, metoda z wykrzyknikiem wykonuje niebezpieczną akcję, np. modyfikuje odbiorcę lub zgłasza wyjątek.
Podsumowując, zrozumienie koncepcji metody hukowe w Ruby rozwój oprogramowania może znacznie poprawić umiejętności kodowania i zapewnić większą przejrzystość bazy kodu. Metody Bang, oznaczone wykrzyknikiem na końcu ich nazw, wskazują destrukcyjną lub potencjalnie niebezpieczną wersję metody. Zgodnie z konwencją bang odpowiednik metody należy używać ostrożnie, ponieważ może ona modyfikować obiekty bezpośrednio, bez tworzenia oddzielnej kopii. Może to być szczególnie przydatne, gdy mamy do czynienia ze zmiennymi obiektami lub gdy zależy nam na optymalizacji wydajności. Ważne jest jednak, aby zachować ostrożność podczas korzystania z metod bang, ponieważ mogą one mieć niezamierzone konsekwencje, jeśli nie są odpowiednio obsługiwane. Warto również zauważyć, że nie wszystkie metody mają atrybut wersja banga ich obecność powinna być oceniana indywidualnie dla każdego przypadku. Wiedząc, kiedy i jak tworzyć metody bang, możesz skutecznie posługiwać się tym potężnym narzędziem i pisać czysty, wydajny kod, który spełnia określone wymagania.