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

Usunięta treść Dodana treść
zamiana ProstaNawigacja->Subst:Naw
Nie podano opisu zmian
 
Linia 5:
Następujący kod pojawił się w rozdziale z [[Ruby/Proste przykłady|prostymi przykładami]].
 
<sourcesyntaxhighlight lang="ruby">
def silnia(n)
if n == 0
Linia 14:
end
puts silnia(ARGV[0].to_i)
</syntaxhighlight>
</source>
 
Ponieważ jest to pierwsze objaśnienie, zbadamy każdą linię osobno.
Linia 20:
=== Silnie ===
 
<sourcesyntaxhighlight lang="ruby">
def silnia(n)
</syntaxhighlight>
</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>.
 
<sourcesyntaxhighlight lang="ruby">
if n == 0
</syntaxhighlight>
</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>.
 
<sourcesyntaxhighlight lang="ruby">
1
</syntaxhighlight>
</source>
 
Wartość <tt>if</tt> wynosi <tt>1</tt> jeżeli warunek jest spełniony.
 
<sourcesyntaxhighlight lang="ruby">
else
</syntaxhighlight>
</source>
 
Jeżeli warunek nie jest spełniony, obliczany jest kod znajdujący się od tego miejsca aż do <tt>end</tt>.
 
<sourcesyntaxhighlight lang="ruby">
n * silnia(n-1)
</syntaxhighlight>
</source>
 
Jeżeli warunek nie jest spełniony, wartość wyrażenia <tt>if</tt> wynosi <tt>n</tt> razy <tt>silnia(n-1)</tt>.
 
<sourcesyntaxhighlight lang="ruby">
end
</syntaxhighlight>
</source>
 
Pierwszy <tt>end</tt> zamyka instrukcję <tt>if</tt>.
 
<sourcesyntaxhighlight lang="ruby">
end
</syntaxhighlight>
</source>
 
Drugi <tt>end</tt> zamyka instrukcję <tt>def</tt>.
 
<sourcesyntaxhighlight lang="ruby">
puts silnia(ARGV[0].to_i)
</syntaxhighlight>
</source>
 
Ta linia wywołuje naszą funkcję <tt>silnia()</tt> używając wartości z linii poleceń oraz wypisuje wynik.
Linia 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ć.
 
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS">
slowa = ['fiolek', 'roza', 'bez']
sekret = slowa[rand(3)]
Linia 92:
end
puts "Chodzilo o ", sekret, "."
</syntaxhighlight>
</source>
 
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 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:
 
<sourcesyntaxhighlight lang="ruby">
puts "Chodzilo o #{sekret}."
</syntaxhighlight>
</source>
 
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 116:
Poniższe cztery wywołania wyjścia są równoważne:
 
<sourcesyntaxhighlight lang="ruby">
# 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 128:
# lub możesz dodawać podając więcej niż jeden łańcuch:
print "Zona Darwina, Esmerelda, zginela w ataku pingwinow.", "\n"
</syntaxhighlight>
</source>
 
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".
 
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS" start="4">
print "zgadnij? "; STDOUT.flush
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS" start="13">
print "zgadnij? "; STDOUT.flush
</syntaxhighlight>
</source>
 
Będziemy z tym bezpieczniejsi również w następnym skrypcie.
Linia 145:
W końcu zbadamy program z rozdziału o [[Ruby/Wyrażenia regularne|wyrażeniach regularnych]].
 
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS">
st = "\033[7m"
en = "\033[m"
Linia 159:
puts tekst.gsub(wyr, "#{st}\\&#{en}")
end
</syntaxhighlight>
</source>
 
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.
Linia 186:
Moglibyśmy podzielić linię 12 na osobne linie, tak jak tutaj:
 
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS" start="12">
podswietlony = tekst.gsub(wyr,"#{st}\\&#{en}")
puts podswietlony
</syntaxhighlight>
</source>
 
lub w "destruktywnym" stylu:
 
<sourcesyntaxhighlight lang="ruby" line="GESHI_NORMAL_LINE_NUMBERS" start="12">
tekst.gsub!(wyr,"#{st}\\&#{en}")
puts tekst
</syntaxhighlight>
</source>
 
Spójrz ponownie na ostatnią część linii 12. <tt>st</tt> i <tt>en</tt> były zdefiniowane w liniach 1-2 jako sekwencje ANSI które odpowiednio zmieniają i przywracają kolor tekstu. W linii 12 są one zawarte w <tt>#{}</tt> by w ten sposób były właściwie interpretowane (i nie wystąpiły zamiast nich nazwy zmiennych). Pomiędzy nimi widzimy <tt>\\&</tt>. Jest to trochę podstępne. Ponieważ podstawiany łańcuch zawarty jest w cudzysłowach (podwójnych), para odwróconych ukośników będzie zinterpretowana jako jeden ukośnik, co <tt>gsub</tt> zobaczy właściwie jako <tt>\&</tt>. To spowoduje powstanie specjalnego kodu, który z kolei odwoła się do czegokolwiek, co jako pierwsze będzie pasować do wzorca. Tak więc nowy łańcuch, gdy będzie wyświetlony będzie wyglądał tak jak pierwszy z wyjątkiem tego, że te fragmenty które pasują do wzorca będą wyświetlone w odwróconych kolorach.