Naprostá většina informací na internetu je dostupná pomocí protokolu HTTP. Ukážeme si, jak jednoduché je načíst v Ruby obsah webové stránky a aby toho nebylo málo zkusíme si první aplikaci s grafickým uživatelským rozhraním (GUI).

Minule jsme používali část standardní knihovny skrývající se pod cestou net/ftp. Tentokrát potřebujeme net/http. Knihovna obsahuje poměrně dost tříd, které podporují rozmanité vlastnosti protokolu HTTP. Pro naše účely však zcela postačí třída Net::HTTP. Ta definuje metodu get, která provede požadavek GET podle HTTP protokolu a výsledek vrátí jako řetězec. Pro začátek nebudeme načítat a zpracovávat žádný složitý obsah. Pro naše experimenty využijeme Strahovský teploměr, který již dlouhá léta na adrese http://teplomer.sh.cvut.cz/servlet/teplota poskytuje aktuální údaj z teploměru ve formě prostého textového řetězce. Ale dost povídání, podívejme se, jak to vypadá v kódu.

irb(main):001:0> require ‚net/http‘
=> true
irb(main):002:0> res = Net::HTTP.get(‚teplomer.sh.cvut.cz‘, ‚/servlet/teplota‘)
=> „20.3“
irb(main):003:0> res.to_f
=> 20.3
irb(main):004:0> Net::HTTP.get(‚www.interval.cz‘, ‚/‘).size
=> 84

Jak je vidět, obdržený řetězec snadno převedeme na reálné číslo pro případné další zpracování. Metodou get lze samozřejmě načítat i obsah v HTML. Celý formát volání je get(uri_or_host, path = nil, port = nil). Cesta je nepovinná, stejně tak poslední parametr port, který je defaultně obvyklých 80. První parametr je buď název cílového počítače nebo objekt třídy URI. Pokud bychom dostávali na vstupu URL, více by se nám hodilo volání v následující podobě.

irb(main):007:0> Net::HTTP.get(URI.parse(‚http://teplomer.sh.cvut.cz/servlet/teplota‘))
=> „20.1“

Jako u každé metody pracující se vstupem a výstupem může i v případě get vznikat spousta různých výjimek, které je v reálném životě třeba ošetřovat. Zkusme vytvořit kostru programu s jednoduchou metodou, která zajistí bezpečné načtení teploty. V případě vzniku chyby vrátí zvláštní hodnotu, která bude chybu indikovat. Protože teplotu budeme chtít zobrazovat, zajistíme si rovnou rozumné formátování výstupu.

require ‚net/http‘
 
def read_temperature
Net::HTTP.get(‚teplomer.sh.cvut.cz‘, ‚/servlet/teplota‘).rjust(5)
rescue
‚ xx.x‘
end
 
puts read_temperature

Na výpisu vidíme definici metody a zatím neznámé použití klauzule rescue. V rámci definice metody nám Ruby umožňuje vynechat začátek bloku pro ošetření výjimek v podobě klíčového slova begin. Respektive místo něho je začátkem bloku začátek metody. To nám v kombinaci s faktem, že návratovou hodnotou metody je hodnota posledního vyhodnoceného výrazu, umožňuje elegantně popsat zpracování v případě s chybou i bez chyby jen na několika řádcích. Řetězcová metoda rjust zarovná vrácený výsledek, který je ve tvaru -nn.n, kde n jsou číslice a na začátku může a nemusí být záporné znaménko. Zarovnání proběhne doplněním mezery, aby výsledek měl dohromady pět znaků i když zrovna nemrzne.

c:>ruby strahov.rb
19.9

Jak jsem slíbil, dáme teď teploměru GUI kabátek. Pro Ruby existuje vícero knihoven zajišťujících propojení s prakticky všemi rozšířenějšími grafickými toolkity. Pro naše potřeby bude nyní nejvhodnější jedna ze starších knihoven, která využívá toolkitu s prozaickým názvem ‚tk‘. Vhodný je zejména proto, že bývá dostupný na všech platformách, kde je k dipozici Ruby a obvykle není potřeba ničeho jiného než použití příslušbného ‚require‘. Práce s toolkitem není složitá. Pro začátek jsem opět mírně zadaptoval příklad z knihy Hala Fultona Ruby – kompendium znalostí pro začátečníky i profesionály. Informace o ní najdete na tomto serveru.

require ‚tk‘
 
root = TkRoot.new() do
title „Datum“
end
str = Time.now.strftime(„Dnes jen%d.%m.%Y“)
lab = TkLabel.new(root) do
text str
pack(„padx“ => 15, „pady“ => 10, „side“ => „top“)
end
Tk.mainloop

Takto jednoduchá GUI aplikace vzniká postupně v několika krocích. Vždy vytvoříme některý prvek grafického rozhraní a předáme mu blok, ve kterém lze volat metody nastavující různé vlastnosti právě vytvářeného prvku. Na konci spustíme metodu mainloop, která zajišťuje cyklus, ve kterém aplikace běží a čeká na události – například kliknutí na některý z prvků. Zde jsme nejdříve vytvořili hlavní okno aplikace a nastavili mu popisek. Referenci na okno máme uloženu pod názvem root. Dále si zformátujeme řetězec s dnešním datem a vytvoříme textový popisek, kterému nastavíme jako obsah tento text. Pomocí metody pack říkáme knihovně, jakým způsobem má prvek zobrazit. Pojmenované parametry metody zadané ve formě hashe říkají, že prvek má být odsazen horizontálně o 15 pixelů a vertikálně o 10 a text má být zarovnán na střed.

Spuštěnou aplikaci lze ukončit pouze standardním ovládacím prvkem operačního systému – v případě Windows křížkem v pravém horním rohu. To však nyní nebudeme řešit a pokusíme se raději příklad zkřížit s předchozím kódem pro stahování teploty. Následuje ukázka jednoho možného řešení.

require ‚tk‘
require ‚net/http‘
 
TXT = „Teplota jen%s“
 
def read_temperature
Net::HTTP.get(‚teplomer.sh.cvut.cz‘, ‚/servlet/teplota‘).rjust(5)
rescue
‚ xx.x‘
end
 
def refresh_temperature(lab)
lab.text = sprintf(TXT, read_temperature)
end
 
root = TkRoot.new() do
title „Teplota“
end
lab = TkLabel.new(root) do
pack(„padx“ => 15, „pady“ => 10, „side“ => „top“)
end
TkButton.new(root) do
text „Obnov“
command(proc { refresh_temperature(lab) })
pack(„padx“ => 15, „pady“ => 10, „side“ => „top“)
end
refresh_temperature(lab)
Tk.mainloop

Hlavní část programu vypadá velmi podobně jako předchozí ukázka. Navíc je přidáno tlačítko, které při stisknutí spouští metodu refresh_temperature. Ta má za úkol nastavit text textového popisku. Šablona textu je uložena v konstantě TXT a využíváme metody sprintf, abychom do šablony dosadili řetězec načtený z webu. Metoda sprintf má jako první parametr formátovací řetězec – šablonu, která může obsahovat zástupky, které jsou pak nahrazeny dalšími parametry metodami. Zástupka %s je pro řetězcový parametr. Stisknutím tlačítka se tedy popisek nastaví na šablonu s doplněnou aktuální teplotou.

Vytvořená aplikace je velmi primitivní. Může ale posloužit jako základ a po dalším zdokonalování se stát užitečnou pomůckou. Možná se k ní vrátíme v některém z příštích dílů.

3 Příspěvků v diskuzi

  1. Mám dotaz trochu mimo téma, sice v poslední době třeba nemám příliš čas sledovat každý nový článek seriálu, tak když už někdy chvilku vyšetřím, tak je čtu tzv. po vícero, tedy chtěl bych vznést takovou malou žádost, zda by nemol být na konci každého článku odkaz na předchozí a následující článek. Přehled „Souvisejcích článků“ je sice fajn věc, ale je to o něco chaotičtější než fce „tam a zpět“.

Odpovědět