Ruby v příkladech (1) - Úvod

1. 9. 2005
Doba čtení: 7 minut

Sdílet

Programovací jazyk Ruby u nás sice není (zatím?) tak rozšířený jako třeba Python nebo Perl, ale jeho čistě navržená objektová orientace, jednoduchá, ale mocná syntaxe a v neposlední řadě i pokročilost standardní knihovny z něj dělá jejich důstojného konkurenta.

Minulé Vánoce byla uvolněna verze 1.8.2 jazyka Ruby. Tento jazyk sice u nás není (zatím?) tak rozšířený jako třeba Python nebo Perl, ale jeho čistě navržená objektová orientace, jednoduchá, ale mocná syntaxe a v neposlední řadě i pokročilost standardní knihovny z něj dělá jejich důstojného konkurenta. V poslední době dozrály i některé projekty, které staví Ruby do konkurenční pozice také například vůči Javě v oblasti webových aplikací. Neotřelé je i použití Ruby pro spojení linuxových počítačů do clusteru nebo pro transformace XML dokumentů.

Pokud znáte nebo používáte jiný programovací jazyk, ale chtěli byste si Ruby také vyzkoušet, musím vás varovat:

Přejít z jiného jazyka na Ruby je snadné a příjemné, ale případný návrat bývá bolestivý. Takovou eleganci hned tak nenajdete.

Proč zrovna Ruby?

Na Ruby jsem před časem narazil, když jsem potřeboval nějaký nástroj pro skriptování a rychlou tvorbu jednodušších aplikací typu např. generování webových stránek. Chtěl jsem, aby byl multiplatformní (minimálně pro Linux a Windows), ne moc velký, ne moc složitý, ale objektově orientovaný. Dostatečně zralá a obsáhlá standardní knihovna (v mém případě včetně jednoduché manipulace s XML) byla také nutností. Chtěl jsem prostě něco, jako je Perl, který má sice výborné zpracování textu a regulární výrazy, jenže jeho syntaxe je mi poněkud nepříjemná a z provedení jeho objektové orientace přímo čiší, že byla dodělávána do páté verze neobjektového jazyka. Nevyhovuje mi ani syntaxe Pythonu, i když v ní nacházím více logiky než v Perlu. Ruby, ačkoliv je silně inspirován Perlem, má syntaxi opravdu elegantní. Názvy metod standardní knihovny jsou navrženy tak, aby si ani občasný programátor v Ruby, který zná jiný programovací jazyk, nemusel příliš lámat hlavu. Potřebujete-li zjistit délku řetězce nebo počet prvků pole v jiném jazyku, začnete přemýšlet (dívat se do dokumentace), zda ta správná metoda je „ length“, nebo „ size“. Ruby vás toho ušetří, neboť obsahuje obě metody (jsou zcela ekvivalentní).

Čtenáři znalí jazyků typu C++, Java, C#a podobných mají jistě slušnou představu o objektové orientaci (OO) ve staticky typovaných jazycích. Nicméně Ruby je opravdu čistý OO jazyk, takže zpočátku může překvapit, že všechno je zde objekt. Dokonce i samotné třídy jsou instance (tj. objekty) třídy Class. Takovýto jednotný přístup je ale jednak logický, jednak umožňuje některé elegantní konstrukce, které by jinak nebyly možné.

Další rozdíl je v tom, že Ruby je jazyk dynamický, a tak je úloha tříd oproti statickým jazykům poněkud oslabena. Třída určuje, kterým zprávám bude objekt rozumět (jinými slovy: které metody lze volat) při svém vzniku. Během života objektu se to ale může změnit – konkrétnímu objektu lze například později přidat metodu. Z toho také vyplývá poněkud odlišné pojetí polymorfismu, který zde nemusí být nutně spojen s dědičností.

Některé konstrukce v Ruby jsou podobné Smalltalku (např. uzávěry a bloky), nicméně Ruby má mnohem přijatelnější syntaxi (alespoň pro mne). Podobně jako v Perlu jsou proměnné beztypové, data však typy mají.

Instalace

V rozumných distribucích Linuxu bývá Ruby k dispozici ve formě balíčků. Stačí si ho prostě nainstalovat jako cokoliv jiného. Jedna připomínka: Některé distribuce mají sklon rozdělovat balíčky na tzv. „uživatelské“ a „vývojářské“. V takovém případě doporučuji raději nainstalovat i „vývojářskou“ část Ruby (mívá název např. ruby-dev). Pokud pro vaši (exotickou?) distribuci Ruby 1.8.2 není k dispozici, je potřeba stáhnout a zkompilovat zdrojový kód.

Uživatelé MS Windows mají hned několik možností. Nejjednodušší je použít „One-Click Ruby Installer, kde je zabaleno všechno, co je potřeba (hlavně všelijaké sdílené knihovny), a mnoho věcí navíc (např. editor SciTE, vývojové prostředí FreeRIDE, extra balíčky, dokumentace apod). Výhodou je, že máte vše pohromadě. Instalátor také nastaví Windows tak, aby se skripty napsané v Ruby daly spouštět přímo (tj. pouze zadáním jména souboru na příkazovém řádku, případně i bez přípony). Nevýhodou je, že instalátor má přes 13 MB a že ne všichni snášejí instalátory. Jinou možností je stažení archivu binární distribuce 1.8.2 (6 MB). Po rozbalení si pak ovšem musíte Windows zkonfigurovat sami (cesty apod.) a doplnit některé sdílené knihovny (minimálně readline.dll, iconv.dll a zlib.dll).

Ruby má dosti silnou pozici i u Maců, ale tam s instalací nemám žádné zkušenosti.

První kroky

Ačkoliv mi obvykle nepřipadá příliš užitečné začínat aplikací typu „Hello World“, učiním výjimku, abych demonstroval to, že v Ruby, podobně jako v Perlu, existuje vždy několik cest, jak dosáhnout cíle. Řekněmě, že chceme do proměnné přiřadit celé číslo a vypsat jej s nějakým textem na standardní výstup. Zde je několik možností. Nejprve jak je to typické pro Ruby:

cislo = 5
puts "Cislo je: #{cislo}" 

První řádek přiřadí proměnné s názvem cislo celočíselnou hodnotu 5. Druhý řádek volá metoduputs s parametrem typu řetězec (String). Všimněte si konstrukce „ #{}“. Pokud se vyskytuje v řetězci ohraničeném uvozovkami, ve složených závorkách lze uvést výraz, jehož výsledek se převede na řetězec (tj. na objektu, který je výsledkem výrazu, se zavolá metoda to_s ). Všimněte si, že parametr metody není v závorce. Ruby to (někdy) nevyžaduje, nicméně se závorkování parametrů metod spíše doporučuje. Lépe by tedy druhý řádek měl být:

puts("Cislo je: #{cislo}") 

Pokud se vám líbí jazyk C, můžete se stejným výsledkem použít i tuto konstrukci:

cislo = 5
printf("Cislo je: %d\n", cislo) 

Kdo ovládá C++, může zase použít:

cislo = 5
$stdout << "Cislo je: " << cislo << "\n" 

Přestože syntaxe Ruby spíše vede k přehledným programům, zkrátka nepřijdou ani vývojáři mající v oblibě krkolomější konstrukce, nad kterými si mohou lámat hlavu hned další den:

IO.new(1,'w').<<('Cislo je: '.+((cislo = 5).to_s).<<(10)).flush() 

Chcete-li výše uvedené skripty vyzkoušet, můžete si pustit interaktivní Ruby (příkazem „irb“ z shellu) a příkazy ze skriptů zadat ručně. Interaktivní Ruby je výborný k experimentům, přímému provedení primitivních skriptů nebo může posloužit jako kalkulačka s mnoha funkcemi. Podrobnější informace o „irb“ i o tom, jak skripty spouštět ze souborů, najdete ve starším (nicméně stále aktuálním) článku „Ruby z rychlíku (1)“.

Věnujme se ale něčemu praktičtějšímu. Dosti často potřebuji provést nějakou manipulaci se soubory. Například převést názvy souborů stažených z digitálního fotoaparátu na malá písmena. V Ruby jsou pro tyto účely k dispozici třídyDir a File (mimo jiné). V tom mi pomůže jednoduchý skript:

Dir.glob('*.JPG') { |fname| File.rename fname, fname.downcase } 

Skript, či vzhledem k jednoduchosti spíše jen příkaz zapsaný přímo v „ irb“, načítá jednotlivá jména souborů aktuálního adresáře, která vyhovují zadané masce. Na každé jméno (typu String ) se pak aplikuje blok (tj. ten kód, co je ve složených závorkách). Jméno souboru je do bloku vždy předáno jako parametr s názvem fname. Metoda rename třídy File pak daný soubor vždy přejmenuje. Nové jméno souboru je vytvořeno převedením fname na malá písmena. To zařizuje metoda downcase volaná na instanci (objektu) fname třídy String.

Pro častější použití lze skript zdokonalit, aby se soubory, které se mají přejmenovat, zadávaly na příkazové řádce. Protože pak je ale možné zadávat soubory včetně názvů adresářů, je nutné převádět na malá písmena vždy jen základní jméno souboru, nikoliv však název adresáře. V následujícím skriptu je použita víceřádková varianta bloku (klíčová slovado aend místo složených závorek). Pro manipulaci se jmény souborů a přejmenovávání je zde tentokrát použita třída Pathname , což je elegantní fasáda funkcionality tříd FileDir.

require 'pathname'

ARGV.each do |fname|
  p = Pathname.new(fname)
  dir, base = p.split
  new_name = dir.join(base.to_s.downcase)
  p.rename(new_name)
end 

První řádek s klíčovým slovem require způsobí zavedení souboru „ pathname.rb“ ze standardní knihovny (pro šťouraly a pokročilé: require

není vlastně klíčové slovo, ale obyčejná metoda z modulu Kernel ).
ARGV je pole argumentů z příkazového řádku — v našem případě půjde o jména
souborů. Pokud na příkazovém řádku uvedete masku (např.
*.JPG), expanduje do názvů jednotlivých souborů. Metoda each
je iterátor po jednotlivých prvcích pole ARGV. Objekt p je
instance třídy Pathname ,
kterou metoda split

rozdělí na adresář (dir) a základní jméno souboru (base). Na tomto řádku si také všimněte vícenásobného přiřazení. Nové jméno souboru (new_name) vytvoříme připojením základního jména převedeného na malá písmena k adresáři. Soubor nakonec přejmenujeme metodou rename .

Práce se soubory je obvykle základem (nejen) jednoduchých skriptů. Kromě třídyPathname (nebo případně tříd Dir a File ) se může pro tyto účely hodit i modul FileUtils , který obsahuje prostředky pro kopírování, přesouvání a porovnávání souborů, rekurzívní kopírování, vytváření linků, kaskádové vytváření adresářů apod. Modul Find , pak obsahuje metodu pro aplikaci bloku na soubory ve vyjmenovaných adresářích včetně podadresářů.

Dokumentace

Celá dokumentace standardní knihovny Ruby je dobře dostupná na Internetu na www.ruby-doc.org/core/ a www.ruby-doc.org/stdlib/. Ruby samotné obsahuje utilitu „ri“, která umí vypsat dokumentaci ke třídě nebo metodě. Použití je snadné. Utilita „ri“ se volá z shellu (ne z Ruby), např.:

ri Pathname
ri Pathname.split 

Výjimečně se může stát, že metodu s určitým názvem lze volat jak pro třídu, tak i pro instanci (pozor, jde obecně o různé metody!). V programu ri to upřesníme takto:

bitcoin školení listopad 24

ri File::mtime   # metoda tridy File
ri File#mtime    # metoda instance tridy File 

Zápis File#mtime se samozřejmě používá jen pro program ri, nikoliv v kódu Ruby.

Pro dnešek je to vše a příště se podíváme na složitější skripty.