Metody
Znamy już kilka podstawowych typów danych, więc czas dowiedzieć się co można z nimi robić. A można bardzo dużo!
Co to jest metoda?
Metoda to wydzielona część kodu, będąca zbiorem wyrażeń, który zwraca pewną wartość. Od razu warto zauważyć, że metod możesz używać wielokrotnie. Zamiast zapisywać pewien ciąg operacji kilka(set) razy w kodzie, lepiej wydzielić je w metodę. Co więcej, metody mogą przyjmować pewne argumenty (obiekty) i zwracać wartość w zależności od nich.
Zapewne pamiętasz “magiczną linijkę” wypisującą podany tekst: puts “Your text”. Tak naprawdę ta linijka to wywołanie metody puts z argumentem “Your text”. Poznajmy nową metodę:
irb(main):001:0> "What is this?".include? "is" => true irb(main):002:0> "What’s that?".include? "is" => false
Metoda include? sprawdza czy jeden podany napis zawiera drugi. Zauważmy, że sposób wywołania tej metody (argument, kropka, nazwa_metody, (argument(y))) różni się od tego w metodzie puts (nazwa_metody, (argumenty)). Na szczęście, pomijając operatory (o których później) są to jedyne “sposoby” wywoływania metod w Rubym. Jedyne, z dokładnością do nawiasów. Argumenty metody mogą być ujęte w nawiasy (czasem muszą, ale ten wątek zostawimy na inną chwilę) lub nie. Wszystkie poniższe sposoby zapisu są poprawne:
#File: Methods.rb puts ”Hey” puts(”Hey”) "abcdefg".include? "a" "abcdefg".include?("a")
Definiowanie własnych metod
Często zdarza się, że język programowania w którym działamy nie posiada metody, której potrzebujemy (szczególnie, gdy jest osobliwa ;)). Możemy jednak zdefiniować własną:
#File: My_own_method.rb def about_me(name, fav_book, fav_actor) puts "My name is #{name}" puts "My favourite book is \"#{fav_book}\"" puts "My favourite actor is #{fav_actor}" end about_me "Janek", "Agile Web Development with Rails 4", "Nicolas Cage"
jan@Stacja-Linux ~/Pulpit $ ruby My_own_method.rb My name is Janek My favourite book is "Agile Web Development with Rails 4" My favourite actor is Nicolas Cage
Zastanówmy się teraz, co zostało zakodowane w pliku My_own_method.rb ;) Najpierw widzimy definicję metody. Ogólna składnia (czyli sposób zapisu) to:
def nazwa_metody(argumenty)
CIAŁO METODY
end
Zaczynamy od słowa kluczowego def, nazwy metody oraz jej argumentów w nawiasie lub bez (oczywiście możemy też zdefiniować funkcję bez argumentów). W następnych liniach zapisujemy “to” co metoda ma robić. W ostatniej linijce kończymy definicję słowem kluczowym end.
Zauważ, że ciało metody jest wcięte w stosunku do pierwszej i ostatniej linii definicji. Interpreter Ruby'iego nie zwraca uwagi na wcięcia (w przciwieństwie np. do Pythona), ale dzięki nim kod jest bardziej czytelny. Istotne są jednak znaki końca linii ("entery").
Każda metoda zwraca ostatnie przetworzone w niej wyrażenie (about_me zwraca nil). Poniżej pewien dający do myślenia przykład:
#File: My_own_methods.rb def potential_prime(n) 2**n-1 puts “Thanks for using my method!” end def potential_prime2(n) puts “Thanks for using my method!” 2**n-1 end puts potential_prime 5 puts potential_prime2 5
jan@Stacja-Linux ~/Pulpit $ ruby My_own_methods.rb Thanks for using my method! Thanks for using my method! 31
Metoda potential_prime oblicza wyrażenie 2**n-1, po czym wyświetla komunikat tekstowy. Ostatnim przetworzonym wyrażeniem jest wypisanie napisu, przez co metoda zwraca wartość nil (stąd pusta linijka po uruchomieniu programu). Metoda potential_prime2 robi to samo, ale w odwrotnej kolejności, dzięki czemu zwracana jest wartość o którą nam chodzi.
Argumenty metody w Rubym mogą mieć wartość domyślną (czyli taką, która zostanie wykorzystana, jeśli w wywołaniu metody nie będzie podanej innej wartości). Aby ją określić dopisz znak równości i wartość po nazwie argumentu:
#File: Default_parameter.rb def greetings(name="Anonymous") puts name end greetings greetings 'Janek'
jan@Stacja-Linux ~/Pulpit $ ruby Default_parameter.rb Anonymous Janek
Operatory
Operatory to jedno- lub wieloargumentowe konstrukcje zwracające pewną wartość. W Rubym operatory to tak naprawdę wywołania metod, ale ich specjalna składnia sprawia, że kod wygląda przejrzyściej. Poniżej krótki przegląd najważniejszych operatorów.
Operatory arytmetyczne
Spotkałeś/aś się z nimi już wcześniej. Jedyna “nowość” to operator %, który zwraca resztę z dzielenia. Tak przy okazji - w wyrażeniach arytmetycznych i logicznych możesz używać nawiasów ;):
#File: Arithmetic_operators.rb puts "5+2 = #{5+2}" puts "5-2 = #{5-2}" puts "5*2 = #{5*2}" puts "5/2 = #{5/2} r. #{5%2}" puts "5/2 = #{5.0/2.0}" puts "5**2 = #{5**2}" puts "(5+6)**2*(3+4) = #{(5+6)**2*(3+4)}"
jan@Stacja-Linux ~/Pulpit $ ruby Arithmetic_operators.rb 5+2 = 7 5-2 = 3 5*2 = 10 5/2 = 2 r. 1 5/2 = 2.5 5**2 = 25 (5+6)**2*(3+4) = 847
Operatory porównań
Ten typ operatorów też nie jest Ci już obcy. Zaliczamy do niego m. in. operatory: równe z (==), różne od (!=), większe niż (>), mniejsze niż (<), większe równe (>=), mniejsze równe (<=):
#File: Comparision_operators.rb puts "1==1 #{1==1}" puts "1!=1 #{1!=1}" puts "3>2 #{3>2}" puts "2>3 #{2>3}" puts "3>=3 #{3>=3}" puts "3<=2 #{3<=2}"
jan@Stacja-Linux ~/Pulpit $ ruby Comparision_operators.rb 1==1 true 1!=1 false 3>2 true 2>3 false 3>=3 true 3<=2 false
Operatory logiczne
Do operatorów logicznych zaliczamy m. in. and, or oraz not:
#File: Logical_operators.rb puts "true and true: #{true and true}" puts "true and false: #{true and false}" puts "false or false: #{false or false}" puts "false or true: #{false or true}" puts "not false: #{not false}" puts "not(true and false): #{not(true and false)}" puts "not((2>4) or (5==2+2)): #{not((2>4) or (5==2+2))}"
jan@Stacja-Linux ~/Pulpit $ ruby Logical_operators.rb true and true: true true and false: false false or false: false false or true: true not false: true not(true and false): true not((2>4) or (5==2+2)): true
Przegląd najważniejszych metod (i operatorów) dla typów liczbowych i tekstowego.
Liczby
Pomijamy operatory, których działanie dla liczb już analizowaliśmy.
Metoda | Opis |
---|---|
to_i | “Przerabia” podany obiekt na liczbę całkowitą. |
to_f | “Przerabia” podany obiekt na liczbę zmiennoprzecinkową. |
abs | Zwraca wartość absolutną podanej liczby. |
floor | Zwraca podłogę podanej liczby. |
ceil | Zwraca sufit podanej liczby. |
round(ndigits) | Zwraca zaokrąglenie podanej liczby do ndigits miejsc po przecinku. Argument ndigits może być ujemny! Domyślnie ndigits=0. |
Poniżej praktyczne spojrzenie na powyższe metody:
irb(main):001:0> "Text".to_i => 0 irb(main):002:0> "14".to_i => 14 irb(main):003:0> 123.456.to_i => 123 irb(main):004:0> 1.to_i => 1 irb(main):005:0> 1.to_f => 1.0 irb(main):006:0> -12.to_f => -12.0 irb(main):007:0> -12.abs => 12 irb(main):008:0> 3.14.abs => 3.14 irb(main):009:0> 3.14.floor => 3 irb(main):010:0> 3.14.ceil => 4 irb(main):011:0> 3.14159.round => 3 irb(main):012:0> 3.14159.round 4 => 3.1416 irb(main):013:0> 3.14159.round 2 => 3.14 irb(main):014:0> -123.14159.round => -123 irb(main):015:0> -123.14159.round 2 => -123.14 irb(main):016:0> -123.14159.round -1 => -120 irb(main):017:0> -123.14159.round -2 => -100
Napisy
Metoda | Opis |
---|---|
to_s | “Przerabia” podany obiekt na napis. |
+ | Łączy podane napisy. |
* | Powiela podany napis. |
capitalize | Zwraca kopię napisu, zamieniając pierwszą literę na wielką literę. |
downcase | Zwraca kopię napisu, zamieniając wszystkie litery na małe litery. |
upcase | Zwraca kopię napisu, zamieniając wszystkie litery na wielkie litery. |
count(other_str) | Zwraca ilość wystąpienia napisu other_str w napisie. |
gsub(pattern, replacement) | Zwraca kopię napisu z zamienionymi wystąpieniami pattern na replacement. |
reverse | Zwraca odwrócony napis. |
chomp | Usuwa białe znaki z końca napisu. |
Poniżej powyższe metody w przykładach:
irb(main):001:0> "abc".to_s => "abc" irb(main):002:0> -12.5.to_s => "-12.5" irb(main):003:0> "Nicolas "+"Cage" => "Nicolas Cage" irb(main):004:0> "Nicolas Cage "*10 => "Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage Nicolas Cage " irb(main):005:0> "university of Warsaw".capitalize => "University of warsaw" irb(main):006:0> "Hi!".capitalize => "Hi!" irb(main):007:0> "PoKeMoN!".downcase => "pokemon!" irb(main):008:0> "PoKeMoN!".upcase => "POKEMON!" irb(main):009:0> "An Anaconda".count("a") => 2 irb(main):010:0> "An Anaconda".count("n") => 3 irb(main):011:0> "An Anaconda".count("r") => 0 irb(main):011:0> "I really like Python, because Python is simple".gsub("Python", "Ruby") => "I really like Ruby, because Ruby is simple" irb(main):012:0> "I really like Python, because Python is simple".gsub("C++", "Java") => "I really like Python, because Python is simple" irb(main):013:0> "stressed".reverse => "desserts" irb(main):013:0> "new line\n".chomp => "new line"
Metody “uniwersalne”
Istnieją metody, których działanie nie jest ograniczone do jednego typu danych. Poznaliśmy już jedną taką metodę - puts. Za jej pomocą możemy wypisać zarówno napis jak i liczbę (a nawet typ logiczny i nil). W analogiczny sposób działają też metody print i class (i wiele, wiele innych). Print robi to samo co puts, z dokładnością do znaku nowej linii, którego w tym przypadku nie ma. Metoda class zwraca nazwę typu obiektu, który został jej przekazany:
#File: Print_class.rbputs 10.class puts 10.0.class puts "10”.class print 20.class print 20.0.class print "20”.class
jan@Stacja-Linux ~/Pulpit $ ruby Print_class.rb Fixnum Float String FixnumFloatString
Wywoływanie metody, a nawiasy
Wspominaliśmy wcześniej, że argumenty metody mogą być objęte nawiasem (nawet jeśli ich liczba to zero ;)) lub nie:
irb(main):001:0> "123".to_i => 123 irb(main):002:0> "234".to_i() => 234
Zazwyczaj nie ma to znaczenia (poza przejrzystością kodu), ale jest jedna sytuacja, kiedy nawiasy są niezbędne - kiedy chcemy wywołać kolejną metodę na wyniku poprzedniej:
irb(main):001:0> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".count("a").round(-1) => 40 irb(main):002:0> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".count "a".round(-1) NoMethodError: undefined method `round' for "a":String from (irb):2 from /home/jan/.rbenv/versions/2.1.7/bin/irb:11:in `<main>'
Pierwsze wyrażenie jest poprawne - najpierw obliczana jest ilość wystąpień litery ”a” w napisie, po czym zwracana liczba zaokrąglana jest do pełnych dziesiątek. Drugie wyrażenie jest błędne, ponieważ interpreter Ruby’iego “odczytuje” je tak, jakby wyrażenie “a”.round(-1) miało być argumentem dla metody count. Metoda round nie jest jednak zdefiniowana dla typu String, przez co następuje błąd.
Dla ciekawych świata:
Trochę więcej o wcięciach i ogólnie składni Ruby'iego.
Kompletny przegląd metod dla napisów, liczb całkowitych i liczb zmiennoprzecinkowych (zauważ, że w tekście samouczka metody dla liczb zostały ujęte w jedną tabelkę, gdyż te wymienione działają dla obu typów).
Dla bardzo ciekawych świata:
O wzorze w funkcji potential_prime.