V dnešním pokračování si povíme o balíčkovacím systému RubyGems, o vytváření GUI aplikací pomocí knihovny FXRuby a o také tom, proč je Ruby čistě objektově orientované i v případech, kdy nepoužijeme třídy nebo objekty explicitně.
Balíčkovací systém RubyGems
RubyGems je balíčkovací systém pro Ruby, který používají téměř všechny novější knihovny. Už z tohoto důvodu je vhodné si jej doinstalovat. Práce s RubyGems je poměrně pohodlná. Pokud například chceme nainstalovat nejnovější verzi knihovny „redcloth“, stačí zadat:
$ gem install redcloth
Pokud stojíme o určitou (nikoliv nejnovější) verzi, řekněme „redcloth“ verze 3.0.3, zadáme:
$ gem install redcloth -v 3.0.3
Skript gem
se podívá, zda příslušný balíček není v pracovním adresáři, a pokud ne, spojí se s centrálním úložištěm balíčků a stáhne jej odsud. Balíček se pak automaticky nainstaluje (případně i zkompiluje, pokud je to potřeba). RubyGems umožňuje i update nainstalovaných balíčků a další operace. Seznam příkazů získáme takto:
$ gem help command
Vlastní balíčky mají příponu .gem
, nicméně jsou to obyčejné archivy tar obsahující gzipovaný soubor s metadaty a gzipovaný tarový archiv s daty. Jako vedlejší efekt tedy s instalací RubyGems získáte i docela šikovné (bohužel nedokumentované) API pro práci s tar.gz
soubory.
Jedinou komplikací je, že RubyGems instalují balíčky jinam, než kde je Ruby normálně očekává. Pro použití souboru z balíčku nainstalovaného přes RubyGems pak obecně nestačí zadat jen require 'soubor'
. Jedna z metod je ilustrována v níže uvedeném výpisu GUI aplikace. Jako první se zavede pomocí require
vlastní RubyGems (řádek 1), ten přidá vlastní metodu require_gem
, kterou pak zavedeme soubor z balíčku nainstalovaného přes RubyGems. Další variantou je spouštět interpret Ruby s parametrem -rubygems
(je to vlastně volba -r
s parametrem ubygems
, která zařídí, že před vlastním skriptem se zavede soubor ubygems.rb
). Parametr může být i v proměnné prostředí s názvem RUBYOPT
, pak se soubor ubygems.rb
zavádí vždy.
Místo require_gem
(řádek 2) by mělo stačit i pouhé require
, protože RubyGems přepisuje chování této metody. Na příkladu jsem chtěl ale ukázat, že syntaxe Ruby zdánlivě obsahuje klíčová slova či příkazy, jako např. zmíněné require
, nicméně jsou to jen pouhé metody, v tomto případě z modulu Kernel. Můžeme tedy přidávat své metody nebo přepisovat funcionalitu existujících metod. Takže takto například můžeme přepsat metodu require
, aby pokaždé, když je volaná, navíc vypsala 'Volano require'
:
module Kernel
alias original_require require
def require(path)
puts 'Volano require'
original_require(path)
end
end
GUI aplikace
Ruby, podobně jako Perl, obsahuje v základní knihovně vazbu na GUI knihovnu Tk, která pochází z jazyka Tcl. Pokud ji chcete použít, je nutné mít nainstalováno Tcl/Tk v příslušné verzi. Já jsem si ovšem vybral knihovnu FXRuby. Je to vazba z Ruby na multiplatformní knihovnu FOX Toolkit. Knihovnu FXRuby nainstalujeme snadno pomocí RubyGems, nejlépe podle návodu z uživalelské příručky. V systému musí být samozřejmě nainstalovány i sdílené knihovny FOX Toolkitu v příslušné verzi. Uživatelé Windows, kteří si nainstalovali Ruby pomocí instalátoru, by měli mít FXRuby verze 1.0.x nainstalováno automaticky (používá ho FreeRIDE – IDE dodávané s instalací). Pro následující příklad jsem si ale nainstaloval FXRuby verze 1.2.6. V Linuxu je potřeba mít nainstalovánu sdílenou knihovnu FOX Toolkitu příslušné verze (FXRuby verze 1.2.x by mělo být kompatibilní s libFOX.so verze 1.2.y pro libovolné x, y). V MS Windows stačí nainstalovat binární gem FXRuby. Knihovna libFOX je k němu přilinkována staticky.
1: require 'rubygems'
2: require_gem 'fxruby'
3: require 'iconv'
4: require 'jmeniny'
5:
6: include Fox
7:
8: class JmeninyGUI < FXMainWindow
9: NOT_FOUND = '-- nenalezeno --'
10:
11: def jmeno_datum
12: if @text.value =~ /^ *([0-9]{1,2}\. *){2}$/
13: den, mesic = @text.value.split('.')
14: jmeno = Jmeniny.jmeno(den.to_i, mesic.to_i)
15: @text.value = @from_utf8.iconv(jmeno)
16: @text.value = NOT_FOUND unless jmeno
17: else
18: jmeno = @to_utf8.iconv(@text.value)
19: den, mesic = Jmeniny.den(jmeno)
20: @text.value = den ? "#{den}.#{mesic}." : NOT_FOUND
21: end
22: end
23:
24: def initialize(app)
25: super(app, "Jmeniny")
26:
27: code_page = PLATFORM =~ /win/i ? 'windows-1250' : 'iso-8859-2'
28: @from_utf8 = Iconv.new(code_page, 'utf-8')
29: @to_utf8 = Iconv.new('utf-8', code_page)
30:
31: @text = FXDataTarget.new("")
32: top = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)
33:
34: p = proc { jmeno_datum }
35:
36: FXLabel.new(top, @from_utf8.iconv('Zadej jméno nebo datum:')) do |theLabel|
37: theLabel.layoutHints = LAYOUT_FILL_X
38: end
39:
40: FXTextField.new(top, 20, @text, FXDataTarget::ID_VALUE) do |theTextField|
41: theTextField.layoutHints = LAYOUT_FILL_X
42: theTextField.setFocus()
43: end
44:
45: FXButton.new(top, @from_utf8.iconv('Jméno -> Datum a zpět')) do |jdButton|
46: jdButton.connect(SEL_COMMAND, p)
47: end
48:
49: FXButton.new(top, 'Konec') do |exitButton|
50: exitButton.connect(SEL_COMMAND) { exit }
51: end
52: end
53:
54: def create
55: super
56: show(PLACEMENT_SCREEN)
57: end
58: end
59:
60: if __FILE__ == $0
61: app = FXApp.new("Jmeniny", "FXRuby")
62: app.normalFont = FXFont.new(app, "Helvetica", 11, FONTWEIGHT_NORMAL,
63: FONTSLANT_REGULAR, FONTENCODING_EASTEUROPE)
64: JmeninyGUI.new(app)
65: app.create
66: app.run
67: end
Na aplikaci není nic složitého – kód se týká více knihovny FXRuby (viz dokumentaci) než vlastního Ruby. Povšimněte si jen volání konstruktoru nadřazené třídy (předka) na řádku 25, dále pak řádku 27, kde se zjišťuje, zda aplikace běží na Windows, či nikoliv, a dle výsledku se automaticky nastavuje kódování z UTF-8 do systémového kódování a zpět.
Za zmínku stojí i řádek 34, kde se do proměnné p přiřazuje objekt proc
. Je to vlastně převedení kousku zdrojového kódu (v našem případě je to jen volání metody jmeno_datum
) na běžný objekt. Ten se pak použije jako „akce“ přiřazená tlačítku (řádek 46).
Výsledný grafický interface aplikace pak vypadá takto:
Další GUI knihovny
Kromě výše uvedených knihoven Ruby/Tk a FXRuby jsou k dispozici tyto hlavní knihovny pro tvorbu GUI aplikací:
- WxRuby – vazba na C++ knihovnu wxWidgets (dříve wxWindows),
- Ruby/GTK2 – vazba na knihovnu GTK2 (součást projektu Ruby-GNOME2),
- SWin/VRuby- vazba na API MS Windows,
- QtRuby – vazba na knihovnu Qt (součást projektu Korundum),
- RubyWebDialogs zajímavý pokus o „lokální“ webovou aplikaci, kdy script spouští vestavěný webový server a GUI je zobrazováno pomocí HTML prohlížeče daného systému.
Volba knihovny bude záležet na vašich osobních preferencích a na požadované funkcionalitě. Ne všechny knihovny totiž zvládají složitější úlohy typu komunikace se schránkou nebo „táhni a pusť“ stejně snadno (nebo na všech platformách).
Ruby jako čistý OOP jazyk
V minulých dílech jsme si ukázali, že v Ruby je všechno (třeba i celočíselná konstanta) objekt, kterému můžeme posílat zprávy (jinak řečeno, na kterém můžeme volat metody). Šťourové ale řeknou: vždyť v Ruby lze napsat skript „neobjektově“ – prostě jen definujeme funkce a ty pak použijeme. Například takto:
# muj neobjektovy skript
def muj_soucet(a,b)
return a + b
end
puts muj_soucet(2, 3)
I výše uvedený příklad je však objektový. V tomto případě pracujete v kontextu objektu main. Objekt main je instance třídy Object
. A definicí „neobjektové“ funkce muj_soucet
definujete vlastně (singleton) metodu objektu main. Z praktického hlediska to sice není až tak podstatné, ale při chybovém hlášení se můžete dozvědět, že něco není v pořádku v kontextu objektu main třídy Object
. Znalost toho, co se děje „za scénou“, pak umožní lépe se orientovat v takových hlášeních.
Příště se podíváme, jak udělat webovou aplikaci.