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

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Szymon wro (dyskusja | edycje)
Nie podano opisu zmian
Linia 5:
Następujący kod pojawił się w rozdziale z [[Ruby/Proste przykłady|prostymi przykładami]].
 
<source lang="ruby">
<pre>
def silnia(n)
if n == 0
Linia 14:
end
puts silnia(ARGV[0].to_i)
</presource>
 
Ponieważ jest to pierwsze objaśnienie, zbadamy każdą linię osobno.
Linia 20:
=== Silnie ===
 
<source lang="ruby">
<pre>def silnia(n)</pre>
</source>
 
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>.
 
<source lang="ruby">
<pre>if n == 0</pre>
</source>
 
<tt>if</tt> służy do sprawdzania warunku. Kiedy warunek jest spełniony, następny fragment kodu jest obliczany. W przeciwnym razie obliczane jest cokolwiek co występuje za <tt>else</tt>.
 
<source lang="ruby">
<pre>1</pre>
1
</source>
 
Wartość <tt>if</tt> wynosi <tt>1</tt> jeżeli warunek jest spełniony.
 
<source lang="ruby">
<pre>else</pre>
else
</source>
 
Jeżeli warunek nie jest spełniony, obliczany jest kod znajdujący się od tego miejsca aż do <tt>end</tt>.
 
<source lang="ruby">
<pre>n * silnia(n-1)</pre>
</source>
 
Jeżeli warunek nie jest spełniony, wartość wyrażenia <tt>if</tt> wynosi <tt>n</tt> razy <tt>silnia(n-1)</tt>.
 
<source lang="ruby">
<pre>end</pre>
13 end
</source>
 
Pierwszy <tt>end</tt> zamyka instrukcję <tt>if</tt>.
 
<source lang="ruby">
<pre>end</pre>
end
</source>
 
Drugi <tt>end</tt> zamyka instrukcję <tt>def</tt>.
 
<source lang="ruby">
<pre>puts silnia(ARGV[0].to_i)</pre>
</source>
 
Ta linia wywołuje naszą funkcję <tt>silnia()</tt> używając wartości z linii poleceń oraz wypisuje wynik.
Linia 60 ⟶ 76:
Teraz zbadamy nasz program - łamigłówkę z rozdziału o [[Ruby/Łańcuchy znakowe|łańcuchach znakowych]]. Ponieważ jest on nieco długi, ponumerujmy linie, by móc się łatwo do nich odwoływać.
 
<source lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS">
<pre>
01 slowa = ['fiolek', 'roza', 'bez']
02 sekret = slowa[rand(3)]
 
03
04 print "zgadnij? "
05 while odp = STDIN.gets
06 odp.chop!
07 if odp == sekret
08 puts "Wygrales!"
09 break
10 else
11 puts "Przykro mi, przegrales."
12 end
13 print "zgadnij? "
14 end
15 puts "Chodzilo o ", sekret, "."
</presource>
 
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>odp = STDIN.gets</tt> jest zarówno aktywną instrukcją (pobierającą linię wejściową od użytkownika i zachowującą ją jako <tt>odp</tt>), oraz warunkiem (jeżeli nie ma żadnego wejścia, <tt>odp</tt>, które reprezentuje wartość całego wyrażenia <tt>odp = STDIN.gets</tt>, będzie miało wartość <tt>nil</tt>, która spowoduje przerwanie pętli <tt>while</tt>).
Linia 90 ⟶ 106:
W linii 15 drukujemy tajne słowo (<tt>sekret</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>sekret</tt> jako <tt>#{sekret}</tt> by było jasne, że jest to zmienna do przetworzenia, nie zaś literalne słowo:
 
<source lang="ruby">
<pre>
puts "Chodzilo o #{sekret}."
</presource>
 
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 ⟶ 116:
Poniższe cztery wywołania wyjścia są równoważne:
 
<source lang="ruby">
<pre>
# nowa linia jest automatycznie dodawana przez puts, jeżeli znak nowej linii jeszcze nie wystąpił:
puts "Zona Darwina, Esmerelda, zginela w ataku pingwinow."
Linia 112 ⟶ 128:
# lub możesz dodawać podając więcej niż jeden łańcuch:
print "Zona Darwina, Esmerelda, zginela w ataku pingwinow.", "\n"
</presource>
 
Jeden słaby punkt: czasami okno tekstowe z powodu prędkości działania posiada buforowane wyjście. Poszczególne znaki są buforowane i wyświetlane dopiero gdy pojawi się znak przejścia do nowej linii. Więc, jeżeli skrypt naszej zgadywanki nie pokazuje zachęty dla użytkownika dopóki użytkownik nie poda odpowiedzi, niemal na pewno winne jest buforowanie. Aby upewnić się, że tak się nie stanie możesz wyświetlić (ang. ''flush'' - dosł. "wylać") wyjście jak tylko zostanie wydrukowana zachęta dla użytkownika. <tt>flush</tt> mówi standardowemu urządzeniu wyjściowemu (obiekt nazwany <tt>STDOUT</tt>), "nie czekaj - wyświetl to co masz w tej chwili".
 
<source lang="ruby line="GESHI_NORMAL_LINE_NUMBERS" start="4">
<pre>
04 print "zgadnij? "; STDOUT.flush
<source>
...
<source lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS" start="13">
13 print "zgadnij? "; STDOUT.flush
</pre>
</source>
 
Będziemy z tym bezpieczniejsi również w następnym skrypcie.
Linia 128 ⟶ 145:
W końcu zbadamy program z rozdziału o [[Ruby/Wyrażenia regularne|wyrażeniach regularnych]].
 
<source lang="ruby line="GESHI_NORMAL_LINE_NUMBERS">
<pre>
01 st = "\033[7m"
02 en = "\033[m"
 
03
04 puts "Aby zakonczyc wprowadz pusty tekst."
06 while true
05
07 print "tekst> "; STDOUT.flush; tekst=gets.chop
06 while true
08 break if tekst.empty?
07 print "tekst> "; STDOUT.flush; tekst=gets.chop
09 print "wzor> "; STDOUT.flush; wzor=gets.chop
08 break if tekst.empty?
break if wzor.empty?
09 print "wzor> "; STDOUT.flush; wzor=gets.chop
10 wyr break if= Regexp.new(wzor.empty?)
12 puts tekst.gsub(wyr, "#{st}\\&#{en}")
11 wyr = Regexp.new(wzor)
end
12 puts tekst.gsub(wyr, "#{st}\\&#{en}")
</source>
13 end
</pre>
 
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.