Definiowane funkcji w Ruby odbywa się za pomocą słów kluczowych def
i end
. Najprostsza funkcj może wyglądać następująco:
def pozdrowienie
puts "Witaj epi"
end
Wywołujemy ją podając jej nazwę, np.
pozdrowienie
pozdrowienie
pozdrowienie
Nawiasy w wywołaniu są opcjonalne, w szczególności, jeśli funkcja nie przyjmuje parametrów. Ale można również ją wywołać z nawiasami - w szczególności jeśli mamy zagnieżdżone wywołania funkcji:
pozdrowienie()
Uwaga: IRuby zapamiętuje zdefiniowane funkcje, ale tylko w ramach jednej sesji uruchomieniowej. Dlatego jeśli chcemy wykorzystać wcześniej zdefiniowaną funkcję w innej komórce, musimy się upewnić, czy została zdefiniowana w tej samej sesji.
Funkcje mogą przyjmować parametry. Ponieważ Ruby jest językiem dynamicznie typizowanym, nie określamy ich typów, a jedynie nazwy:
def pozdrowienie(imie)
puts "Witaj #{imie}"
end
pozdrowienie("Anno")
pozdrowienie("Błażeju")
pozdrowienie("Zosiu")
Parametry mogą być opcjonalne - jeśli nie przekażemy wartości, to zostanie użyta wartość domyślna, np.
def pozdrowienie(imie="człowieku")
puts "Witaj #{imie}"
end
pozdrowienie("Anno")
pozdrowienie
Jako swój wynik, funkcje zwracają wartość ostatniego ewaluowanego (obliczanego) wyrażenia, np.
def razy_dwa(wartosc)
2 * wartosc
end
razy_dwa(2)
Warto zwrócić uwagę, że funkcja nie zawsze wypisuje coś na ekran (porównaj funkcje pozdrowienie
oraz razy_dwa
)! Dlatego jeśli wywołujemy funkcje, które tylko zwracają wartość, musimy sami wyświetlić ich wynik. W przeciwnym razie zostanie wyświetlona wartość tylko ostatniego wywołania. Prównaj:
razy_dwa(3)
razy_dwa(4)
oraz
puts razy_dwa(3)
puts razy_dwa(4)
Zdefiniuj funkcję pierwiastek_szescienny
, która oblicza pierwiastek szcześcienny z przekazanego parametru. Jeśli użytkownik nie przekaże żadnego parametru, to funkcja powinna zwracać wartość 0. Sprawdź działanie funkcj dla następujących przypadków:
Dlaczego wartość otrzymana dla 27 jest niedokładna?
if
¶Podstawową instrukcją warunkową w Ruby jest if
.
Jest ona podobna do instrukcji z języcka C:
def parzystosc(liczba)
if liczba % 2 == 0
"Liczba #{liczba} jest parzysta"
else
"Liczba #{liczba} jest nieparzysta"
end
end
puts parzystosc(11)
puts parzystosc(12)
Instrukcja if
nie wymaga użycia nawiasów wokół warunku. Ponadto zamiast nawiasów klamrowych wykorzystywane są wyłącznie słowa kluczowe: opcjonalne else
oraz wymagane end
. Jeśli w instrukcji występuje połączenie instrukcji else
z if
to używa się innego słowa kluczowego elsif
:
def jezyk(plik)
print "#{plik} -> "
if plik =~ /\.rb\z/
puts "Język Ruby"
elsif plik =~ /\.c\z/
puts "Język C"
elsif plik =~ /\.java\z/
puts "Język Java"
else
puts "Nieznany język programowania"
end
end
jezyk("program.c")
jezyk("inny_program.rb")
jezyk("prosty_program.scala")
W języku Ruby występują tylko dwie wartości, które oznaczają fałsz: wartość nil
oraz wartość false
. Wszystkie pozostałe wartości traktowane są jako prawda. Dlatego np. w poprzednim przykładzie, nawet gdyby dopasowanie dało wynik 0
, tzn. zaczynało się na początku łańcucha, kod zadziałałby poprawnie:
if 0
"Zero jest prawdą"
else
"Zero jest fałszem"
end
Złożone wyrażenia logiczne konstruowane są za pomocą operatorów logicznych: ||
(lub), &&
(i) oraz !
(nie). Przy złożonych warunkach warto użyć nawiasów:
def dobry_wybor?(plik)
print "#{plik} -> "
if !(plik =~ /\.rb\z/) && !(plik =~ /\.py\z/)
puts "to kiepski wybór"
else
puts "to dobry wybór"
end
end
dobry_wybor?("rails.rb")
dobry_wybor?("django.py")
dobry_wybor?("yoomla.php")
Uwaga! W powyższym przykładzie nawiasy są wymagane. Isotna jest tutaj kolejność działań. Moża to sprawdzić na następujących przykładach:
puts !"aaa" =~ /b/
puts !("aaa" =~ /b/)
Dlatego jeśli chcemy zanegować dopasowanie do wzorca lepiej użyć specjalnego operatora !~:
"aaa" !~ /b/
Istnieją również operatory or
, and
oraz not
, ale nie powinno się ich stosować w instrukcji warunkowej, gdyż są to instrukcje sterujące.
Zdefiniuj funkcje przytnij
, która akceptuje jeden parametr - napis. Funkcja powinna zwarcać ten sam napis, jeśli jest krótszy niż 30 znaków. W przeciwnym razie przycinać napis oraz dodawać 3 kropki na końcu, wskazujące, że napis zostł ucięty. Łącznie z kropkami napis nie może być dłuższy niż 15 znaków. Ostatni wyraz w napisie powinie być wyświetlony zawsze w całości.
Przykładowo:
puts przytnij("Ala ma kota.") # Ala ma kota.
puts przytnij("Ala ma kota, papugę i psa.") # Ala ma kota,...
puts przytnij("Ala ma psa, papugę i kota.") # Ala ma psa,...
unless
¶W języku Ruby istnieje również polecenie unless
, które działa jak "odwrócony" if
, tzn. warunek jest zanegowany. Poprzedni przykład możemy wyrazić następująco:
def dobry_wybor?(plik)
unless plik =~ /\.rb\z/
puts "To kiepski wybór"
end
end
dobry_wybor?("program.c")
if
oraz unless
mogą również działać jako tzw. modyfikatory, stojące po instrukcji. Pozwalają zwięźlej zapisać warunkowe wykonanie pojedynczej instrukcji:
def dobry_wybor?(plik)
puts "To kiepski wybór" unless plik =~ /\.rb\z/
end
dobry_wybor?("program.c")
Tego rodzaju kod czyta się bardzo naturalnie i często spotykany jest w programach napisanych w Ruby.
W instrukcjach warunkowych często porównujemy wartości, np. dwóch zmiennych. Należy zwrócić uwagę, że istnieje wiele rodzajów równości, które mają zastosowanie w różnych okolicznościach:
==
- naturalna równośćeql?
- dodatkowy wymóg - identyczny typ wartościequal?
- identyczne obiekty=~
- dopasowanie wyrażeń regularnych===
- porównywanie w instrukcji selekcjiNaturalne równość jest najczęściej wykorzystywana i pozwala porównywać proste oraz złożone wartości:
p 0 == 0.0
p "ala" == "ala"
p [1,2,3] == [1,2,3]
eql?
dodaje wymóg, aby wartości posiadały identyczny typ. Np. liczby całkowite i rzeczywiste mają inny typ, dlatego ta instrukcja może służyć do ich odróżnienia:
p 0.eql?(0.0)
p "ala".eql?("ala")
p [1,2,3].eql?([1,2,3])
Operator eql?
jest stosowany w połączeniu z tablicami asocjacyjnymi - to ten rodzaj równości wykorzystywany jest do zastępowania zawartości tablicy:
tablica = {}
tablica[1] = "jeden"
tablica[1.0] = "jeden"
p tablica
tablica = {}
tablica["1"] = "jeden"
tablica["1"] = "jeden"
p tablica
equal?
jest jeszcze bardziej restrykcyjne. Wymagana jest identyczność obiektów. Zasadniczo dwa różne obiekty choć mogą mieć identyczną wartość, nie będą równe względem tej równości, jeśli nie są dokładnie tym samym obiektem:
a = "ala"
p a.equal?(a)
b = a
p a.equal?(b)
c = "ala"
p a.equal?(c)
Istnieją jednak pewne wartości, które zawsze posiadają dokładnie jedną instancję - są to symbole oraz "małe" liczby całkowite:
a = :ala
b = :ala
p a.equal?(b)
a = 10
b = 10
p a.equal?(b)
a = 10.0
b = 10.0
p a.equal?(b)
Operator =~
wykorzystywany jest do dopasowywania wyrażeń regularnych. Podobnie działa również operator ===
, ale ma on szersze zastosowanie, przede wszystkim dlatego, że wykorzystywany jest w instrukcji selekcji (patrz niżej). Wiele typów posiada metodę pozwalającą na wykorzystanie tego operatora, np.
p (1..5) === 3
p (1..5) === 5
p (1...5) === 5
p Fixnum === 1
p /^a/ === "ala"
Uwaga: operator ===
nie jest symetryczny!
p (1..5) === 3
p 3 === (1..5)
Zdefiniuj funkcję rowne_tablice?(a,b)
, która zwraca prawdę, jeśli tablice są równe, bez względu na kolejność elementów. Np.
puts rowne_tablice?([1,2,3],[1,2,3]) # true
puts rowne_tablice?([1,2,3],[3,2,1]) # true
puts rowne_tablice?([1,2,3],[1,2]) # false
puts rowne_tablice?([1,2,3],[1,2,3,4]) # false
case
¶Instrukcja case
to instrukcja selekcji. Najprostsze jej zastosowanie polega na porównaniu zmiennej ze stałą, np.
case liczba
when 1
puts "jeden"
when 2
puts "dwa"
when 3
puts "trzy"
else
puts "bardzo duża liczba"
end
liczba = 5
Dzięki wykorzystaniu operatora ===
zastosowanie instrukcji case
jest znacznie szersze. Można np. porównać wartość zmiennej z szeregiem wyrażeń regularnych:
case plik
when /\.rb\z/
"Ruby"
when /\.pl\z/
"Perl"
when /\.php\z/
"PHP"
when /\.c\z/
"Język C"
else
"Nieznany język"
end
plik = "moj_program.php"
Możliwe jest również zastosowanie zakresów:
case rok
when 1901..2000
"XX"
when 2001..2100
"XXI"
when 2101..2200
"XXII"
else
"ciemne wieki"
end
rok = 1994