Základním zdrojem informací o Ruby je www.ruby-lang.org a vynikající on-line kniha Programming Ruby.
Kdy vás může Ruby zaujmout? Zejména pokud splňujete některou z následujících podmínek:
- stále zkoušíte nové programovací jazyky
- ještě nemáte svůj oblíbený skriptovací jazyk
- hledáte v programování krásu konstrukce a potěšení z tvorby
- máte rádi software s myšlenkou, jasným designem a absencí ad hoc konstrukcí
Článek předpokládá určitou zkušenost a orientaci v běžných pojmech procedurálního a objektového programování. Zabývat se budeme mimo jiné proměnnými, operátory, řídícími strukturami, I/O operacemi a ošetřováním výjimek.
Hello, World!
Přejděme tedy k praxi. Po instalaci můžete (za obvyklých podmínek) ihned spustit interpret v interaktivním režimu pomocí příkazu irb. Irb ihned vyhodnocuje každý zadaný řádek:
irb 0.6.1(99/09/16) irb(main):001:0> 1+1 2 irb(main):002:0>
Dialog s irb ukončíte stiskem Ctrl+D.
Kód programu vytvořený libovolným editorem lze samozřejmě také uložit do souboru (obyčejně s příponou rb) a spustit příkazem ruby <soubor>.
Obligátní HelloWorld.rb by mohl vypadat například takto:
#!/usr/local/bin/ruby # Nadefinujeme funkci bez parametrů. Definice končí příkazem end. def helloWorld_1 # Funkce puts vypisuje parametry na standardní výstup. puts 'Hello, world!' end # Zavoláme nadefinovanou funkci. helloWorld_1
Asi nás nepřekvapí výsledek:
Hello, world!
Podívejme se, co lze zjistit pohledem na kód tohoto jednoduchého příkladu:
- jak je u interpretovaného kódu zvykem, první řádek začínající na #! určuje cestu k interpretu
- znak # zároveň označuje komentář, zbytek řádku je interpretem ignorován
- při programování v Ruby nebudete dvě hodiny ladit kvůli chybějícímu středníku
- pokud to nevede k nejednoznačnosti, nemusíte používat ani závorky
- ačkoliv (jak uvidíme) je Ruby opravdu objektový jazyk, nevnucují se nám objekty za každou cenu – příkládek je čistě procedurální
- kód se vykonává sekvenčně od začátku souboru a neexistuje žádný ekvivalent funkce main z jazyka C
Udělejme malinko složitější HelloWorld2.rb (možná ho plně pochopíte až po dočtení článku):
#!/usr/local/bin/ruby # Podle toho, zda objekt zadaný parametrem reaguje # na metodu 'times', funkce zobrazí n krát text, nebo # přímo zadaný parametr. def helloWorld_2(n) if n.respond_to?(:times) n.times { |x| puts "#{x}, Hello, world!" } else puts n end end helloWorld_2(3) helloWorld_2('Konec')
Po spuštění získáme:
0, Hello, world! 1, Hello, world! 2, Hello, world! Konec
Vidíme, že:
- definice a volání funkce helloWorld jsou rozšířeny o použití parametru
- ve funkci se používá řídící konstrukce if/else/end, která bude vysvětlena později
- ve funkci se využívá volání metod zápisem objekt.metoda
- volání respond_to? umožňuje zjistit, zda má objekt definovánu zadanou metodu
- celá čísla mají definovánu metodu times, která volá zadaný blok tolikrát, jaká je hodnota čísla
- aktuální hodnota iterované proměnné může být předávána do bloku
- pro ohraničení řetězce lze použít apostrofy (jako v HelloWorld1) nebo uvozovky (jako v HelloWorld2)
- obsah řetězce v apostrofech se již dále nezpracovává
- obsah řetězce v uvozovkách se zpracovává (např. v řetězci #{výraz} se výraz vyhodnotí a celý řetězec se nahradí výsledkem)
- navíc si řekneme, že obsah řetězce v obrácených apostrofech se nahradí standardním výstupem externího příkazu obsaženého v řetězci
a=33 puts '1: abc \n def #{a}' puts "2: abc \n def #{a}" puts `date`
Vypíše:
1: abc \n def #{a} 2: abc def 33 Fri Feb 1 09:58:58 CET 2002
Proměnné a operátory
Základní fakta:
- proměnné není třeba deklarovat
- není třeba se starat o typ proměnné – určuje si ho za běhu interpret (a je možné ho zjistit voláním metody type)
- není třeba se starat o uvolňování paměti – obstará ho garbage collector
- v tomto článku se setkáme pouze s lokálními proměnnými a globálními proměnnými – název lokální proměnné začíná malým písmenem, název globální velkým písmenem nebo znakem $
Čísla
Ruby podporuje celá i reálná čísla. Celá čísla odpovídající 32bitovému nebo 64bitovému integeru (podle platformy) jsou interně uložena jako obejkt třídy Fixnum. Větší celá čísla jsou ukládána jako objekt třídy Bignum. Bignum umožňuje pracovat s integery, jejichž velikost je omezena jen velikostí paměti počítače. Protože typy všech proměnných jsou v Ruby určovány až za běhu programu, je i přechod mezi dvěma integerovými typy bezbolestný:
n=8 7.times do # blok pro opakování je uzavřen mezi 'do' a 'end' puts "#{n.type} #{n}" # metoda 'type' vrací typ proměnné n*=n end
Vypíše:
Fixnum 8 Fixnum 64 Fixnum 4096 Fixnum 16777216 Bignum 281474976710656 Bignum 79228162514264337593543950336 Bignum 6277101735386680763835789423207666416102355444464034512896
Celá čísla je také možné zapisovat jako binární, oktalová nebo hexadecimální. Dekadické číslo 513 lze zapsat také jako:
- binární 0b1000000001
- oktalové 01001
- hexadecimální 0×201
Protože jsou čísla objekty, ukažme si několik základních metod, které mají definovány:
puts -23.abs # absolutní hodnota puts 65.chr # znak, jehož ASCII kód je roven číslu puts 3.next # o jedničku vyšší číslo puts 0.zero? # vrací 'true', když je číslo rovno nule puts 10.remainder(3) # zbytek po dělení čísla parametrem puts 15.type # typ proměnné
Jak jistě tušíte, výsledkem je:
23 A 4 true 1 Fixnum
Stojí za zmínku, že většina operátorů, o kterých bude řeč později, jsou ve skutečnosti metody s upravenou syntaxí volání: a+b můžeme napsat jako a+(b), což je volání metody ‚+‘ objektu ‚a‘ s parametrem ‚b‘.
Reálná čísla jsou uchovávána jako objekty třídy Float, a to ve dvojnásobné přesnosti. Float poskytuje několik základních metod:
puts 3.14.round # zaokrouhlení podle matematických pravidel puts 3.14.ceil # nejbližší větší celé číslo puts 3.14.floor # nejbližší menší celé číslo puts -3.14.round puts -3.14.ceil puts -3.14.floor
Nepřekvapí nás výsledek:
3 4 3 -3 -3 -4
Zbytek aritmetických operací je soustředěn v tzv. modulu Math a jejich vysvětlení přesahuje rozsah tohoto článku.
Řetězce
Řetězcové proměnné jsou v Ruby uchovávány v objektech třídy String. Jsou to v podstatě sekvence 8bitových znaků, takže v objektu String lze uchovávat i binární data (například načtená ze souboru). Obvykle se řetězce inicializují pomocí konstant uzavřených v uvozovkách nebo apostrofech a platí stejná pravidla pro vyhodnocování obsahu, jaká byla uvedena výše. Navíc nabízí Ruby pohodlnou cestu k inicializaci dlouhých, několikařádkových řetězců:
s1='Neinterpretuje\nse' s2="Interpretuje\nse 1+1 = #{1+1}" s3=<<KONEC Tento řetězec může mít několik řádků a končí až slovem, které je uvedeno za znaky '<<'. (Počítá se do něj i případné odsazení řádků.) KONEC puts s1 puts s2 puts s3
Výsledkem je:
Neinterpretuje\nse Interpretuje se 1+1 = 2 Tento řetězec může mít několik řádků a končí až slovem, které je uvedeno za znaky '<<'. (Počítá se do něj i případné odsazení řádků.)
Protože práce s řetězci je programátorovým denním chlebem, poskytuje String opravdu velké množství metod pro manipulaci s nimi. Uveďme si jen několik jednoduchých příkladů:
puts 'HellO'.downcase # převod do malých písmen puts 'hello'.upcase # převod do velkých písmen puts 'hello'.length # délka řetězce puts 'hello'.include?('el') # vrací 'true', pokud řetězec obsahuje parametr puts 'hello'.index('el') # pozice parametru v řetězci puts 'hello'.reverse # obrácený řetězec puts 'hello'.reverse.reverse # návratová hodnota je zase objekt, jehož # metodu můžeme volat puts ' hello '.strip # odstranění prázdných znaků ze začátku a konce puts 'hello'.tr('he','Ha') # zaměňuje znaky (jako příkaz 'tr' v UNIXu)
Získáme:
hello HELLO 5 true 1 olleh hello hello Hallo
Navíc můžeme počítat se silnými nástroji pro nahrazování a změny částí řetězců a pro práci s regulárním výrazy, o nichž bude ještě řeč.
Možná jste si již všimli konvence, kdy názvy metod vracejících hodnotu boolean končí otazníkem. Podobně exitují metody, jejichž název končí vykřičníkem. Vykřičník upozorňuje na to, že dochází přímo ke změně samotného objektu. (Normální metody vrací hodnotu, ale stav objektu zůstává nezměněn.)
a='hello' puts a puts a.reverse # jen vrať hodnotu puts a puts a.reverse! # vrať hodnotu a změň objekt puts a
Vrací:
hello olleh hello olleh olleh
True, false, nil
Nebudeme-li se snažit o zbytečnou složitost, můžeme říct, že v Ruby jsou definovány tři speciální hodnoty, kterých také může proměnná nabýt:
- true – označuje pravdu (např. pravdivý výsledek porovnání)
- false – označuje nepravdu
- nil – označuje prázdnou proměnnou (například nenalezený znak řetězce)
Použití osvětlí příklad:
puts 2<3 # to je pravda puts 3<2 # to není pravda puts 'abcd'.index 'r' # znak v řetězci není - vrací se doslova "nic"
S výsledkem:
true false nil
Příště se podíváme na další datové typy a operátory, řídící struktury a také si povíme něco o tom, jak Ruby podporuje mocnou zbraň skriptovacích jazyků – regulární výrazy.