Jak urychlit RubyGems na Ma OS X Leopard?
Rychlost RubyGems na Leopardovi je opravdu mizerná. Naštěstí není vůbec problém RubyGems výrazně urychlit.Jaké bylo EURUKO 2008?
EURUKO je evropská konference o Ruby. Jaká byla? Co nám pověděl Matz na své keynote? Co všechno lze dělat v JRuby? Co nového se chystá v NetBeans 6.1? A jak je vlastně rychlý YARV?Jak nainstalovat ImageMagick a RMagick na Mac OS X?
RMagick je jeden z absolutně nejproblematičtějších gemů. Jak jej nainstalovat na Leoparda?Road to Mongrel
Vlastní server to je spousta práce, ale také spousta zkušeností. Od hrátek s aptitude přes nastavovaní systému a konečně konfiguraci apache jsem se dostal k deploymentu vlastních Rails aplikací. Klasické první “Hurá!”, když se první pokus rozbělh pod hloupým (a pomalým) CGI nastalo už docela dávno. Od té doby jstem se stihl naučit pracovat s FastCGI (přesněji řečeno mod_fcgid) a všecko běhalo rychle a spolehlivě. Problém je, že fcgi procesy spawnuje (hnusné slovo, já vím) apache a proto bylo potřeba vydat se cestou k hoře jménem Mongrel.
Vezmu to ale pěkně popořádku. Development máme za sebou a v subversion se na nás směje aplikace jakš-takš připravená na nelítostné světlo intenetového světa. Co s tím?
Krok první: Capistrano
Neznáte? Ale jo, určitě znáte. Já si si s Capistranem už několikrát v minulosti zahrával, ale v podmínkách, jaké nabízel Websupport, to prostě nějak nedávalo smysl a skončil jsem u vlastních updatovacích skriptů (jo jo, mělo to i jakýsi rollback). Na vlastním stroji (nebo i vserveru) je situace kapku jiná. Capistrano je prostě nutnost. Pokud jste s Capem v minulosti také hráli, ale pořád to bylo jakési moc složité, zkuste to dnes znovu. Verze 2.x už jsou nějakou dobu venku a konfigurace je konečně jednoduchá jako facka. No posuďte sami:
set :application, "myapp"
set :repository, "http://path.to/yourapp/svn/trunk"
set :user, "remote_ssh_user"
set :deploy_to, "/deployment/root/#{application}"
role :app, "www.myapp.cz"
role :web, "www.myapp.cz"
role :db, "www.myapp.cz", :primary => true
Jasně, je to konfigurace kdy všechno běží na jednom serveru, ale stejně, je to sranda. Rozeberme si to. Název aplikace nemá žádný zvláštní význam, můžete ho dále použít jako proměnou (třeba v deploy_to). Následuje cesta ke zdrojákům v SVN. Proměnná user se hodí v případě, že vaše uživatelské jméno na lokále je jiné než to na serveru. deploy_to říká, ve kterém adresáři na serveru bude cap operovat. A pak už stačí jenom třikrát copy&pastnout url serveru, na který se bude nasazovat. Ještě před prvním spuštěním cap příkazu si vytvořte soubor script/spin. Nemusí nic dělat, ale pokud chcete může nastartovat váš první Mongrel. U mě nedělá nikdy nic. Proč? Dozvíte se níže. Teď jenom udělejte následující:
$ cap deploy:setup # vytoří adresářovou strukturu
$ cap deploy:cold # studený deploy - když aplikace ještě neběží
Je libo nahrát na sever poslední změny?
$ cap deploy
Je libo vrátit se zpět, páč se něco po*ralo?
$ cap rollback
Nakonec používate-li cgi, fcgi nebo tak něco, tak doporučuju nastavit svn:executable propety u následujících souborů:
script/**
public/dispatch.*
No a i když nic z toho nepoužíváte, udělejte to stejně. Uštříte hromadu problémů v budoucnu.
Kdok druhý: Pipe | Switch | Pipe
Jak jsem už říkal já si nějakou dobu, vystačil s krokem jedna a mod_fcgid. Jedna věc mě na tom ale docela štvala. Součástí mého deployment recipe (termínus technikus pro config/deploy.rb) musel být následující kód:
task :restart_web_server, :roles => :web do
sudo "/etc/init.d/apache2 restart"
end
after "deploy:start", :restart_web_server
after "deploy:restart", :restart_web_server
Prostě fuj. Nepatřím mezi early-adopters nadšence, ale o SwitchPipe se už nějakou dobu píše jako upload & run deployment řešení pro Rails. Narozdíl od mod_rails je už dnes k dispozici, tak proč ho nezkusit? SwitchPipe je jednoduchý, ale velmi mocný process-manager. Prostě spouští a zabíjí procesy jak je potřeba a to je přesně to co kombinace Rails & Monrel potřebuje. Konfigurace? Trivka! Dejme tomu, že máte nastavený virtual-host a vaše aplikace už nějak běží. Jak přejít na SwitchPipe? Nejřív si ho musíte naintalovat, což v podstatě sestává z následujícího:
$ svn co http://switchpipe.org/switchpipe1/tags/release-1.04 \
/usr/local/switchpipe
$ cd /usr/local/switchpipe
$ cp # config.yml.example # config.yml
Pak je ještě dobré zajistit start SwitchPipe démona po startu zalinkováním script/initdscript do /etc/init.d a toho pak do /etc/rc3.d. A včíl už jenom ty aplikačky. V adresáři switchpipe/apps hledá démon změny a pokud nějaké najde hned reaguje. Konfigurujeme v YAML. Příklad najdete na stránce o konfiguraci a fakt na to není třeba nic vymýšlet. Stačí čtyři řádky, save a cluster mongrelů čeká na requesty. Poslední věci, kterou je třeba udělat, je zahodit celý den dlouhý a složitý .htacces, který generují Rails a nahradit jej následujícím:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ http://127.0.0.1:10000/myapp/$1 [P]
Nezapomeňte myapp nahradit návem konfiguračního .yml souboru.
Závěr: A co ty restarty?
Ironií osudu je, že SwitchPipe zatím neumí elegantně restartovat cluster pro jednu aplikaci. Je to ale subjektivní. Jakákoli změna konfigurace clusteru způsobí jeho reload (kill všech procesů a začně se znova). Co s tím teda? Řešení se jmenuje touch a pomůže nám s ním opět Capistrano.
task :restart_cluster, :roles => :web do
sudo "touch /usr/local/switchpipe/apps/myapp.yml"
end
after "deploy:restart", :restart_cluster
No a teď se o deployment stará Capistrano a restartují se jenom Mongrely příslušné k aktualizované aplikaci. A ještě k tomu nastavování byla fakt sranda, žádné hledání zakopaného psa jako s mod_fcgid.
$ cap deploy
Sake: single-line scripts sssucks!
Jistě to znáte. Máte spousty nápadů, co se dá snadno automatizovat. Napíšete si tedy skript, který se vejde třeba na řádek nebo dva. Po určitém čase máte skripty všude a nevíte k čemu je který. A řešení? Sake!mod_rails: Rails deployment vyřešen?
Tak to vypadá, že problematičnost deploymentu Rails aplikací bude brzo minulostí. mod_rails je prozatím jenom video prezenetující, že upload & run postup známý PHPkářům je možný i s Rails. Video například tvrdí, že prvotní instalace zabere pouhé dvě minuty. To je sice pěkné, ale já to beru spíše jako minimum. Nevím proč, ale vždycky, když začnu něco kompilovat, se mi to napoprvé nějak nepodaří. Oficiální bechmarky sice zatím nejsou, ale můžete se dočíst, že výkonnost je stejná jako u mongrelu. Každopádně považuju mod_rails za pozitivní událost. Někteří jsou, ale jiného názoru. Podle mě docela zcestně. Široká adaptace Rails sice přinese určité změny v core komunitě, ale že by měla znamenat konec světa? To asi ne.
Odkazovníček pro měsíc březen
Zajímavé odkazy z celého internetu. Dnes si povíme, jak fixnout problém s diakritikou v IRB v Leopardu, vygenerujeme si mikroformáty a ukážeme si tip pro práci s regulárními výrazy.RSpec: vyprávění nebo testování?
RSpec je implementací BDD. Vyznačuje se velmi čitelnou syntaxí a tím, že zároveň slouží k dokumentaci kódu. Dnes technický úvod a odkazy.Úvod do testování v Ruby
Testování, bolístka mnoha programátorů. Pokud jste z těch, co ještě testovat nezačali, mám pro vás drobné popostrčení.A použijte to ... no ... jak ono se to jmenuje?
Drobný tutoriálek o tom, jak najít metodu, která vím co dělá, ale nevím, jak se jmenuje.Rozcestník: kam na Ruby na českém internetu?
Česká komunita okolo Ruby a Rails roste čím dál tím více. Abyste měli přehled, kde všude je živo, připravil jsem drobné shrnutí.Triky pro práci s proměnnými prostředí Ruby
Proměnné prostředí ovlivňují výrazně běh programů v Ruby a určitě se je vyplatí znát. Lze přes ně nastavit jak defaultní argumenty, tak cesty, v nichž bude Ruby hledat své knihovny.Drobný hack aneb jak na „staticky typované“ Ruby
Dynamické typování je skvělá věc, ale občas bychom raději použili typování statické. To Ruby sice nemá, lze si ale trochu vypomoci.Parser bankovních výpisů aneb hrátky s Ragel
Nedávno jsem dostal nelehký úkol: parsovat bankovní výpisy České spořitelny. Formátování vstupních dat je ale velmi nestandardní a často se nedrží ani vlastních pravidel. Hledal jsem proto vhodný parser, který by si s problémem poradil. Nakonec jsem využil Ragel, jehož použití je všestranné a pohodlné.Hrátky s Unicode identifkátory v Ruby
Na Silvestra vydal Jakub Vrána nevážně míněný článek o
patchi, který umožňuje používat v PHP různé symboly z Unicode – třeba
operátor ≤ nebo funkci √. Vzhled programu se tak
přibližuje matematickému zápisu.
Hned po přečtení textu jsem začal přemýšlet nad tím, jak něco podobného spáchat v Ruby. Ruby totiž povoluje Unicode znaky v identifikátorech, a není tak ani třeba upravovat interpret, jako bylo nutné v případě PHP.
Pro další čtení doporučuji nejdřív přečíst zmiňovaný Jakubův článek, abyste byli v obraze. Tento text z něj totiž svým uspořádáním vychází.
Konstanty
Definice hodnot s názvy jako ½ či ¼ není v Ruby
problém:
½ = 0.5
¼ = 0.25
⅜ = 0.375
π = Math::PI
puts ½ # => 0.5
puts ¼ # => 0.25
puts ⅜ # => 0.375
puts π # => 3.14159265358979
Občas by se mohla hodit i prázdná množina nebo nekonečno:
∅ = []
∞ = 1.0 / 0.0
puts ∞ # => Infinity
Bohužel na rozdíl od opatchovaného PHP si tyto hodnoty nemůžeme definovat jako konstanty, neboť konstanty musí v Ruby začínat velkým písmenem. Musí postačit obyčejné proměnné.
Operátory
Psát v Ruby výrazy jako 1 ≠ 2 by bylo hezké, bohužel to ale tak
úplně nejde, protože Ruby neumožňuje definovat vlastní operátory (z jazyků, co
aspoň trochu znám, tohle umí jen Haskell). Pokud ale přežijeme volání "přes
tečku", můžeme si vytvořit aliasy pro odpovídající metody na numerických třídách
a volat pak je:
class Fixnum
alias ≠ != # nefunguje v Ruby 1.8.x
alias ≤ <=
alias ≥ >=
alias × *
alias ÷ /
# ...
end
# Analogicky i pro třídy Bignum a Float...
puts 1.≠ 2 # => true
puts 3.× 4 # => 12
puts 6.÷ 2 # => 2
Další matematika
Je libo odmocňovat pomocí funkce √? Stačí přidat alias do modulu
Math:
module Math
alias √ sqrt
end
Po inkluzi modulu už odmocninu můžeme používat:
include Math
puts √ 9 # => 3
Sumu (∑) nebo součin (∏) už jako alias definovat
nemůžeme, protože Ruby nemá vhodné metody, na které by šly tyto názvy namapovat.
Budeme si je tedy muset napsat (a to hezky funkcionálně :-)
def ∑(array)
array.inject(0) { |sum, item| sum item }
end
def ∏(array)
array.inject(1) { |product, item| product * item }
end
puts ∑ [1,2,3,4] # => 10
puts ∏ [1,2,3,4] # => 24
Čistější by samozřejmě bylo definovat metody ve třídě Array,
nebo ještě lépe v modulu Enumerable.
V Ruby 1.9.0 bychom díky vylepšené metodě Enumerable#inject mohli
definice součtu a součinu ještě o trochu zkrátit:
def ∑(array)
array.inject(0, : )
end
def ∏(array)
array.inject(1, :*)
end
Lambda
Pokud jste se nahlédli do seznamu novinek Ruby 1.9.0, možná jste si všimli nové syntaxe pro lambda funkce:
f = ->(a, b){ a b }
puts f.call(1, 2) # => 3
Matzovi (tvůrci Ruby) znaky "->" údajně po menší rotaci a translaci připomínají písmenko "lambda". Jelikož mě ne, rozhodl jsem se lambdu nadefinovat po svém:
module Kernel
alias λ lambda
end
f = λ { |a, b| a b }
puts f.call(1, 2) # => 3
Pozor, nebezpečí!
V Ruby je (po vzoru Lispu) zvykem označovat metody, které "nebezpečně" modifikují obsah objektu, pomocí vykřičníku na konci jejich názvu:
s = "ABCD"
s.downcase!
puts s # => "abcd"
Pokud se vám to ale zdá málo výrazné, není problém použít jiný znak:
class String
alias downcase☠ downcase!
undef downcase!
# Podobně s dalšími metodami...
end
s = "ABCD"
s.downcase☠
puts s # => "abcd"
Chcete si taky hrát?
Na případné hraní s Unicode doporučuji stáhnout čerstvé Ruby 1.9.0, které podporuje specifikaci kódování zdrojáku přímo v souboru – na první řádek stačí napsat například toto:
# encoding=utf-8
V Ruby 1.8.x Unicode identifikátory fungují taky, ale při spuštění programu, který je používá, je nutno použít volbu -Ku, která přepne Ruby do režimu UTF-8. Tato volba funguje i v Ruby 1.9.0.
Šup sem s Ruby 1.9.0
Ruby 1.9.0 je v tuto chvíli k dispozici jen jako balík se zdrojovým kódem, který je nutno rozbalit a zkompilovat.
Pokud to uděláte, tak při spouštění ./configure doporučuji použít volbu --prefix a specifikovat adresář, kam se Ruby 1.9.0 po zkompilování nainstaluje. Nehrozí tak, že by nově zkompilovaná verze přepsala verzi nainstalovanou v systému.
Na mém Ubuntu 7.10 proběhla kompilace Ruby 1.9.0 bez problémů a stačilo napsat variaci na obvyklou "svatou trojici" příkazů:
./configure --prefix=/home/dmajda/ruby19 make sudo make install
Ke stažení
Příklady uvedené výše si můžete stáhnout hezky pohromadě v jednom souboru: unicode-fun.rb.
A to je konec...
alias † exit
†
Použité zdroje
- Mail Davida Flanagana a navazující vlákno v mailing listu ruby-core
- Changes in Ruby 1.9
Dodatek k článku "Ruby 1.9.0 - zpackané vydání?"
Můj týden starý článek Ruby 1.9.0 - zpackané vydání? vyvolal poměrně silnou negativní odezvu. Přesněji řečeno, tuto odezvu vyvolal spíše článek Jakuba Šťastného Ukvapené vydání Ruby 1.9?, který vyšel na Rootu. Tento článek ale z toho mého vycházel a odezva na něj se tak dotýká i mě.
Čeho se odezva týkala? Můj (i Jakubův) článek kritizoval způsob vydání Ruby 1.9 a vycházel přitom z toho, že 1.9 je v zásadě další běžná verze tohoto jazyka. To není pravda – Ruby 1.9 je verze vývojová a není určena pro běžné uživatele. V tomto kontextu pak zmíněná kritika ztrácí z velké části význam.
Kde byla chyba?
V komunikaci.
Pro běžného čtenáře je věc jasná – podívá se na web a u Ruby 1.9 vidí zřetelné označení development release. Cesta k napadání článku za ignorování základních faktů je volná.
Běžný čtenář už bohužel nevidí to, že definice toho, co to vlastně 1.9 je, se v čase dost měnila. Ještě v roce 2006 bylo například Ruby 1.9 označováno za budoucí stabilní verzi a i některé Matzovy maily z podzimu 2007 nevyznívají rozhodně jednoznačně.
Mojí chybou bylo, že jsem Matzova prohlášení ve stylu "1.9 bude možná méně stabilní než bychom chtěli" interpretoval jako "1.9 bude v zásadě stabilní, jen bude mít trochu více bugů, než je u nových verzí Ruby zvykem", zatímco realita byla spíš něco jako "1.9 bude jen o málo víc než aktuální snapshot vývojového stromu".
Na druhou stranu, nejsem jediný, kdo byl zmaten. Třeba v mailing listu debian-ruby se ještě během podzimu o 1.9 také diskutovalo jako o příští stabilní verzi.
Jak by se nedorozumění dalo předejít?
Když pominu chybu na mé straně, zbývá jedno – zlepšit komunikaci na straně vývojářů Ruby.
Komunikací myslím především jasně, včas a veřejně (tj. na webu, ne v nějakém zapadlém mailing listu) definovat, co jednotlivé verze znamenají a jaká je motivace jejich vydání. Pomohl by i podrobnější plán vývoje do budoucna.
Nástrojem komunikace je ale třeba i číslo verze – 1.9 vypadá na první pohled jako následovník 1.8. Označení verze například jako "2.0 Development Snapshot 1" by reálný stav věci myslím vystihovalo lépe a nikdo by tuto verzi určitě nepovažoval za stabilní.
Vývojáři Ruby s Matzem v čele by si měli uvědomit, že Ruby už není malá hračka, ale nástroj, na nějž mnozí spoléhají a jehož vývoji přizpůsobují i vývoj svých produktů. A na to, co tvůrce jazyka jednou o nějaké budoucí verzi řekne, lidé spoléhají a leckdy na základě toho investují do něčeho nemalé úsilí.
A co z článku zůstává?
Myslím, že i přes výše uvedené zůstávají některá tvrzení z mého článku v platnosti. Ani vývojovou verzi není například správné vydávat s nefunkčními testy. A stále se domnívám, že vývoj Ruby je až příliš chaotický a Matz není dobrý vedoucí projektu. Když už pro nic jiného, tak proto, že výše uvedené problémy v komunikaci nevidí a/nebo neřeší.
Spousta omylů ohledně Ruby 1.9.0
Je to pár dní co mi několik nezávislých zdrojů přes RSS čtečku sdělilo, že Ruby 1.9.0 je na světě. Jelikož tento release nese označení development release nechával mě úplně klidným, protože to znamená, že pro proukci je nepoužitelný a na testování nových fíčur nějak nemám energii. Čláky jsem nicméně pročetl a nové Ruby se změnami, o kterých se píše už měsíce, jsem ignoroval. V podstatě pro mě tento release nemá žádný význam.
Dnes mě ale Google Reader překvapil českými reakcemi na Ruby 1.9. Článek na Rootu považuje release za ukvapený. Tak aspoň zní honosný titulek, nikde ale není vysvětleno co je na development relase ukvapeného. Článek dále cituje tento výlev Davida Majdy, který je opět protkán nepochopením.
Nechci zde nikoho odsuzovat ani obhajovat, protože je nutno přiznat, že obě strany mají tak trochu pravdu. Čeští kritikové to nicméně vzali za špatný konec. Z mého pohledu udělal největší chybu Matz, a to tu, že nikde (nebo aspoň nikde viditelně) není oznámeno, že 1.9.0 není nástupce 1.8.x, ale předchůdce na cestě k 2.0. Co to znamená?
Normálně by člověk předpokládal, že když se sníží minor verze produktu (to druhé číslo) tak je zachována zpětná kompatibilita. Tady to z již zmíněných důvodů neplatí.
Matz udělal chybu, protože na letmý pohled vypadá 1.9.0 jako nástupce 1.8.6, ale označení development release by mělo odratit ty co hledají spolehlivý a stabilní produkt.
Krikitové udělali na druhé straně chybu tu, že místo toho aby Ruby povzbudili na cestě k verzi 2.0 děsí se nad nekompatibilitou a chybami ve vývojářské verzi.
Osobně bych rozšiřování syntaxe spíše zavrhoval a soutředil se na zvyšování rychlosti a nativní podporu Unicode. Nakonec je ale tento release dobrá věc, spoustu lidí co ho nepochopí znechutí a otevře místo pro zkoušení alternativních implementací.
Java jsou tupé núžky..
..je odpověď Dava Thomase na nářky (které jsme diskutovali i u nás), že Ruby dovoluje programátorům příliš mnoho. Tím ale veškerá kontroverze končí, video, na které chci poukázat, již pak obsahuje jen vysoce zajímavé ukázky toho, co Ruby dokáže na poli metaprogramování a jak se toho využivá v Railsech. Hodinka strávená sledováním přednášky MetaProgramming - Extending Ruby for Fun and Profit podle mě promarněná určitě není.
A když už jsem v tom linkování, našel jsem zajímavý koncentrát článků o Ruby/Railsech jménem Ruby Galore (jenom separátní doména tzv. "blog komunity" SocialRanku, ale to je vedlejší). Kromě slavného a brzy ještě slavnějšího rantu Zeda Shawa jsem se moc daleko nedostal (snad jen: na projektu Rubinius pracuje teď pět lidí na full-time a navíc se jedná o špičky Ruby komunity!), ale kvalita výběru se zdá ucházející.