Ruby po kapkách (7.) – struktura programu, metody

10. dubna 2009

Poznali jsem již značné množství stavebních bloků, z nichž lze vytvářet Ruby programy. V tomto článku se podíváme na způsob, jakým sestavit a spouštět jednoduchý program.

Ruby je prezentován jako silně objektově orientovaný jazyk. To vyvolává představu tříd, objektů a metod. Zároveň je ale klíčovým návrhovým principem Ruby snaha nevytvářet zbytečné formální překážky. Pro jednoduché programy – typicky skripty používané pro různé drobné úlohy například při administraci systému – si vystačíme s kódem strukturovaným pouze základními řídícími strukturami. Případně pro strukturování programu můžeme použít členění kódu na metody. Získáváme tak vlastně obdobu procedurálního jazyka. Veškerý kód včetně definic metod, který není součástí žádné explicitně jmenované třídy, běží v kontextu pro tento účel vytvořené instance třídy Object.

Kód jazyka Ruby se skládá z výrazů a příkazů, které jsou odděleny koncem řádku. Je také možné zapsat více výrazů na jeden řádek, ale musí pak být odděleny středníkem. V jiném případě se středníky nepoužívají. V případě, že chceme výraz rozdělit tak, aby část byla na jednom řádku a výraz pokračoval na dalším řádku, je třeba na konec nekompletního řádku přidat zpětné lomítko. V některých případech interpreter může rozpoznat neúplný řádek sám – například když končí operátorem, za kterým musí následovat další operand.

Pokud se v kódu vyskytne znak mřížka (#) mimo řetězcovou konstantu, je zbytek řádku interpretem považován za komentář. Jiným druhem potenciálně víceřádkového komentáře je text uzavřený mezi příkazy =begin a =end. Tato varianta bývá využívána automatickými nástroji pro generování dokumentace.

# Struktura kódu
=begin
Víceřádkový
komentář.
=end

a = 1
b = 2; c = 3
d = 4 + 5 + # zde není třeba zpětné lomítko
6 + 7
e = 8 + 9 \
+ 10 # zde naopak zpětné lomítko třeba je
puts self.class

Uvedený kód vlastně navenek téměř nic nedělá, kromě posledního řádku, kde vypisuje třídu aktuálního objektu, což by měla být třída Object. Ověřit si to můžeme uložením kódu do souboru a spuštěním ruby jmeno.rb, kde jméno nahraďte skutečným názvem souboru.

Při spouštění programu nastaví interpret některé speciální konstanty a globální proměnné. Pro nás jsou zajímavé zejména ty, které umožňují interakci programu s okolím. Pod označením ENV se skrývá objekt, který se chová podobně jako hash a obsahuje proměnné prostředí programu. Zde je jednoduchý program, který vypíše na platformě Windows nějaké informace o hardware počítače.

ENV.each do |name, value|
puts „#{name} => #{value}“ if name.index(‚PROC‘) == 0
end

Výstup může vypadat například následovně.

C:\Ruby>ruby hw.rb
PROCESSOR_ARCHITECTURE => x86
PROCESSOR_IDENTIFIER => x86 Family 6 Model 15 Stepping 13, GenuineIntel
PROCESSOR_LEVEL => 6
PROCESSOR_REVISION => 0f0d

Podobným zajímavým objektem je ARGV, který se pro změnu chová obdobně jako pole a obsahuje parametry programu zadané při spouštění z příkazové řádky. Pozor zde musí dát programátoři zvyklí na jazyky vycházející z konvence, kde první prvek (s indexem 0) takového pole parametrů je název spouštěného programu. ARGV obsahuje skutečně jen parametry. Název programu bychom získali pomocí globální proměnné $0. Taková proměnná vypadá dosti divně. Je to dáno tím, že Ruby vychází do značné míry z jazyka Perl, který se snaží šetřit programátorům prsty, ačkoliv je to mnohdy na úkor čitelnosti. I v Ruby je tedy celá řada speciálních proměnných nastavených interpretem, která má označení sestávající ze dvou či tří speciálních znaků. Máme nicméně k dispozici knihovnu English, která jim přiřadí anglicky čitelné aliasy a název programu je pak dostupný přes $PROGRAM_NAME. Použití uvidíme v následujícím krátkém prográmku, který vypíše svůj název a součet čísel zadaných jako parametry příkazové řádky.

require ‚English‘
puts $PROGRAM_NAME
puts ARGV.inject(0) { |suma, a| suma + a.to_i }

Výstup bude záviset na tom, jak program spustíme.

C:\Ruby>ruby name.rb 3 4 5 6
name.rb
18

Nyní se již pojďme podívat, jak se v Ruby definují metody. Metoda je jednoduše řečeno ohraničený kus kódu, který přijímá předem definované parametry a vrací hodnotu. Dále ukázaná metoda nazvaná add očekává dva parametry a vrací jejich součet.

def add(a, b)
a + b
end

puts add(1, 2)
puts add(‚x‘, ‚y‘)

Výsledek je podle očekávání.

C:\Ruby>ruby add.rb
3
xy

Definice metody začíná klíčovým slovem def a končí klíčovým slovem end. Za slovem def následuje název metody. Ten začíná malým písmenem, pak mohou následovat alfanumerické znaky, podtržítko a na konci může být otazník nebo vykřičník. S touto konvencí jsme se již setkali – metody končící v názvu na otazník vrací pravdivostní hodnotu a typicky testují platnost nějakého predikátu, metody končící na vykřičník mění svého příjemce. Za názvem metody je seznam parametrů uvedený v závorkách. S parametry pak můžeme pracovat v těle metody pod příslušnými názvy, pro které platí stejná pravidla jako pro lokální proměnné.

Zde je třeba se zmínit o typech. Ve striktně typovaných jazycích se při definování proměnné nebo parametru metody či funkce stanovuje i očekávaný typ – t.j. zda očekáváme parametr, který bude číslo nebo třeba řetězec. V Ruby platí, že proměnná či parametr je jen referencí na objekt, který je teprve nositelem typu. To má své výhody i nevýhody. (A ti, kdo s Ruby pracují, jsou přesvědčeni, že výhody dramaticky převažují.) V našem případě se to projevuje tak, že metoda při volání akceptuje jak čísla, tak znaky. Jediné co potřebuje, je aby dané objekty měly definovaný operátor +.

Hodnota posledního výrazu v těle metody se automaticky stává návratovou hodnotou metody. Explicitně bychom mohli ukončit běh metody a vrátit hodnotu pomocí příkazu return. Parametrům metody lze v rámci definice přiřadit defaultní hodnoty.

def add(a = 1, b = a + 2)
a + b
end

Někdy potřebujeme, aby metoda měla proměnný počet parametrů. V takovém případě je možné použít jeden parametr, se kterým budeme pracovat jako s polem. Případně předávat metodě jako parametr hash a pracovat s ním jako se sadou pojmenovaných parametrů. Ruby má přímo vestavěný mechanismus, který umožňuje ošetřit běžný případ, kdy máme několik povinných parametrů a zbytek volitelných.

def varargs(a, *b)
[a, b] end
puts varargs(1).inspect
puts varargs(1, 2).inspect
puts varargs(1, 2, 3).inspect

Zde je první parametr očekávaný vždy. Dalšímu parametru je předřazena hvězdička, což znamená, že všechny další skutečně předané argumenty budou převedeny na pole s příslušným počtem prvků. Zároveň metoda vrací dvouprvkové pole svých parametrů. Fungování nejlépe osvětlí výstup.

C:\ruby>ruby varargs.rb
[1, []] [1, [2]] [1, [2, 3]]

Pochopiteně je také možné definovat metodu, která nečeká žádné parametry. A to je v kostce základ definování a používání metod v Ruby. Ve skutečnosti jsme problematiku zjednodušili a vynechali některé složitější věci, ke kterým se vrátíme později. Ale již s dosavadními znalostmi řídících struktur a metod byste měli být schopni psát relativně funkční programy či skripty.

Uveďme nakonec malý příklad. Program, který načítá ve smyčce čísla ze standardního vstupu a vypisuje seznam všech dělitelů (poněkud naivním algoritmem). Další chování programu odhadněte z kódu a ověřte pokusem.

def delitele(x)
return „Moc velké číslo!“ if x > 999
a = [] 1.upto(x) { |n| a << n if x % n == 0 }
return „Žádný dělitel!“ if a.size == 0
a.join(‚, ‚)
end
while r = gets
break if r.chop == ‚konec‘
puts delitele(r.to_i)
end

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *