Ruby/Powrót do prostych przykładów: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Linia 6:
 
<pre>
def factsilnia(n)
if n == 0
1
else
n * factsilnia(n-1)
end
end
puts factsilnia(ARGV[0].to_i)
</pre>
 
Linia 20:
=== Silnie ===
 
<pre>def factsilnia(n)</pre>
 
W pierwszej linii, <tt>def</tt> jest instrukcją służącą do definiowania funkcji (lub, bardziej precyzyjnie, metody. O tym, czym jest metoda będziemy mówić więcej w [[Ruby/Metody|dalszym rozdziale]]). Tutaj, <tt>def</tt> wskazuje, że funkcja przyjmuje pojedynczy argument, nazwany <tt>n</tt>.
Linia 36:
Jeżeli warunek nie jest spełniony, obliczany jest kod znajdujący się od tego miejsca aż do <tt>end</tt>.
 
<pre>n * factsilnia(n-1)</pre>
 
Jeżeli warunek nie jest spełniony, wartość wyrażenia <tt>if</tt> wynosi <tt>n</tt> razy <tt>factsilnia(n-1)</tt>.
 
<pre>end</pre>
Linia 48:
Drugi <tt>end</tt> zamyka instrukcję <tt>def</tt>.
 
<pre>puts factsilnia(ARGV[0].to_i)</pre>
 
Ta linia wywołuje naszą funkcję <tt>factsilnia()</tt> używając wartości z linii poleceń oraz wypisuje wynik.
 
<tt>ARGV</tt> jest tablicą, która zawiera argumenty z linii poleceń. Elementy <tt>ARGV</tt> są łańcuchami znakowymi, więc aby dokonać konwersji na liczby całkowite używamy metody <tt>to_i</tt>. Ruby nie zamienia łańcuchów na liczby automatycznie tak jak Perl.
Linia 61:
 
<pre>
01 wordsslowa = ['foobarfiolek', 'bazroza', 'quuxbez']
02 secretsekret = wordsslowa[rand(3)]
03
04 print "guesszgadnij? "
05 while guessodp = STDIN.gets
06 guessodp.chop!
07 if guessodp == secretsekret
08 puts "You winWygrales!"
09 break
10 else
11 puts "Sorry,Przykro youmi, loseprzegrales."
12 end
13 print "guesszgadnij? "
14 end
15 puts "theChodzilo word iso ", secretsekret, "."
</pre>
 
W tym programie użyta jest nowa struktura sterująca - <tt>while</tt>. Kod pomiędzy <tt>while</tt> a jej kończącym <tt>end</tt> będzie wykonywany w pętli tak długo jak pewien określony warunek pozostanie prawdziwy. W tym przypadku <tt>guessodp = STDIN.gets</tt> jest zarówno aktywną instrukcją (pobierającą linię wejściową od użytkownika i zachowującą ją jako <tt>guessodp</tt>), oraz warunkiem (jeżeli nie ma żadnego wejścia, <tt>guessodp</tt>, które reprezentuje wartość całego wyrażenia <tt>guessodp = STDIN.gets</tt>, będzie miało wartość <tt>nil</tt>, która spowoduje przerwanie pętli <tt>while</tt>).
 
<tt>STDIN</tt> oznacza obiekt standardowego wejścia. Zwykle <tt>guessodp = gets</tt> robi to samo, co <tt>guessodp = STDIN.gets</tt>.
 
<tt>rand(3)</tt> w linii 2 zwraca losową liczbę w przedziale od 0 do 2. Ta losowa liczba jest użyta do wyciągnięcia jednego elementu z tablicy <tt>wordsslowa</tt>.
 
W linii 5 czytamy jedną linię ze standardowego wejścia przez metodę <tt>STDIN.gets</tt>. Jeżeli wystąpi EOF (ang. ''end of file'' - koniec pliku) podczas pobierania linii, <tt>gets</tt> zwróci <tt>nil</tt>. Tak więc kod skojarzony z tą pętlą <tt>while</tt> będzie powtarzany dopóki nie zobaczy <tt>^D</tt> (lub <tt>^Z</tt> czy też F6 pod DOS/Windows), co oznacza koniec wprowadzania.
 
<tt>guessodp.chop!</tt> w linii 6 usuwa ostatni znak z <tt>guessodp</tt>. W tym wypadku zawsze będzie to znak nowej linii, gdyż <tt>gets</tt> dodaje ten znak by odzwierciedlić naciśnięcie przez użytkownika klawisza Enter (Return), co w naszym wypadku jest niepotrzebne.
 
W linii 15 drukujemy tajne słowo (<tt>secretsekret</tt>). Zapisaliśmy to jako wyrażenie <tt>puts</tt> (skrót od ang. ''put string'' - dosł. "połóż łańcuch") z dwoma argumentami, które są drukowane jeden po drugim. Można to zapisać równoważnie z jednym argumentem, zapisując <tt>secretsekret</tt> jako <tt>#{secretsekret}</tt> by było jasne, że jest to zmienna do przetworzenia, nie zaś literalne słowo:
 
<pre>puts "the word is #{secretsekret}."</pre>
 
Wielu programistów uważa, że utworzenie pojedynczego łańcucha jako argumentu metody <tt>puts</tt> to czytelniejszy sposób formułowania wyjścia.
Linia 100:
<pre>
# nowa linia jest automatycznie dodawana przez puts, jeżeli znak nowej linii jeszcze nie wystąpił:
puts "Darwin'sZona wifeDarwina, Esmerelda, diedzginela inw aataku fit of penguinspingwinow."
 
# znak nowej linii musi być jawnie dodany do polecenia print:
print "Darwin'sZona wifeDarwina, Esmerelda, diedzginela inw aataku fit of penguinspingwinow.\n"
 
# możesz dodawać wyjście stosując +:
print "Darwin'sZona wifeDarwina, Esmerelda, diedzginela inw aataku fit of penguinspingwinow." + "\n"
 
# lub możesz dodawać podając więcej niż jeden łańcuch:
print "Darwin'sZona wifeDarwina, Esmerelda, diedzginela inw aataku fit of penguinspingwinow.", "\n"
</pre>
 
Linia 115:
 
<pre>
04 print "guesszgadnij? "; STDOUT.flush
...
13 print "guesszgadnij? "; STDOUT.flush
</pre>
 
I rzeczywiście, będziemyBędziemy z tym bezpieczniejsi również w następnym skrypcie.
 
=== Wyrażenia regularne ===
Linia 130:
02 en = "\033[m"
03
04 puts "EnterAby anzakonczyc emptywprowadz stringpusty at any time to exittekst."
05
06 while true
07 print "strtekst> "; STDOUT.flush; strtekst=gets.chop
08 break if strtekst.empty?
09 print "patwzor> "; STDOUT.flush; patwzor=gets.chop
10 break if patwzor.empty?
11 rewyr = Regexp.new(patwzor)
12 puts strtekst.gsub(rewyr, "#{st}\\&#{en}")
13 end
</pre>
Linia 144:
W linii 6 w warunku dla pętli <tt>while</tt> zakodowana jest "na sztywno" wartość <tt>true</tt>, co w efekcie daje nam nieskończoną pętlę. Aby więc przerwać wykonywanie pętli umieściliśmy instrukcje <tt>break</tt> w liniach 8 i 10. Te dwie instrukcje są również przykładem ''modyfikatorów'' <tt>if</tt>. ''Modyfikator'' <tt>if</tt> wykonuje wyrażenie po swojej lewej stronie wtedy i tylko wtedy, gdy określony warunek jest prawdziwy. Konstrukcja ta jest niezwykła, gdyż działa logicznie od prawej do lewej strony, ale jest dostępna, ponieważ wielu ludziom przypomina podobne wzorce obecne w mowie potocznej. Dodatkowo jest ona zwięzła - nie potrzebuje wyrażenia <tt>end</tt> by wskazać interpreterowi ile kodu następującego po <tt>if</tt> ma być traktowane jako warunek. ''Modyfikator'' <tt>if</tt> jest wygodnym sposobem używanym w sytuacjach, gdzie wyrażenie i warunek są wystarczająco krótkie by zmieścić się razem w jednej linii skryptu.
 
Rozważmy zmiany w interfejsie użytkownika w stosunku do poprzedniego skryptu - łamigłówki. Bieżący interfejs pozwala użytkownikowi zakończyć program poprzez wciśnięcie klawisza Enter (Return) przy pustej linii. Sprawdzamy czy każda linia z wejścia jest pustym łańcuchem, a nie czy w ogóle istnieje.
 
W liniach 7 i 9 mamy "nie-destruktywny" <tt>chop</tt>. Pozbywamy się tak niechcianego znaku końca linii, który zawsze otrzymujemy od <tt>gets</tt>. Jak dodamy wykrzyknik, będziemy mieli "destruktywny" <tt>chop</tt>. Jaka to różnica? W Rubim istnieje konwencja dołączania znaków <tt>!</tt> lub <tt>?</tt> do końca nazw pewnych metod. Wykrzyknik (<tt>!</tt>) oznacza coś potencjalnie destruktywnego, coś co może zmienić wartość przylegającego wyrażenia. <tt>chop!</tt> zmienia łańcuch bezpośrednio, <tt>chop</tt> daje ci obciętą kopię bez psucia oryginału. Oto ilustracja tej różnicy.
 
<pre>
ruby> s1 = "forthteksty"
"forthteksty"
ruby> s1.chop! # To zmienia s1.
"forttekst"
ruby> s2 = s1.chop # To tworzy zmienioną kopię pod s2,
"forteks"
ruby> s1 # ... bez wpływu na s1.
"forttekst"
</pre>
 
Linia 168:
 
<pre>
highlightedpodswietlony = strtekst.gsub(rewyr,"#{st}\\&#{en}")
puts highlightedpodswietlony
</pre>
 
Linia 175:
 
<pre>
strtekst.gsub!(rewyr,"#{st}\\&#{en}")
puts strtekst
</pre>