<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Tag python</title>
    <link>http://blog.zabiello.com/articles/tag/python</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Passenger bli&#380;ej - Rails, Rack i WSGI</title>
      <description>&lt;p&gt;Stworzony pierwotnie na u&#380;ytek Rails, aktualnie mod_passenger ju&#380; obs&#322;uguje nie tylko Rails ale tak&#380;e mas&#281; innych framework&#243;w u&#380;ywaj&#261;cych Rack&amp;#8217;a. W &lt;a href="http://tinyurl.com/6edmve"&gt;nowej dokumentacji&lt;/a&gt; wymienione s&#261; frameworki: &lt;a href="http://code.whytheluckystiff.net/camping"&gt;Camping&lt;/a&gt;, &lt;a href="http://halcyon.rubyforge.org/"&gt;Halcyon&lt;/a&gt;, &lt;a href="http://www.mackframework.com/"&gt;Mack&lt;/a&gt;, &lt;a href="http://merbivore.org/"&gt;Merb&lt;/a&gt;, &lt;a href="http://ramaze.net/"&gt;Ramaze&lt;/a&gt; i &lt;a href="http://sinatrarb.com/Home"&gt;Sinatra&lt;/a&gt;. W dokumentacji nie wymieniono jeszcze &amp;#8220;drugiej listy&amp;#8221;, zawieraj&#261;cej frameworki korzystaj&#261;ce z &lt;a href="http://www.wsgi.org/wsgi"&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt; i Pythona (np. &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, &lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt; itp.). Chc&#261;c sprawdzi&#263; plotki wok&#243;&#322; tej sprawy, sprawdzi&#322;em, czy faktycznie mod_passenger pracuje nie tylko z Ruby, ale tak&#380;e z Pythonem. Sprawdzi&#322;em tak&#380;e jak to jest faktycznie z ob&#322;ug&#261; Rails i framework&#243;w na Rack&amp;#8217;u (tu sprawdzi&#322;em tylko Merba). Sprawdzi&#322;em te&#380; JRuby dla Rails i Merba.&lt;/p&gt;


	&lt;p&gt;Wszystkie testy by&#322;y wykonywane na laptopie MacBook Pro Core 2 Duo, 2.16GHZ, 4GB &lt;span class="caps"&gt;RAM&lt;/span&gt; (OSX 10.5.3 dla tego modelu widzi tylko 3GB) i dyskiem 200GB kr&#281;c&#261;cym si&#281; z szybko&#347;ci&#261; 7200 rpm. Ruby 1.8.6, Python 2.5.2, Apache 2.2.8 (mpm-prefork) by&#322;y instalowane z MacPort&#243;w. Passenger, mimo &#380;e instalowany &lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;ze &#378;r&#243;de&#322;&lt;/a&gt; w Apache&amp;#8217;u by&#322; wy&#347;wietlany jako &amp;#8220;Phusion_Passenger/1.1.0&amp;#8221; (by&#263; mo&#380;e wi&#281;c to nie jest jeszcze ta nowa wersja 2.0 o kt&#243;rej pisa&#322;em &lt;a href="http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise"&gt;wcze&#347;niej&lt;/a&gt;) Nie sprawdza&#322;em Linuksa, by&#263; mo&#380;e wyniki i wnioski b&#281;d&#261; wtedy inne.&lt;/p&gt;


	&lt;p&gt;Dla tych co chcieliby sami popr&#243;bowa&#263; podaj&#281; wpierw konfiguracj&#281; serwer&#243;w wirtualnych dla Apache&amp;#8217;a potrafi&#261;c&#261; unie&#347;&#263; razem: &lt;span class="caps"&gt;PHP&lt;/span&gt; (2.5.6), Rails (2.1), Merb (0.9.4 edge), i Django (edge).&lt;/p&gt;


	&lt;h2&gt;Konfiguracja Apache&amp;#8217;a  2.2.8&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_apache "&gt;
# Ruby (Rails):
&amp;lt;VirtualHost *:80&amp;gt;     
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/rails_app/public&amp;quot;  
  ServerName rails_app
&amp;lt;/VirtualHost&amp;gt;

# Ruby (Merb):        
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/merb_app/public&amp;quot;    
  ServerName merb_app       
&amp;lt;/VirtualHost&amp;gt;

# Python (WSGI):
&amp;lt;VirtualHost *:80&amp;gt;          
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/wsgi_app/public&amp;quot;    
  ServerName wsgi_app
&amp;lt;/VirtualHost&amp;gt;      

# Django (mod_python)
&amp;lt;VirtualHost *:80&amp;gt;         
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/djangus/public&amp;quot;    
  ServerName django_modpython 
  &amp;lt;Location &amp;quot;/&amp;quot;&amp;gt;
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE djangus.settings
    PythonDebug On        
    PythonPath &amp;quot;['/opt/local/apache2/vhosts'] + sys.path&amp;quot;    
  &amp;lt;/Location&amp;gt;       
&amp;lt;/VirtualHost&amp;gt;   

# PHP:
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/php_app/public&amp;quot;        
  ServerName php_app   
&amp;lt;/VirtualHost&amp;gt;    &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Wszystkie aplikacje korzystaj&#261;ce z mod_passengera musz&#261; posiada&#263; folder &lt;code&gt;public&lt;/code&gt; i &lt;code&gt;tmp&lt;/code&gt;. Gdy do katalogu &lt;code&gt;tmp&lt;/code&gt; dorzucimy jakikolwiek (mo&#380;e by&#263; pusty) plik o nazwie &lt;code&gt;restart.txt&lt;/code&gt;, to przy nast&#281;pnym prze&#322;adowaniu przegl&#261;darki nast&#261;pi restart aplikacji.&lt;/p&gt;


	&lt;p&gt;We wszystkich przypadkach u&#380;y&#322;em dosy&#263; banalnego kodu polegaj&#261;cego na wy&#347;wietleniu &amp;#8220;Hello World!&amp;#8221;. Z wynik&#243;w programu &lt;code&gt;ab&lt;/code&gt; wyci&#261;&#322;em nieistotne informacje.&lt;/p&gt;


	&lt;h2&gt;Rails (2.1)&lt;/h2&gt;


	&lt;h3&gt;Rails 2.1 + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Rails obs&#322;ugiwane s&#261; w Passengerze praktycznie bezobs&#322;ugowo. Wystarczy wkopiowa&#263; pliki na serwer i to wszystko.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ab -n 1000 -c 1 http://rails/ 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Total transferred:      582000 bytes
HTML transferred:       12000 bytes
Requests per second:    430.20 [#/sec] (mean)
Transfer rate:          244.35 [Kbytes/sec] received

ab -n 1000 -c 4 http://rails/
...
Concurrency Level:      4
Failed requests:        239
   (Connect: 0, Length: 239, Exceptions: 0)
Write errors:           0
Total transferred:      488073 bytes
HTML transferred:       9132 bytes
Requests per second:    520.75 [#/sec] (mean)
Transfer rate:          247.88 [Kbytes/sec] received&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; nie jest najgorsza, ale niepokoj&#261;ca jest du&#380;a lista b&#322;&#281;dnych request&#243;w w wypadku zapyta&#324; r&#243;wnoleg&#322;ych. Jak si&#281; dalej okazuje, ten problem dotyczy tak&#380;e ob&#322;ugi Rack jak i &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Albo to jaka&#347; specyfika &lt;span class="caps"&gt;OSX&lt;/span&gt;, albo wcale nie jest tak dobrze ze stabilno&#347;ci&#261; mod_passengera dla r&#243;wnoleg&#322;ych zapyta&#324;. Trzeba by by&#322;o te&#380; zbada&#263;, czy ten efekt wyst&#281;puje tak&#380;e dla Linuksa. Zdziwi&#322;bym si&#281; gdyby tam by&#322;o podobnie skoro Dreamhost ju&#380; oferuje hosting z mod_rails&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Dla por&#243;wnania Rails u&#380;ywaj&#261;cy Mongrela, Thin oraz Ebb. Mo&#380;na by pokusi&#263; aby odpali&#263; Ebb i Thina na uniksowych socketach (Ebb te&#380; to ju&#380; potrafi!), ale wtedy musia&#322;bym zestawia&#263; klaster i uruchamia&#263; to przez proxy. Jak kto&#347; chce to niech si&#281; sam pobawi. Dla prostoty u&#380;y&#322;em port&#243;w &lt;span class="caps"&gt;TCP&lt;/span&gt;. Sprawdzi&#322;em te&#380; JRuby.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ebb_rails -e production start

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    488.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
..
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    533.22 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; wi&#281;ksza od mod_passengera i co wa&#380;niejsze, zero jakichkolwiek b&#322;&#281;d&#243;w przy pracy r&#243;wnoleg&#322;ej.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;thin start -e production              

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    485.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    506.21 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Szybko&#347;&#263; troch&#281; mniejsza od Ebb, ale stabilno&#347;&#263; b. dobra.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/server -e production

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    373.74 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    360.46 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Stabilno&#347;&#263; bez zarzutu, wydajno&#347;&#263; jednak mniejsza od serwer&#243;w pracuj&#261;cych asynchronicznie.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + JRuby 1.1.2&lt;/h3&gt;


	&lt;p&gt;W wypadku JRuby trzeba go troch&#281; &amp;#8220;rozgrza&#263;&amp;#8221;. Pe&#322;na wydajno&#347;&#263; Javy pojawia si&#281; po jakim&#347; czasie pracy. Wynika to ze specyfiki i mo&#380;liwo&#347;&#263;i &lt;span class="caps"&gt;JVM&lt;/span&gt; kt&#243;ra dokonuje dynamicznych optymalizacji kodu w trakcie jego dzia&#322;ania (z tego powodu Java potrafi przewy&#380;szy&#263; wydajno&#347;ci&#261; C++). &amp;#8220;Dla rozgrzewki&amp;#8221; przepu&#347;ci&#322;em Rails przez 30 tys. request&#243;w co spowodowa&#322;o &#380;e pocz&#261;tkowych 137 req/s zrobi&#322;o si&#281; 257 req/s.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;jruby script/server -e production    

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    200.48 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    257.05 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;JRuby jest stabilny ale z wydajno&#347;ci&#261; dla Rails jeszcze jest troch&#281; do poprawienia. Dorzucenie opcji optymalizacyjnych, czyli odpalenie Rails przez&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  
jruby -J-server -J-Djruby.compile.frameless=true script/server -e production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;troch&#281; poprawi&#322;o wynik: 273 req/s, ale generalnie nie jest to wielka r&#243;&#380;nica. JRuby 1.1.x ju&#380; ma domy&#347;lnie pow&#322;&#261;czane optymalizacje.&lt;/p&gt;


	&lt;h3&gt;Rails &amp;#8211; wnioski&lt;/h3&gt;


	&lt;p&gt;mod_passenger dla Rails faktycznie jest wydajny, cho&#263; trzeba jeszcze by zbada&#263; dlaczego zwraca tyle b&#322;&#281;dnych request&#243;w dla r&#243;wnoleg&#322;ych zapyta&#324; i czy ten problem wyst&#281;puje te&#380; na Linuksie. Dlatego na razie najwydajniejszym i najstabilniejszym rozwi&#261;zaniem dla Rails wci&#261;&#380; pozostaje kombinacja nginx + proxy do ebb lub thin. mod_passenger kusi g&#322;&#243;wnie prostot&#261; konfiguracji (w&#322;a&#347;ciwie brakiem konfiguracji). No i chyba ja to testowa&#322;em dla mod_passengera w wersji 1.1, a nie 2.0 (przynajmniej taka si&#281; wy&#347;wietla w Apache).&lt;/p&gt;


	&lt;h2&gt;Merb 0.9.4 edge&lt;/h2&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Aby u&#380;y&#263; frameworka Rack z Passengerem trzeba w katalogu projektu tworzy&#263; plik &lt;code&gt;config.ru&lt;/code&gt; zawieraj&#261;cy konfiguracj&#281; Rack&amp;#8217;a. W wypadku Merba b&#281;dzie to&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merb-core&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;setup&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;   &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
                   &lt;span class="symbol"&gt;:environment&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RACK_ENV&lt;/span&gt;&lt;span class="punct"&gt;'])&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environment&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:environment&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;BootLoader&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;

&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Application&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    762.62 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        247
   (Connect: 0, Length: 247, Exceptions: 0)
Write errors:           0
Requests per second:    985.15 [#/sec] (mean) &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb jest wci&#261;&#380; du&#380;o szybszy od Rails. Podobnie jak dla Rails, wiele r&#243;wnoleg&#322;ych zapyta&#324; nie zosta&#322;o poprawnie wykonanych. Na produkcyjne u&#380;ycie Passengera dla Merba jest jeszcze troch&#281; za wcze&#347;nie.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a ebb  
...                              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1463.69 [#/sec] (mean)

Concurrency Level:      10
Failed requests:        0
Write errors:           0
Requests per second:    1560.60 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Merb na Ebb deklasuje wydajno&#347;ci&#261; wszystkie inne rozwi&#261;zania. Tylko czysty &lt;span class="caps"&gt;PHP&lt;/span&gt; jest w stanie mu dor&#243;wna&#263;, ale por&#243;wnywanie &lt;span class="caps"&gt;PHP&lt;/span&gt; z ca&#322;ym, z&#322;o&#380;onym frameworkiem Rubiego jest troch&#281; bez sensu. Z tego co m&#243;wi&#322; ostatnio (na kanale &lt;span class="caps"&gt;IRC&lt;/span&gt;) Ezra Zygmuntowicz, podpi&#281;cie Ebb na czystym Rack&amp;#8217;u, daje nawet &lt;strong&gt;7 tys req/s&lt;/strong&gt; i deklasuje (rzekomo) szybkiego &lt;span class="caps"&gt;PHP&lt;/span&gt;. Gadanie o wy&#380;szej wydajno&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; jest po prostu g&#322;upie. Mo&#380;na si&#281; za&#322;o&#380;y&#263;, &#380;e jakiekolwiek por&#243;wnanie frameworka naprzeciw frameworka, tj. Merba z Symfony czy Cake &lt;span class="caps"&gt;PHP&lt;/span&gt;, obna&#380;y bezlito&#347;nie s&#322;abo&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; &lt;a href="http://blog.zabiello.com/articles/2006/07/14/django-i-rails-bij%C4%85-php"&gt;tak, jak to zrobi&#322; Django&lt;/a&gt; w jednym ze starszych test&#243;w.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a thin 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    1147.78 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1234.82 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Wydajno&#347;&#263; r&#243;wnie dobra, cho&#263; troch&#281; s&#322;absza od Ebb. Sporo wi&#281;cej od Rails i zero problem&#243;w ze stabilno&#347;ci&#261;.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a mongrel
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    868.10 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    837.01 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;   

	&lt;p&gt;Mongrel jest wolniejszy od serwer&#243;w asynchronicznych ale i tak wyra&#378;nie szybszy od Rails.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + JRuby 1.1.2&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt; 
jruby -S merb -e production 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    449.52 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    505.52 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb na &amp;#8220;rozgrzanym&amp;#8221; (30 tys. req) JRuby osi&#261;ga wydajno&#347;&#263; tak&#261; jak najszybsze rozwi&#261;zania dla Rails z u&#380;yciem asynchronicznego Ebb! To znaczy, &#380;e u&#380;ycie produkcyjne Merba w systemach Javy ma jak najbardziej sens.&lt;/p&gt;


	&lt;h2&gt;Passenger &amp;#38; &lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/h2&gt;


	&lt;p&gt;Pora na przyjrzenie si&#281; temu jak mod_passenger daje sobie rad&#281; z Pythonem. W katalogu ze &#378;r&#243;d&#322;ami Passengera le&#380;y gotowa, prosta aplikacja &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Dzieki dobrej dokumentacji Django, uda&#322;o mi si&#281; uruchomi&#263; ten framework pod Passengerem. Gorzej by&#322;o z Pylons. Nie uda&#322;o mi si&#281; stworzy&#263; poprawnego pliku passenger_wsgi.py, niezb&#281;dnego do tego aby Passenger uruchomi&#322; aplikacj&#281; &lt;span class="caps"&gt;WSGI&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Django edge&lt;/h3&gt;


	&lt;p&gt;Django, mimo swych zalet, stosuje bardzo g&#322;upi&#261; polityk&#281; nie wypuszczania kolejnych wersji kodu. Dost&#281;pna na stronie wersa 0.96 jest stara i generalnie zaleca si&#281; aby u&#380;ywa&#263; nowsz&#261; wersj&#281;, kt&#243;ra istnieje tylko w repozytorium Subversion. Oparcie kodu produkcyjnego o wersj&#281; edge jest troch&#281; ryzykowne i szybko sprowadza si&#281; do z&#322;ej praktyki ci&#261;g&#322;ego  &#322;atania kodu.&lt;/p&gt;


	&lt;p&gt;W wypadku Django plik &lt;code&gt;passenger_wsgi.py&lt;/code&gt; zawiera kod:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sys&lt;/span&gt;
&lt;span class="ident"&gt;sys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/bezwl/sciezka/do/nazwaprojektu&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; 
&lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;DJANGO_SETTINGS_MODULE&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;nazwaprojektu.settings&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;
&lt;span class="ident"&gt;application&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;WSGIHandler&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  ab -n 10000 -c 10            
  ...   
  apr_poll: The timeout specified has expired (70007)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test pad&#322; po 9tys requestach. Dalej nie mo&#380;na by&#322;o uruchomi&#263; Django. Dopiero restart calego Apache&amp;#8217;a pom&#243;g&#322;. Dla ni&#380;szej ilo&#347;ci r&#243;wnoleg&#322;ych zapyta&#324; (ab -n 1000 -c 4) Django nie pad&#322;o, ale by&#322;o du&#380;o b&#322;&#281;dnych request&#243;w. Okaza&#322;o si&#281;, &#380;e problem wynika&#322; z r&#243;wnoczesnej obecno&#347;ci modu&#322;u mod_python i mod_passenger. Nie mo&#380;na ich razem w&#322;&#261;cza&#263;.&lt;/p&gt;


	&lt;p&gt;Usuni&#281;cie mod_passengera i zostawienie samego mod_pythona pomog&#322;o. (Albo jest jaki&#347; konflikt mi&#281;dzy nimi, albo (co bardziej jest prawdopodobne) trzeba poczeka&#263; na opcj&#281; wy&#322;&#261;czaj&#261;c&#261; passengera dla serwera wirtualnego u&#380;ywaj&#261;cego mod_pythona. Dla Rails i Rack s&#261; takie opcje (RailsAutoDetect, RackAutoDetect), dla &lt;span class="caps"&gt;WSGI&lt;/span&gt; nie mog&#322;em nic takiego znale&#378;&#263; w kodzie &#378;r&#243;d&#322;owym. Modu&#322;u mod_wsgi nie sprawdza&#322;em, bo nie by&#322;o go dost&#281;pnego w portach &lt;span class="caps"&gt;OSX&lt;/span&gt;.)&lt;/p&gt;


	&lt;p&gt;Po zablokowaniu mod_passenger&amp;#8217;a tym razem mod_python nie zwraca&#322; &#380;adnego b&#322;&#281;dnego requestu.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    934.87 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1240.26 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Nie jest &#378;le. Django jest tu wyra&#378;nie szybsze od Rails (co nikogo nie dziwi), ale jest wolniejsze od Merba, co dla mi&#322;o&#347;nik&#243;w Pythona mo&#380;e by&#263; przykr&#261; niespodziank&#261;. Wi&#281;kszo&#347;&#263; krytyki Rubiego oparta jest na krytyce (s&#322;abszej) wydajno&#347;ci Rails&#243;w. Okazuje si&#281;, &#380;e winny nie jest Ruby, ale s&#322;abo zoptymalizowany Rails. Merb jest dowodem na to, &#380;e mo&#380;na napisa&#263; w Rubim framework, kt&#243;ry nie tylko b&#281;dzie partnerem dla rozwi&#261;zan Pythona, ale nawet potrafi je przewy&#380;sza&#263; wydajno&#347;ciowo.&lt;/p&gt;


	&lt;p&gt;Zobaczmy jak wypadnie &lt;strong&gt;mod_passenger&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    904.60 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        240
   (Connect: 0, Length: 240, Exceptions: 0)
Write errors:           0
Requests per second:    497.51 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W pracy jednoprocesowej nie mo&#380;na mie&#263; zastrze&#380;e&#324;. Szybko&#347;&#263; jest niez&#322;a. Niestety praca r&#243;wnoleg&#322;a to pora&#380;ka. Du&#380;o request&#243;w nie zosta&#322;o obs&#322;u&#380;onych. Gorzej, za drugim razem (tylko dla 4 rownoleg&#322;ych zapyta&#324;) Django kompletnie si&#281; za&#322;ama&#322;o i zwr&#243;ci&#322;o wyj&#261;tek &amp;#8220;apr_poll: The timeout specified has expired (70007)&amp;#8221;. Nie mo&#380;na by&#322;o go d&#322;u&#380;ej u&#380;ywa&#263;. Wymagany by&#322; restart Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Aby sprawdzi&#263; czy to tylko problem Django czy og&#243;lnie implementacji &lt;span class="caps"&gt;WSGI&lt;/span&gt; dla mod_passengera, uruchomi&#322;em test na prostej aplikacji &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Niestety sytuacja jest ta sama.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Wniosek&lt;/strong&gt;: mod_passenger dla Pythona wymaga dopracowania pracy r&#243;wnoleg&#322;ej. Jeszcze za wcze&#347;nie aby go u&#380;ywa&#263; z Pythonem. Ale z drugiej strony uruchomi&#322;em mod_passengera z &lt;span class="caps"&gt;WSGI&lt;/span&gt;  troch&#281; przedwcze&#347;nie. Nie ma przecie&#380; w manualu ani jednego zdania o tym, &#380;e Passenger dzia&#322;a z &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Opar&#322;em si&#281; tylko na pog&#322;oskach i wygrzeba&#322;em t&#261; opcj&#281; ze &#378;r&#243;de&#322;. Wi&#281;c jeszcze wszystko mo&#380;e si&#281; tu zmieni&#263;. To samo dotyczy Rack&amp;#8217;a. Tw&#243;rcy musz&#261; przyjrze&#263; si&#281; problemom zwi&#261;zanym z obs&#322;ug&#261; r&#243;wnoleg&#322;ych zapyta&#324;.&lt;/p&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;Jednak dobrze si&#281; domy&#347;la&#322;em, Apache nie oszukiwa&#322;. W tek&#347;cie testowa&#322;em starszego Passengera 1.1. Tak&#380;e nie by&#322; to Ruby Enterprise. &lt;span class="caps"&gt;NOWY&lt;/span&gt; Passenger 2.0RC1 oraz Ruby Enterprise zosta&#322; dopiero niedawno &lt;a href="http://blog.phusion.nl/2008/06/09/phusion-passenger-20-rc-1-and-ruby-enterprise-edition-released/"&gt;opublikowany&lt;/a&gt;. Co ciekawe, dodano obs&#322;ug&#281; Apache &lt;span class="caps"&gt;MPM&lt;/span&gt; &lt;strong&gt;Worker&lt;/strong&gt; a nie &lt;span class="caps"&gt;MPM&lt;/span&gt; Prefork, co dodatkowo zmniejsza zu&#380;ycie pami&#281;ci. Niestety Passenger 2.0RC1 jest na razie dost&#281;pny tylko w wersji na Linuksa.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Jun 2008 15:24:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:1dc84c82-1634-41dd-9aa1-9c744a876dff</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/07/passenger-rack-wsgi</link>
      <category>rails</category>
      <category>ruby</category>
      <category>python</category>
      <category>django</category>
      <category>merb</category>
      <category>apache</category>
      <category>benchmark</category>
      <category>jruby</category>
    </item>
    <item>
      <title>Sprz&#261;tanie po PHP czyli Passenger 2.0 i Ruby Enterprise 1.0</title>
      <description>&lt;p&gt;Sta&#322;o si&#281;! &lt;a href="http://www.phusion.nl/"&gt;Tw&#243;rcy&lt;/a&gt; &#347;wietnego modu&#322;u Apache&amp;#8217;a &amp;#8211; &lt;a href="http://www.modrails.com/"&gt;mod_rails&lt;/a&gt; &amp;#8211; zmieniaj&#261; jego nazw&#281; na &lt;strong&gt;mod_passenger&lt;/strong&gt;, bo mod_rails nie jest ju&#380; wi&#281;cej modu&#322;em tylko dla &lt;a href="http://rubyonrails.pl"&gt;Rails&lt;/a&gt;. W nowej wersji 2.0 (ktora ma wyj&#347;&#263;&#160;&lt;a href="http://groups.google.com/group/phusion-passenger/browse_thread/thread/a2b63650c1b9394"&gt;na dniach&lt;/a&gt;) dodano pe&#322;ne wsparcie dla &lt;a href="http://blog.zabiello.com/articles/2008/03/04/frameworki-rubiego-rack-wsgi"&gt;Rack&lt;/a&gt; i tym samym mod_passenger 2.0 obs&#322;uguje wszystkie pozosta&#322;e frameworki u&#380;ywaj&#261;ce Rack&amp;#8217;a (ze &#347;wietnym &lt;a href="http://merbivore.com"&gt;Merbem&lt;/a&gt; w&#322;&#261;cznie).&lt;/p&gt;


	&lt;p&gt;Drugim, ciekawym projektem firmy &lt;a href="http://www.phusion.nl/"&gt;Phusion&lt;/a&gt; jest &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt; (wersja 1.0 ma by&#263; dost&#281;pna lada dzie&#324; razem z Passenger 2.0). Jest to podrasowana wersja interpretera Rubiego (MRI) powoduj&#261;ca nie tylko przy&#347;pieszenie ale tak&#380;e znaczne zmniejszenie zu&#380;ycia pami&#281;ci &lt;span class="caps"&gt;RAM&lt;/span&gt; (dodano technik&#281; copy-on-write do garbage collectora interpretera &lt;span class="caps"&gt;MRI&lt;/span&gt;, dok&#322;adniej opisano to na &lt;a href="https://dl.getdropbox.com/u/26205/railsconf.pdf"&gt;slajdach&lt;/a&gt;). Wg tego co twierdz&#261; ludzie z Phusion, uzyskano zmniejszenie o 33% zu&#380;ycia pami&#281;ci przez Rails. To bardzo dobra wiadomo&#347;&#263;, bo pami&#281;&#263; mimo, &#380;e jest generalnie tania, nie jest tania w ofertach hostingowych &lt;span class="caps"&gt;VPS&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Passenger wprowadza now&#261; jako&#347;&#263; dla framework&#243;w Rubiego. Coraz wi&#281;cej firm hostingowych to docenia i przechodzi na Passenger&amp;#8217;a (z tych bardziej znanych, &lt;a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/"&gt;Dreamhost ju&#380; tego u&#380;ywa&lt;/a&gt;). Sam modu&#322;&#160;mod_passenger jest nie tylko trywialny w u&#380;yciu, jest te&#380; bardzo szybki i stabilny. Chyba nadchodz&#261; ci&#281;&#380;kie chwile dla tych, co trzymali si&#281; &lt;span class="caps"&gt;PHP&lt;/span&gt; g&#322;&#243;wnie z powodu jego taniego hostingu i prostoty uruchomiania serwerze. Rails i Merb mog&#261; wkr&#243;tce troch&#281; pozamiata&#263; po &lt;span class="caps"&gt;PHP&lt;/span&gt;. :)&lt;/p&gt;


	&lt;p&gt;Szybko&#347;&#263; mod_passenger&amp;#8217;a robi wra&#380;enie. Bije wydajno&#347;ci&#261; kombinacj&#281; &lt;a href="http://nginx.net/"&gt;Nginx&lt;/a&gt; + asynchroniczny &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt; u&#380;ywaj&#261;cy szybkich, uniksowych socket&#243;w. Jest te&#380; szybszy od komercyjnego &lt;a href="http://litespeedtech.com/"&gt;Litespeed&amp;#8217;a&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_thin.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_litespeed.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;Co ciekawe, mod_passenger obs&#322;uguje interfejs &lt;strong&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt; do Pythona&lt;/strong&gt;! Jeden modu&#322; pozwoli wi&#281;c na odpalanie Rails, Merb&amp;#8217;a i Django r&#243;wnocze&#347;nie. Ma&#322;o tego, je&#347;li mod_passenger dla Pythona b&#281;dzie dzia&#322;a&#322; tak sprawnie jak dla Rails, to b&#281;dziemy mie&#263; trywialne prze&#322;adowywanie aplikacji Django bez konieczno&#347;ci restartu ca&#322;ego Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Vide:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.railsjedi.com/posts/52-The-Holy-Grail-for-Rails-Deployment"&gt;The Holy Grail for Rails Deployment&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.rubyinside.com/28_mod_rails_and_passenger_resources-899.html"&gt;28 mod_rails / Passenger Resources To Help You Deploy Rails Applications Faster&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;Passenger 2.0 na GitHub.com&lt;/a&gt; dla tych, co chc&#261; ju&#380; teraz zainstalowa&#263; mod_passenger 2.0 (ja ju&#380; to zainstalowa&#322;em)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;&lt;em&gt;2008-06-25&lt;/em&gt;&lt;/p&gt;


&lt;object width="400" height="225"&gt;    &lt;param name="allowfullscreen" value="true" /&gt;    &lt;param name="allowscriptaccess" value="always" /&gt;    &lt;param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;    &lt;embed src="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://www.vimeo.com/1198020?pg=embed&amp;#38;sec=1198020"&gt;Phusion Passenger 2.0 and Ruby Enterprise Edition&lt;/a&gt; from &lt;a href="http://www.vimeo.com/user519957?pg=embed&amp;#38;sec=1198020"&gt;Carl Youngblood&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;#38;sec=1198020"&gt;Vimeo&lt;/a&gt;

	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://blog.dmilith.pl/2008/06/25/ruby-enterprise-edition-32bit-na-debianie-etch-64bit"&gt;Ruby Enterprise Edition 32bit na debianie etch 64bit?&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Wed, 04 Jun 2008 01:40:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:77d6b3df-2b86-4365-b5de-d4fd9b153ecc</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise</link>
      <category>mod_rails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>merb</category>
      <category>rack</category>
      <category>apache</category>
      <category>php</category>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title> Google App Engine</title>
      <description>&lt;p&gt;Od niedawna Google oferuje dosy&#263; atrakcyjn&#261; mo&#380;liwo&#347;&#263; pisania aplikacji webowych wykorzystuj&#261;cych pot&#281;g&#281; ich infrastruktury &amp;#8211; &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;. Us&#322;uga jest darmowa i jeszcze testowa. Mo&#380;na stworzy&#263; do 3 aplikacji z kt&#243;rych ka&#380;da mo&#380;e u&#380;ywa&#263; do 500MB danych trzymanych w BigTable i Google obiecuje &#380;e bez problemu b&#281;dzie mo&#380;na uzyska&#263; do 5 mln ods&#322;on miesi&#281;cznie i niez&#322;y traffic 10 TB/m-c.&lt;/p&gt;


	&lt;p&gt;W tej chwili jedynym j&#281;zykiem dost&#281;pnym jest Python ale maj&#261; przyby&#263; kolejne. Wykorzystywany jest &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Dost&#281;pny jest te&#380; &lt;a href="http://code.google.com/appengine/articles/django.html"&gt;okrojony framework Django&lt;/a&gt; (nie mo&#380;na u&#380;ywa&#263; djangowego &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;a ani wszystkich mo&#380;liwo&#347;ci jakie daj&#261; djangowe szablony).&lt;/p&gt;


	&lt;p&gt;To co si&#281; bardzo zmienia, to podej&#347;cie do bazy danych. Baza kolumnowa &lt;a href="http://en.wikipedia.org/wiki/Bigtable"&gt;BigTable&lt;/a&gt; &lt;strong&gt;nie jest baz&#261; relacyjn&#261;&lt;/strong&gt; (nie istnieje tam poj&#281;cie join&#243;w). Trzeba wi&#281;c troch&#281;&#160;inaczej przemy&#347;le&#263; spos&#243;b tworzenia swoich danych. Pewnym problemem mo&#380;e by&#263; nie tylko uzale&#380;nienie od infrastruktury Google ale te&#380; trudno&#347;&#263; z p&#243;&#378;niejszym przeniesienia tak sk&#322;adowanych danych na inn&#261; platform&#281; (cho&#263; istnieje z drugiej strony open-source&amp;#8217;owy odpowiednik BigTable &amp;#8211; &lt;a href="http://hadoop.apache.org/hbase/"&gt;HBase&lt;/a&gt;). W zamian jednak u&#380;ycie platformy Google daje bardzo wysok&#261; wydajno&#347;&#263;&#160;i odporno&#347;&#263; na b&#322;&#281;dy (jak padnie jeden serwer to jego prac&#281; przejmuje automatycznie inny). Troch&#281; nie jest dla mnie jeszcze jasne jak sk&#322;adowa&#263; i usuwa&#263; dane z plikami statycznymi (obrazki, style kaskadowe, flash itp) skoro Google nie daje dost&#281;pu do systemu plik&#243;w. Zablokowane s&#261;&#160;te&#380; sockety, w&#261;tki, u&#380;ywanie modu&#322;&#243;w napisanych w C, mo&#380;liwo&#347;&#263;&#160;odpalania podproces&#243;w, mo&#380;liwo&#347;ci u&#380;ywania innych baz ni&#380; BigTable.&lt;/p&gt;</description>
      <pubDate>Sun, 13 Apr 2008 21:12:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:b7f3ea40-77de-4b1d-b122-3799c876ab80</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/04/13/google-app-engine</link>
      <category>google</category>
      <category>python</category>
      <category>django</category>
    </item>
    <item>
      <title>Git, Bazaar, Mercurial - Subversion pod obstrza&#322;em</title>
      <description>&lt;p&gt;&#346;wiat technologii IT zmienia si&#281; coraz szybciej. Nie min&#281;&#322;o wiele lat od dosy&#263; masowego przechodzenia &lt;a href="http://pl.wikipedia.org/wiki/CVS"&gt;&lt;span class="caps"&gt;CVS&lt;/span&gt;&lt;/a&gt; do &lt;a href="http://pl.wikipedia.org/wiki/Subversion"&gt;Subversion&lt;/a&gt; a ju&#380; zanosi si&#281; na kolejn&#261; rewolucj&#281;. Tak jak wcze&#347;niej atakowany by&#322; &lt;span class="caps"&gt;CVS&lt;/span&gt;, teraz atakowany jest Subversion. Atakowany jest przez &lt;strong&gt;rozproszone&lt;/strong&gt; systemy kontroli wersji.&lt;/p&gt;


	&lt;h2&gt;Czym jest system rozproszony (distributed)?&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; jest przyk&#322;adem &lt;strong&gt;centralnego&lt;/strong&gt; systemu wersjonowania. Zawsze mamy do czynienia z centralnym repozytorium kodu. Jakakolwiek pr&#243;ba &#347;ci&#261;gni&#281;cia nowszych wersji plik&#243;w wymaga posiadania po&#322;&#261;czenia z serwerem zawieraj&#261;cym interesuj&#261;ce nas repozytorum. Jakakolwiek aktualizacja zmian w repozytorum wymaga znowu po&#322;&#261;czenia si&#281; z centralnym repozytorium. Systemy rozproszone dzia&#322;aj&#261; zupe&#322;nie inaczej.&lt;/p&gt;


	&lt;p&gt;Po pierwsze, nie posiadaj&#261; &#380;adnego centralnego repozytorium. &#346;ci&#261;gni&#281;cie projektu polega na &lt;strong&gt;sklonowaniu&lt;/strong&gt; danego repozytorium na dysku lokalnym. Wszelkie lokalnie dokonywane zmiany nale&#380;y dodawa&#263; do swojego, lokalnego repozytorium. Nie jest potrzebne posiadanie aktywnego po&#322;&#261;czenia z internetem. Co w wypadku, kiedy pierwotne repozytorium si&#281; zmieni&#322;o i chcemy zaktualizowa&#263; swoje? Nic trudnego.&lt;/p&gt;


	&lt;p&gt;Drug&#261;, pot&#281;&#380;n&#261; r&#243;&#380;nic&#261; w stosunku do Subversion jest &#322;atwo&#347;&#263; z jak&#261; w systemie rozproszonym scala si&#281; dowolne odga&#322;&#281;zienia (branches) kodu. Subversion jest bardzo tu kiepskie. System rozproszony pozwala zatem posiada&#263; najnowsz&#261; wersj&#281; kodu oryginalnego w&#322;&#261;cznie z naszymi poprawkami. Je&#347;li chcemy wys&#322;a&#263; nasze zmiany do autora projektu, mo&#380;na to tak&#380;e uczyni&#263;. Je&#347;li autor uzna, &#380;e nasze zmiany s&#261; warto&#347;ciowe i godne tego aby je do&#322;&#261;czy&#263;, stosuje podobny mechanizm scalania odga&#322;&#281;zie&#324;.&lt;/p&gt;


	&lt;p&gt;Trzeci&#261; istotn&#261; r&#243;&#380;nic&#261; jest brak za&#347;miecania projektu dziesi&#261;tkami folder&#243;w o nazwie &lt;code&gt;.svn&lt;/code&gt; (W Subversion ka&#380;dy wewn&#281;trzny folder, aby podlega&#322; wersjonowaniu, musi posiada&#263; w &#347;rodku taki dodatkowy folder). Systemy rozproszone zwykle tworz&#261; jeden, jedyny folder w g&#322;&#243;wnym katalogu i nie wymagaj&#261; aby wszystkie wewn&#281;trzne foldery posiada&#322;y go r&#243;wnie&#380;.&lt;/p&gt;


	&lt;p&gt;W praktyce, porz&#261;dnie prowadzone projekty u&#380;ywaj&#261;ce Subversion stosuj&#261; jakie&#347; formalne regu&#322;y dodawania zmian w kodzie. Np. zabrania si&#281; &amp;#8220;commitowania&amp;#8221; kodu, kt&#243;ry nie przeszed&#322; pozytywnie wszystkich test&#243;w jednostkowych. Problem w tym, &#380;e od chwili zgrania sobie &#378;r&#243;de&#322; na dysk, tracimy wszelk&#261; mo&#380;liwo&#347;&#263; wersjonowania naszych ma&#322;ych, lokalnych zmian (kt&#243;re niekoniecznie musz&#261; by&#263; pozbawione b&#322;&#281;d&#243;w). Czasami chcemy si&#281; cofn&#261;&#263; do jakiej&#347; wcze&#347;niejszej zmiany i nie mo&#380;emy. Subversion wersjonuje tylko kod w centralnym repozytorium. System rozproszony pozwala za&#347; na takie &#347;ledzenie lokalnych zmian i to nawet w spos&#243;b niezale&#380;ny od &#347;ci&#261;gni&#281;tego kodu z repozytorium Subversion. Niezale&#380;ny, bo mo&#380;na troch&#281; &amp;#8220;oszukiwa&#263;&amp;#8221; system u&#380;ywany w pracy. :) Po &#347;ci&#261;gni&#281;ciu kodu z &lt;span class="caps"&gt;SVN&lt;/span&gt;, mo&#380;na doda&#263; sobie lokalnie system rozproszony i kontrolowa&#263; swoj&#261; histori&#281; lokalnych zmian w spos&#243;b nieinwazyjny dla Subversion.&lt;/p&gt;


	&lt;h2&gt;Git, Mercurial i Bazaar&lt;/h2&gt;


	&lt;p&gt;Aktualnie, najbardziej licz&#261;ce si&#281; systemy rozproszone to &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt;, &lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; i &lt;a href="http://bazaar-vcs.org/"&gt;Bazaar&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Git&lt;/h3&gt;


	&lt;p&gt;Pierwotnie stworzony przez Linusa Torvaldsa do zarz&#261;dzania kodem j&#261;dra systemu Linux, &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; zaczyna dosy&#263; przebojowo zdobywa&#263; popularno&#347;&#263;. Pomijaj&#261;c oczywist&#261; wy&#380;szo&#347;&#263; systemu rozproszonego nad system centralnego repozytorium, trzeba podkre&#347;li&#263;, &#380;e Git bardzo szybki. Niezr&#243;wnanie szybszy od Subversion, szybszy te&#380; od Mercurial i Bazaar. Coraz wi&#281;cej projekt&#243;w zaczyna przechodzi na Git&amp;#8217;a (np. konkurent &lt;a href="http://rubyonrails.pl"&gt;Rails&#243;w&lt;/a&gt; &amp;#8211; &lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt; trzyma &#378;r&#243;d&#322;a repozytorium Git&amp;#8217;a, zobacz te&#380; &amp;#8220;Contributing to Merb&amp;#8221; &amp;#8211; &lt;a href="http://gweezlebur.com/2008/2/1/so-you-want-to-contribute-to-merb-core-part-1"&gt;Part 1&lt;/a&gt; i &lt;a href="http://gweezlebur.com/2008/2/9/contributing-to-merb-part-2"&gt;Part 2&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;Tak&#380;e (napisany w Ruby) system do aktualizacji projekt&#243;w na serwerze (deploying) &amp;#8211; &lt;a href="http://www.capify.org/"&gt;Capistrano&lt;/a&gt; &amp;#8211; posiada &lt;a href="http://github.com/guides/deploying-with-capistrano"&gt;wsparcie dla Git&amp;#8217;a&lt;/a&gt;.  Du&#380;a rol&#281; w popularyzacji Git&amp;#8217;a czyni&#261; serwisy takie jak &lt;a href="https://github.com/"&gt;github.com&lt;/a&gt; czy &lt;a href="http://gitorious.org"&gt;gitorious.org&lt;/a&gt; gdzie mo&#380;na za&#322;o&#380;y&#263; darmowe konto dla swoich projekt&#243;w. A do &#347;ledzenia b&#322;&#281;d&#243;w i zg&#322;aszania poprawek kodu trzymanego w githubie mo&#380;na u&#380;y&#263; serwisu &lt;a href="http://lighthouseapp.com"&gt;http://lighthouseapp.com&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://railscasts.com"&gt;Railscasts.com&lt;/a&gt; znany serwis ze dziesi&#261;tkami darmowych film&#243;w edykacyjnych dla Rails&#243;w, doda&#322; niedawno &lt;a href="http://railscasts.com/episodes/96"&gt;screencast opisuj&#261;cy integracj&#281; Git&amp;#8217;a z Rails&lt;/a&gt;. Troch&#281; d&#322;u&#380;szy film na ten temat jest dost&#281;pny te&#380;&#160;w serwisie &lt;a href="https://peepcode.com/products/git"&gt;peepcode.com&lt;/a&gt;. Zobacz tak&#380;e poni&#380;sz&#261; prezentacj&#281; Linusa Torvarldsa n/t &lt;span class="caps"&gt;GIT&lt;/span&gt;&amp;#8217;a. Linus nie przebiera w s&#322;owach krytyki wobec Subversion, nazywaj&#261;c go po prostu g&#322;upim pomys&#322;em. Subversion to tylko poprawiony, stary &lt;span class="caps"&gt;CVS&lt;/span&gt;. Nie wnosi jednak nic specjalnie nowego i jego koniec jest bliski. ;)&lt;/p&gt;


&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/4XpnKHJAok8&amp;#38;hl=en"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/4XpnKHJAok8&amp;#38;hl=en" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;

	&lt;h3&gt;Mercurial&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://www.selenic.com/mercurial"&gt;Mercurial&lt;/a&gt;, to system rozproszony napisany w Pythonie. Z definicji jest wi&#281;c multiplatformowy (bie&#380;&#261;ca implementacja Git&amp;#8217;a dla win32 jest dosy&#263; s&#322;aba). Zasadniczo niewiele si&#281; r&#243;&#380;ni od Git&amp;#8217;a. Jest troch&#281; wolniejszy, nie ma (przynajmniej ja nie znam) jakich&#347; popularnych darmowych kont do trzymania projekt&#243;w. Ale jego zalet&#261; jest wspomniana wy&#380;ej multiplatformowo&#347;&#263; (dzia&#322;a na win32 bardzo dobrze) oraz integracja z edytorem Netbeans 6 (jeszcze trwaj&#261; prace nad integracj&#261; z Git&amp;#8217;em). Firma Sun wybra&#322;a te&#380; Mercurial jako nast&#281;pc&#281; dla Subversion. S&#261; te&#380; mniejsze firmy kt&#243;re zdecydowa&#322;y si&#281; na Mercurial z powodu lepszej integracji z systemem Windows, ale s&#261; gotowe przej&#347;&#263; na szybszego Git&amp;#8217;a jak tylko zostanie poprawiona jego wersja dla win32.&lt;/p&gt;


	&lt;h3&gt;Bazaar&lt;/h3&gt;


	&lt;p&gt;&lt;a href="http://bazaar-vcs.org/"&gt;Bazaar&lt;/a&gt;, podobnie jak Mercurial, napisany zosta&#322; w Pythonie. Nie ma wi&#281;c problem&#243;w z dzia&#322;aniem pod systemem innym ni&#380; &lt;span class="caps"&gt;POSIX&lt;/span&gt;. Jest to dosy&#263; ciekawy system, bo potrafi pracowa&#263; zar&#243;wno jako system centralny jak i rozproszony. Jego tw&#243;rcy s&#261; mocno przekonani o wy&#380;szo&#347;ci Bazaar nad Git, Mercurial i Subversion, o czym &#347;wiadczy zamieszczone przez nich &#347;mia&#322;e &lt;a href="http://bazaar-vcs.org/BzrWhy"&gt;por&#243;wnanie z tymi systemami&lt;/a&gt;. (Niekt&#243;re stare por&#243;wnania Git&amp;#8217;a z Bazaar podkre&#347;la&#322;y znaczn&#261; przewag&#281; szybko&#347;ci Git&amp;#8217;a, ale niestety najcz&#281;&#347;ciej dotyczy&#322;y one starej, wolniejsze wersji Bazaar. Od wersji 1.0 poprawiono jednak znacznie wydajno&#347;&#263; i ten argument troch&#281;&#160;st&#281;pi&#322; swoje ostrze krytyki).&lt;/p&gt;


	&lt;p&gt;Bazaar posiada, podobnie jak Git, serwer z darmowymi kontami na projekty &amp;#8211; &lt;a href="http://doc.bazaar-vcs.org/latest/en/tutorials/using_bazaar_with_launchpad.html"&gt;launchpad&lt;/a&gt;. To mo&#380;e pom&#243;c spopularyzowa&#263; ten system. Bazaar ma dost&#281;pny wygodny &lt;a href="http://bazaar-vcs.org/BzrEclipse"&gt;plugin do Eclipse&lt;/a&gt;. Co do Netbeans 6, s&#261; jakie&#347; plany, ale &lt;a href="https://lists.ubuntu.com/archives/bazaar/2007q4/033568.html"&gt;na razie nie wiadomo&lt;/a&gt; czy i kiedy dodadz&#261; wsparcie.&lt;/p&gt;


	&lt;h3&gt;Updates&lt;/h3&gt;


	&lt;p&gt;&lt;em&gt;2008-03-23&lt;/em&gt;&lt;/p&gt;


U&#380;ytkownicy &lt;span class="caps"&gt;OSX 10&lt;/span&gt;.5.2 (Leoparda) instaluj&#261; Gita za pomoc&#261; MacPort&#243;w (warto doda&#263; wariant +svn aby mie&#263; dost&#281;p do skrypty git-svn; warianty dost&#281;pne dla Git&amp;#8217;a sprawdza si&#281; za pomoc&#261; komendy &lt;code&gt;port variants git&lt;/code&gt;, a od&#347;wie&#380;enie listy port&#243;w: &lt;code&gt;sudo port -d sync&lt;/code&gt;).
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;sudo port install git-core +svn&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Je&#347;li instalacja wywali si&#281; z powodu problem&#243;w z SQlite3, nale&#380;y doinstalowa&#263; gmake, czyli:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;sudo su
port install gmake
port clean sqlite3
port install sqlite3
port install git-core +svn&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Wed, 19 Mar 2008 12:00:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:52c31377-58b0-4ab0-8c7b-da934a08c64d</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/03/19/distributed-vcs</link>
      <category>git</category>
      <category>mercurial</category>
      <category>bazaar</category>
      <category>python</category>
      <category>subversion</category>
      <category>vcs</category>
    </item>
    <item>
      <title>Szalej&#261;ce frameworki Rubiego i Rack/WSGI</title>
      <description>&lt;p&gt;Merb w wersji 0.9 poszed&#322; na ca&#322;o&#347;&#263; i oparli sw&#243;j midleware na &lt;a href="http://rack.rubyforge.org/"&gt;Rack&amp;#8217;u&lt;/a&gt;. Jej tw&#243;rcy nie kryj&#261; si&#281; &#380;e wzorowali si&#281; na pythonowej bibliotece &lt;a href="http://www.wsgi.org/wsgi"&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt;. Biblioteka ta robi niez&#322;&#261; furor&#281; w kr&#281;gach Rubiego. Powstaje sporo r&#243;&#380;nych mikroframework&#243;w lub szybkich serwer&#243;w &lt;span class="caps"&gt;HTTP&lt;/span&gt; pracuj&#261;cych asynchronicznie i wykorzystuj&#261;cych Rack. Niedawno powsta&#322; &#347;wietny &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt;, a ju&#380; mo&#380;na przeczyta&#263; o &lt;a href="http://www.rubyinside.com/ebb-web-framework-http-server-786.html"&gt;2x szybszy Ebb&lt;/a&gt;. Co ciekawe, Ebb chce docelowo obs&#322;ugiwa&#263; zar&#243;wno frameworki Rubiego jak i &lt;strong&gt;Pythona&lt;/strong&gt;! Jestem ciekaw czy b&#281;dzie w stanie zdetronizowa&#263; serwer &lt;a href="http://pythonpaste.org/"&gt;Paste&lt;/a&gt;... Rack doczeka&#322; si&#281; ju&#380; swojej &lt;a href="http://github.com/booleanman/rackinterfacefilter/tree/master"&gt;implementacji w JRuby&lt;/a&gt;! Umo&#380;liwia to  tym samym odpalanie w &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; wszystkich framework&#243;w kt&#243;re korzystaj&#261; z Rack&amp;#8217;a.&lt;/p&gt;


	&lt;h2&gt;Frameworki&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://rubyonrails.pl"&gt;&lt;strong&gt;Rails&lt;/strong&gt;&lt;/a&gt; &amp;#8211; najwa&#380;niejszy framework Rubiego, mo&#380;e by&#263; odpalany za pomoc&#261; Thina kt&#243;ry &lt;em&gt;u&#380;ywa Rack&lt;/em&gt;. Rails mo&#380;na odpali&#263; na JRuby nawet prosto z &lt;a href="http://www.netbeans.org/features/ruby/index.html"&gt;Netbeans 6&lt;/a&gt; :)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://merbivore.com/"&gt;&lt;strong&gt;Merb&lt;/strong&gt;&lt;/a&gt; &amp;#8211; pretendent do detronizacji Rails, _u&#380;ywa Rack_i tym samym mo&#380;na go odpali&#263; na JRuby.&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://ramaze.net/"&gt;Ramaze&lt;/a&gt; &amp;#8211; podobnie do Merba, stara si&#281; promowa&#263; bardziek elastyczne podej&#347;cie, &lt;em&gt;u&#380;ywa Rack&lt;/em&gt;, raczej nie zagrozi Merbowi&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://fuzed.rubyforge.org/"&gt;Fuzed&lt;/a&gt; &amp;#8211; Rails z &lt;a href="http://yaws.hyber.org/"&gt;&lt;span class="caps"&gt;YAWS&lt;/span&gt;&lt;/a&gt; (szybkim serwerem &lt;span class="caps"&gt;HTTP&lt;/span&gt; napisanym w &lt;a href="http://en.wikipedia.org/wiki/Erlang_programming_language"&gt;Erlangu&lt;/a&gt;)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.nitroproject.org/"&gt;Nitro&lt;/a&gt; &amp;#8211; typu &lt;span class="caps"&gt;MVC&lt;/span&gt; z w&#322;asnym &lt;span class="caps"&gt;ORM&lt;/span&gt; &amp;#8211; &lt;a href="http://www.nitroproject.org/docs/rdoc/classes/Og.html"&gt;Ogg&lt;/a&gt; i naciskiem na &lt;span class="caps"&gt;AJAX&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://enigo.com/projects/iowa/"&gt;&lt;span class="caps"&gt;IOWA&lt;/span&gt;&lt;/a&gt; &amp;#8211; komponentowy, &lt;/li&gt;
		&lt;li&gt;&lt;a href="https://rubyforge.org/projects/wee/"&gt;Wee&lt;/a&gt; wzorowany na smalltalkowym &lt;a href="http://www.seaside.st/"&gt;Seaside&lt;/a&gt; u&#380;ywaj&#261;cym &lt;a href="http://en.wikipedia.org/wiki/Continuation"&gt;kontynuacji&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://sinatra.rubyforge.org/"&gt;Sinatra&lt;/a&gt; &amp;#8211; mikroframework wzorowany na minimalistycznym, pythonowym &lt;a href="http://webpy.org"&gt;Web.py&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://sergiosantos.info/2007/7/camping-a-ruby-microframework"&gt;Camping&lt;/a&gt; &amp;#8211; kolejny mikroframework w Ruby&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://rubywaves.com/"&gt;Wave&lt;/a&gt; &amp;#8211; wzorowany na Camping, te&#380; u&#380;ywa Rack i Rubiego wsz&#281;dzie gdzie si&#281; da.&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://github.com/macournoyer/invisible/tree/master"&gt;Invisible&lt;/a&gt; mikroframework u&#380;ywaj&#261;cy Rack napisany w 35 linijkach kodu Rubiego (bardziej ciekawostka)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Mongrel i sp&#243;&#322;ka&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.webrick.org/"&gt;Webrick&lt;/a&gt; &amp;#8211; serwer http dost&#281;pny razem ze standardow&#261; bibliotek&#261; Rubiego&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://dev.robotcoop.com/Libraries/webrick-high-performance/classes/WEBrick/HighPerformanceServer.html"&gt;Highperformance Webrick&lt;/a&gt; &amp;#8211; szybsza wersja Webricka (u&#380;ywaj&#261;ca uniksowych fork&#243;w)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt; &amp;#8211; klasyka, napisany cz&#281;&#347;ciowo w C, to od niego zacz&#281;&#322;a si&#281; rewolucja i odej&#347;cie od FastCGI jako metody odpalania Rails&#243;w.&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://swiftiply.swiftcore.org/mongrel.html"&gt;Swiftyply i evented_mongrel&lt;/a&gt; asychroniczne, szybsze wersje Mongrela&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://code.macournoyer.com/thin/"&gt;&lt;strong&gt;Thin&lt;/strong&gt;&lt;/a&gt; &amp;#8211; asynchroniczny web server u&#380;ywaj&#261;cy Mongrela i Rack&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://ebb.rubyforge.org/"&gt;&lt;strong&gt;Ebb&lt;/strong&gt;&lt;/a&gt; &amp;#8211; u&#380;ywa Rack, wi&#281;kszo&#347;&#263; kodu jest w C, dlatego jest taki szybki, na razie ma&#322;o dokumentacji, by&#263; mo&#380;e nast&#281;pca Thin&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Tue, 04 Mar 2008 22:56:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:bdcbae56-a710-43b1-84a6-77d5471f8cac</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/03/04/frameworki-rubiego-rack-wsgi</link>
      <category>merb</category>
      <category>jruby</category>
      <category>rack</category>
      <category>python</category>
      <category>ruby</category>
      <category>frameworks</category>
      <category>thin</category>
      <category>rails</category>
      <category>ramaze</category>
      <category>mongerl</category>
      <category>ebb</category>
      <category>fuzed</category>
    </item>
    <item>
      <title>S&#322;oneczna przysz&#322;o&#347;&#263; dla Jythona</title>
      <description>&lt;p&gt;Od czasu odej&#347;cia &lt;a href="http://hugunin.net/story_of_jython.html"&gt;tw&#243;rcy Jythona&lt;/a&gt;, Jima Hugginsa, do firmy Microsoft (do prac na &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPythonem&lt;/a&gt;), rozw&#243;j &lt;a href="http://en.wikipedia.org/wiki/Jython"&gt;Jythona&lt;/a&gt; , (javowej implementacji &lt;a href="http://python.org"&gt;Pythona&lt;/a&gt;) mocno zwolni&#322; i zosta&#322; sporo w tyle za wychodz&#261;cymi kolejnymi wersjami CPythona. Dlatego sympatycy Pythona z pewno&#347;ci&#261; si&#281; uciesz&#261; wiadomo&#347;ci&#261; o tym, &#380;e &lt;a href="http://headius.blogspot.com/2008/03/welcome-pythonistas-to-sun.html"&gt;firma Sun zatrudni&#322;a&lt;/a&gt; na pe&#322;en etat &lt;a href="http://fwierzbicki.blogspot.com/"&gt;Franka Wierzbickiego&lt;/a&gt;, b&#281;d&#261;cego g&#322;&#243;wnym developerem Jythona od grudnia 2005. Jest zatem spora szansa &#380;e projekt nabierze porz&#261;dnego rozp&#281;du tak, jak to si&#281; sta&#322;o z &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Od jakiego&#347; czasu developerzy &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; tak&#380;e pracuj&#261; nad uruchomieniem swego frameworka &lt;a href="http://fwierzbicki.blogspot.com/2008/01/django-beginning-to-work-on-jython.html"&gt;pod Jythonem&lt;/a&gt;. Niestety aktualnie Jython jest zgodny ze starym Pythonem 2.2 i z tego powodu raczej nie zanosi si&#281; aby szybko podobne dzia&#322;ania podj&#281;li developerzy frameworka &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt; (kt&#243;ry wymaga do pracy minimum Pythona 2.4). Ale to wszystko mo&#380;e si&#281;&#160;wkr&#243;tce zmieni&#263;, skoro Jython dosta&#322; si&#281; pod skrzyd&#322;a Suna.&lt;/p&gt;</description>
      <pubDate>Mon, 03 Mar 2008 17:15:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:2927111d-047f-4dcb-8c90-089c05a3f55f</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/03/03/sun-jython</link>
      <category>python</category>
      <category>jython</category>
    </item>
    <item>
      <title>Po wideokonferencji z Matzem</title>
      <description>&lt;p&gt;&lt;a href="http://blog.zabiello.com/articles/2008/02/15/wideokonferencja-z-matzem"&gt;Zapowiadana wcze&#347;niej&lt;/a&gt; wideokonferencja z tw&#243;rc&#261; j&#281;zyka Ruby, zosta&#322;a dobrze przygotowana przez Google. Obraz by&#322; wy&#347;wietlany na du&#380;ym ekranie, i co wa&#380;niejsze mo&#380;na by&#322;o zadawa&#263; pytania prelegentowi i uda&#322;o mi si&#281; nawet dwa zada&#263;. :)&lt;/p&gt;


	&lt;p&gt;Prawd&#281; m&#243;wi&#261;c oczekiwa&#322;em &#380;e Matz powie co&#347; nowego. Nic takiego nie by&#322;o. Mam wra&#380;enie &#380;e nawet slajdy jakie by&#322;y wy&#347;wietlane gdzie&#347; ju&#380; wcze&#347;niej widzia&#322;em. Moim zdaniem, Matz m&#243;wi tak s&#322;abo po angielsku, &#380;e powinien m&#243;wi&#263; w swoim j&#281;zyku, po japo&#324;sku, i korzysta&#263; z t&#322;umacza. Nie s&#261;dz&#281; &#380;e by&#322;oby wolniej, a nie trzeba by by&#322;o te&#380; powtarza&#263; po kilka razy tego samego pytania.&lt;/p&gt;


	&lt;p&gt;Zapyta&#322;em si&#281; go, czy istnieje jaka&#347; oficjalna specyfikacja j&#281;zyka Ruby (lub co&#347; podobnego do pythonowej publicznej &lt;a href="http://www.python.org/dev/peps/"&gt;listy proponowanych ulepsze&#324;&lt;/a&gt;). Brak jednego i drugiego powoduje, &#380;e jest pewne zamieszanie co do sk&#322;adni jaka ma wej&#347;&#263; do Rubiego 2.0. Tak naprawd&#281; to nikt nie wie w jakim kierunku ta sk&#322;adnia pod&#261;&#380;a. Np. nie wiadomo czy &lt;a href="http://www.rubyist.net/~matz/slides/rc2003/"&gt;wcze&#347;niej prezentowane przez Matza slajdy&lt;/a&gt; to tylko takie lu&#378;ne my&#347;li, czy te&#380; jakie&#347; powa&#380;ne propozycje. Nie wiadomo te&#380;&#160;czy cokolwiek z takich &amp;#8220;pomys&#322;&#243;w&amp;#8221; jest dyskutowane w jakim&#347; szerszym gronie poza w&#261;sk&#261; grup&#261; japo&#324;skich samuraj&#243;w (rozmawiaj&#261;cych oczywi&#347;cie tylko po japo&#324;sku).&lt;/p&gt;


	&lt;p&gt;Matz powiedzia&#322; &#380;e jaka&#347; specyfikacja j&#281;zyka jest tworzona przez grup&#281; tworz&#261;c&#261; projekt &lt;a href="http://rubini.us/"&gt;Rubiniusa&lt;/a&gt; i &#380;e jest z nimi w kontakcie. Widz&#281;, &#380;e Matz zaczyna si&#281; z kim&#347; liczy&#263;. To bardzo dobrze. Bo Ruby nie jest taki ca&#322;kiem m&#322;ody (jest w tym samym wieku co Java i tylko rok m&#322;odszy od Pythona) i ju&#380; dawno przesta&#322; by&#263; tylko prywatnym j&#281;zykiem Matza do zabawy.&lt;/p&gt;


	&lt;p&gt;Zapyta&#322;em si&#281; Matza te&#380; o kwesti&#281; sk&#322;adni tzw. &lt;em&gt;named parameters&lt;/em&gt; w Rubim. Czy ju&#380; jest jaka&#347; ustalona sk&#322;adnia i dlaczego po prostu nie skopiuje dobrego i przejrzystego rozwi&#261;zania jakie wyst&#281;puje od dawna w Pythonie? Dla tych co nie znaj&#261; Pythona, przypominam, &#380;e chodzi o wygodne wywo&#322;ywanie funkcji  z parametrami wyst&#281;puj&#261;cymi w dowolnej kolejno&#347;ci. Najlepiej zobaczy&#263; to na przyk&#322;adzie.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;D&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;**&lt;/span&gt;&lt;span class="ident"&gt;kwargs&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;kwargs&lt;/span&gt;
&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;  &lt;span class="comment"&gt;# =&amp;gt; 1 2 C D () {}&lt;/span&gt;
&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 2 C 3 () {}&lt;/span&gt;
&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 2 3 4 (4, 5, 6, 7) {}&lt;/span&gt;
&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;DE&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;foo&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;blah&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 2 C DE () {'foo': 'blah'}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Parametry a i b s&#261; obligatoryjne, c i d posiadaj&#261; domy&#347;lne warto&#347;ci. &lt;code&gt;*args&lt;/code&gt; to lista dowolnych parametr&#243;w (mo&#380;na dzi&#281;ki temu wywo&#322;ywa&#263; funkcj&#281; z dowolnie wielk&#261; liczb&#261; parametr&#243;w). Za&#347; &lt;code&gt;**kwargs&lt;/code&gt; to s&#322;ownik pozwalaj&#261;cy na dodanie dowolnej ilo&#347;ci kolejnych &lt;em&gt;named parameters&lt;/em&gt;. W Pythonie jest to dosy&#263; czytelne i &#322;atwe do zrozumienia.&lt;/p&gt;


	&lt;p&gt;W Ruby sytuacja wygl&#261;da troch&#281; inaczej. Z jednej strony mamy du&#380;e ulepszenie w stos. do Pythona w postaci mo&#380;liwo&#347;ci wysy&#322;ania blok&#243;w kodu do metody. Z drugiej strony, nie mam w og&#243;le mo&#380;liwo&#347;ci wywo&#322;ania parametr&#243;w w dowolnej kolejno&#347;ci lub wywo&#322;ania tylko niekt&#243;rych z nich, reszt&#281; zostawiaj&#261;c warto&#347;ciom domy&#347;lnym.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;D&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{a.inspect}&lt;/span&gt; &lt;span class="expr"&gt;#{b.inspect}&lt;/span&gt; &lt;span class="expr"&gt;#{c.inspect}&lt;/span&gt; &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="comment"&gt;#{d.inspect} #{args.inspect} #{block.inspect}&amp;quot;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W Ruby nie ma jak wywo&#322;a&#263; &lt;code&gt;test(1,2,d=3)&lt;/code&gt;. Takie wygodne pomini&#281;cie na li&#347;cie parametru &lt;code&gt;c&lt;/code&gt; (bo ma domy&#347;ln&#261; warto&#347;&#263;) i tylko tych parametr&#243;w jakie nam pasuje mo&#380;liwe jest tylko w Pythonie. W Ruby aby zmieni&#263; parametr &lt;code&gt;d&lt;/code&gt; trzeba wywo&#322;a&#263; te&#380; parametr &lt;code&gt;c&lt;/code&gt;, czyli w tym wypadku &lt;code&gt;test(1,2,'C',3)&lt;/code&gt;. To jest bardzo niewygodne i powszechnie stosowanym trickiem na pomini&#281;cie tego ograniczenia jest przekazywanie hasza oraz opuszczanie klamer, kt&#243;re w Ruby s&#261; nieobowi&#261;zkowe. Zatem dla&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test2&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;={})&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{x.inspect}&lt;/span&gt; &lt;span class="expr"&gt;#{opts.inspect}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="ident"&gt;test2&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:d=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 {:d=&amp;gt;4}&lt;/span&gt;
&lt;span class="ident"&gt;test2&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:d=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;'})&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 {:d=&amp;gt;4, :c=&amp;gt;&amp;quot;C&amp;quot;}&lt;/span&gt;
&lt;span class="comment"&gt;# to samo bez nawias&#243;w i klamer:&lt;/span&gt;
&lt;span class="ident"&gt;test2&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:d=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 {:d=&amp;gt;4, :c=&amp;gt;&amp;quot;C&amp;quot;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Pozornie uzyskuje si&#281; to samo. Faktycznie jest to tylko &amp;#8220;dirty hack&amp;#8221; i odpowiednik pythonowej konstrukcji&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test2&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;**&lt;/span&gt;&lt;span class="ident"&gt;opts&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;opts&lt;/span&gt;
&lt;span class="ident"&gt;test2&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1 {'c': 'C', 'd': 4}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Po pierwsze, tym sposobem mo&#380;na do metody przekaza&#263; dowolny hasz. Nie ma kontroli na poziomie deklaracji metody, trzeba samemu j&#261; sobie dodatkowo zaimplementowa&#263;. Np. tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;params_check&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;keys&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Forbiden params: &lt;span class="expr"&gt;#{forbiden.inspect}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;opt&lt;/span&gt;&lt;span class="punct"&gt;={})&lt;/span&gt;
  &lt;span class="ident"&gt;params_check&lt;/span&gt; &lt;span class="ident"&gt;opt&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:d&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{x.inspect}&lt;/span&gt; &lt;span class="expr"&gt;#{opt.inspect}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;CE&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; 
&lt;span class="comment"&gt;# =&amp;gt; 1 {:c=&amp;gt;&amp;quot;CE&amp;quot;}&lt;/span&gt;

&lt;span class="ident"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:d=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; 
&lt;span class="comment"&gt;# =&amp;gt; 1 {:d=&amp;gt;4, :c=&amp;gt;&amp;quot;C&amp;quot;}&lt;/span&gt;

&lt;span class="ident"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:c=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:d=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:foo&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;bar&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;hello&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;world&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; RuntimeError: Forbiden params: [:foo, &amp;quot;hello&amp;quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Po drugie, w wypadku przekazywania dodatkowego hasza, pierwszy musi posiada&#263; klamry, bo inaczej nie ma mo&#380;liwo&#347;ci rozr&#243;&#380;nienia kt&#243;re dane maj&#261; wej&#347;&#263; do pierwszego, a kt&#243;re do drugiego hasza.&lt;/p&gt;


	&lt;p&gt;Ale wracaj&#261;c do tego co odpowiedzia&#322; Matz. Przyzna&#322; wprost, &#380;e te &lt;em&gt;named parameters&lt;/em&gt; jakie mia&#322;yby wej&#347;&#263; do Ruby 2.0 s&#261; tak naprawd&#281; zwyk&#322;ym&amp;#8230; haszem! (zobacz &lt;a href="http://www.rubyist.net/~matz/slides/rc2003/mgp00027.html"&gt;ten slajd&lt;/a&gt; z wcze&#347;niejszej prezentacji Matza)&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="comment"&gt;# ...&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;co naprawd&#281; znaczy tyle co&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;fun&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="ident"&gt;c&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;C&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;})&lt;/span&gt;
  &lt;span class="comment"&gt;# ...&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Taka innowacja nie jest w zasadzie &#380;adn&#261; innowacj&#261;, ale sprowadza nas z powrotem do tego co &lt;strong&gt;ju&#380; jest&lt;/strong&gt;. Je&#347;li za&#347; jedyna zmiana jaka tu ma miejsce dotyczy tylko zast&#261;pienia znak&#243;w &lt;code&gt;=&amp;gt;&lt;/code&gt; jednym znakiem dwukropka (tak jak w Pythonie nawiasem m&#243;wi&#261;c) to albo ja tu czego&#347; nie rozumiem, albo to w og&#243;le jest bez sensu.&lt;/p&gt;</description>
      <pubDate>Thu, 21 Feb 2008 01:08:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:35e54175-dbd1-4a27-828a-cb9668b84c6a</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/02/21/po-wideokonferencji-z-matzem</link>
      <category>ruby</category>
      <category>konferencja</category>
      <category>matz</category>
      <category>python</category>
    </item>
    <item>
      <title>Django on Jython</title>
      <description>&lt;p&gt;Pythonistas chyba pozazdro&#347;cili mo&#380;liwo&#347;ci odpalenia &lt;a href="http://rubyonrails.org"&gt;Rails&#243;w&lt;/a&gt; w &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;. Trwaj&#261; prace nad uruchomieniem frameworka &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; w &lt;a href="http://www.jython.org/Project/index.html"&gt;Jythonie&lt;/a&gt;, implementacji Pythona w czystej Javie.&lt;/p&gt;


	&lt;p&gt;Zapyta&#322;em si&#281; na kanale &lt;a href="irc://irc.eu.freenode.net/pylons"&gt;#pylons&lt;/a&gt; odno&#347;nie podobnego ruchu ze strony &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;, ale okazuje si&#281; &#380;e Jython jest dosy&#263; zacofany. Od czasu przej&#347;cia jego tw&#243;rcy do Microsoftu i pracy na &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPythonem&lt;/a&gt; projekt dosy&#263; powoli si&#281; rozwija. Jython zatrzyma&#322; si&#281; na implementacji Pythona 2.2. To dosy&#263; stara wersja zwa&#380;aj&#261;c, &#380;e w mi&#281;dzyczasie wysz&#322;y wersje 2.3, 2.4 i 2.5. Pylons wymaga zgodno&#347;ci min. z Pythonem 2.4. Nie wiem jak ten problem rozwi&#261;&#380;&#261; przy przenoszeniu Django, bo co&#347; nie chce mi si&#281; wierzy&#263; &#380;e jest w pe&#322;ni zgodny ze starym Pythonem 2.2.&lt;/p&gt;</description>
      <pubDate>Tue, 08 Jan 2008 04:34:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:4159d4c3-fcd0-442c-9d15-f96ae24099ea</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/01/08/django-on-jython</link>
      <category>django</category>
      <category>python</category>
      <category>jython</category>
      <category>java</category>
    </item>
    <item>
      <title>Uko&#324;czono Django Book</title>
      <description>&lt;p&gt;Po roku pisania, zebraniu 2.5 tys uwag online od u&#380;ytkownik&#243;w, &lt;a href="http://www.djangoproject.com/weblog/2007/dec/16/book/"&gt;zosta&#322;a uko&#324;czona&lt;/a&gt; ksi&#261;&#380;ka o pythonowym frameworku webowym &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;. Wersja papierowa ma by&#263; w sprzeda&#380;y w przysz&#322;ym tygodniu. &lt;a href="http://www.djangobook.com/"&gt;Wersja online&lt;/a&gt; jest dost&#281;pna za darmo.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Dec 2007 01:07:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:611a5558-cc73-4884-9819-5512ee9bc191</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/12/19/uko%C5%84czono-django-book</link>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Szybki start z Rails, Merb i Pylons</title>
      <description>&lt;p&gt;Celem tego tekstu jest por&#243;wnanie podstawowych czynno&#347;ci niezb&#281;dnych do tego aby uruchomi&#263; Rails, Merb oraz Pylons. Zak&#322;adam &#380;e u&#380;ywany b&#281;dzie&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt; (v2.0.1) + &lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt; + &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt; (v0.4.2)+ &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;Sequel&lt;/a&gt; (v0.4.3) +  &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;  (v0.9.6.1) + &lt;a href="http://sqlalchemy.org"&gt;SQLAlchemy&lt;/a&gt;  + &lt;a href="http://makotemplates.org"&gt;Mako&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Wpierw musimy (je&#347;li jeszcze nie mamy) poinstalowa&#263; stosowne biblioteki. W wypadku Rails i Merba musimy mie&#263; Rubiego i RubyGems oraz doinstalowane gemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;gem install -y rails haml merb sequel merb_sequel&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W wypadku Pylons musimy mie&#263; zainstalowanego Pythona oraz pakiet setuptools daj&#261;cy mo&#380;liwo&#347;&#263; u&#380;ywania skryptu easy_install (taki odpowiednik RubyGems dla Pythona)&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;easy_install Pylons SQLAlchemy Mako&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Tworzenie projektu:&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rails rails_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Merb&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb merb_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Pylons&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster create -t pylons pylons_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Podpi&#281;cie do bazy&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


	&lt;p&gt;Nale&#380;y w pliku config/database.yml wpisa&#263;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_yaml "&gt;&lt;span class="key"&gt;shared&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="anchor"&gt;&amp;amp;shared&lt;/span&gt;  
  &lt;span class="key"&gt;adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; mysql
  &lt;span class="key"&gt;encoding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; utf8
  &lt;span class="key"&gt;username&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; login
  &lt;span class="key"&gt;socket&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; /opt/local/var/run/mysql5/mysqld.sock
  &lt;span class="key"&gt;password&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; haslo
&lt;span class="key"&gt;development&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; rails_app
  &amp;lt;&amp;lt;: *shared
&lt;span class="key"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; test
  &amp;lt;&amp;lt;: *shared
&lt;span class="key"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; rails_app
  &amp;lt;&amp;lt;: *shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Merb&lt;/h3&gt;


Tu jest tak samo jak w Rails z t&#261; r&#243;&#380;nic&#261;, &#380;e nie ma tego pliku. Nale&#380;y stworzy&#263; Plik config/database.yml:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_yaml "&gt;&lt;span class="document"&gt;---
  shared: &amp;amp;shared  &lt;/span&gt;
    &lt;span class="symbol"&gt;:adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; mysql
    &lt;span class="symbol"&gt;:encoding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; utf8
    &lt;span class="symbol"&gt;:username&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; login
    &lt;span class="symbol"&gt;:socket&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; /opt/local/var/run/mysql5/mysqld.sock
    &lt;span class="symbol"&gt;:password&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; haslo
  &lt;span class="key"&gt;development&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; merb_app
    &amp;lt;&amp;lt;: *shared
  &lt;span class="key"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; test
    &amp;lt;&amp;lt;: *shared
  &lt;span class="key"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; merb_app
    &amp;lt;&amp;lt;: *shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Pylons&lt;/h3&gt;


	&lt;p&gt;Tu, niestety, jest wi&#281;ksza zabawa, bo zar&#243;wno Pylons jak i SQLAlchemy s&#261; bardziej z&#322;o&#380;one.&lt;/p&gt;


	&lt;p&gt;W pliku development.ini wstawiamy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;url&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mysql&lt;/span&gt;&lt;span class="punct"&gt;:/&lt;/span&gt;&lt;span class="regex"&gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="symbol"&gt;:haslo@localhost&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="number"&gt;3306&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;pylons_app&lt;/span&gt;
&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;echo&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt;
&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pool_recycle&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;3600&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Warto zwr&#243;ci&#263; uwag&#281;, &#380;e parametr &amp;#8216;pool_recycle&amp;#8217; zabezpiecza nas przed pewnym problemem w MySQL. Ot&#243;&#380; po paru godzinach nieaktywno&#347;ci, potrafi zrywa&#263; zestawione wcze&#347;niej po&#322;&#261;czenie. SQLAlchemy zabezpiecza si&#281; przed tym stukaj&#261;c do bazy co godzin&#281;. Active Record nie ma przed tym standardowo wbudowanego zabezpieczenia (sic!). Sequel za&#347; (te&#380; &amp;#8211; jak SQLAlchemy- pracuj&#261;cy wielow&#261;tkowo) wy&#322;apuje zerwane po&#322;&#261;czenia, czy&#347;ci je i zestawia z powrotem.&lt;/p&gt;


	&lt;p&gt;Musimy ustawi&#263; sesj&#281; dla SQLAlchemy. Dzia&#322;a i czy&#347;ci si&#281; po ka&#380;dym prze&#322;adowaniu przegl&#261;darki internetowej. W pliku pylons_app/lib/base.py wpisujemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# reszta pliku...&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;model&lt;/span&gt; &lt;span class="ident"&gt;as&lt;/span&gt; &lt;span class="ident"&gt;model&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;BaseController(WSGIController):&lt;/span&gt;

    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__call__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;start_response&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
        &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Invoke the Controller&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="ident"&gt;conn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;pylons.g&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;sa_engine&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
        &lt;span class="ident"&gt;model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;conn&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="ident"&gt;try&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
            &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;WSGIController&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__call__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;start_response&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="ident"&gt;finally&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
            &lt;span class="ident"&gt;model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
            &lt;span class="ident"&gt;conn&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;close&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="comment"&gt;# reszta pliku...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;           

	&lt;h2&gt;Tworzenie modeli&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


	&lt;p&gt;W Rails korzystamy z wbudowanych generator&#243;w kodu:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_shell "&gt;$ script/generate model User
-&amp;gt; app/models/user.rb
...
-&amp;gt; db/migrate/001_create_users.rb

$ script/generate model Post
-&amp;gt; app/models/post.rb
...
-&amp;gt; db/migrate/002_create_posts.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Razem z modelami domy&#347;lnie s&#261; tworzone pliki z migracjami. Wpierw jednak zdefiniujmy relacje mi&#281;dzy modelami:&lt;/p&gt;


	&lt;p&gt;Plik app/models/post.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="ident"&gt;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;
  &lt;span class="comment"&gt;# Albo to samo za pomoc&#261; tych metod:&lt;/span&gt;
  &lt;span class="comment"&gt;# def user&lt;/span&gt;
  &lt;span class="comment"&gt;#   User.find :first,:conditions =&amp;gt; [&amp;quot;id=?&amp;quot;, id]&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
  &lt;span class="comment"&gt;# def user=(item)  &lt;/span&gt;
  &lt;span class="comment"&gt;#   self.user_id = item.id&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik app/models/user.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="ident"&gt;has_many&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;
  &lt;span class="comment"&gt;# Albo to samo bardziej bezpo&#347;rednio:&lt;/span&gt;
  &lt;span class="comment"&gt;# def posts&lt;/span&gt;
  &lt;span class="comment"&gt;#  Post.find :all, :conditions =&amp;gt; [&amp;quot;user_id=?&amp;quot;, id]&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Zdefiniujemy nie tylko struktury tabel ale te&#380; wype&#322;nimy je przyk&#322;adowymi danymi.&lt;/p&gt;


	&lt;p&gt;Plik db/migrate/001_create_users.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;CreateUsers&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:force&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;add_index&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
    &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create!&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.down&lt;/span&gt;
    &lt;span class="ident"&gt;drop_table&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik db/migrate/001_create_posts.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;CreatePosts&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:force&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;integer&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;timestamps&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;add_index&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tytu&#322; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tre&#347;&#263; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find_by_name&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save!&lt;/span&gt;    
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.down&lt;/span&gt;
    &lt;span class="ident"&gt;drop_table&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Uruchamiamy migracje:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sprawd&#378;my interaktywnie (w konsoli, czyli po odpaleniu ruby script/console) czy modele dzia&#322;aj&#261; prawid&#322;owo.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;User id: 1, name: &amp;quot;Jarek&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;Post id: 1, user_id: 1, title: &amp;quot;Tytu&#322; artyku&#322;u&amp;quot;, body: &amp;quot;Tre&#347;&#263; artyku&#322;u&amp;quot;, created_at: &amp;quot;2007-12-15 18:16:27&amp;quot;, updated_at: &amp;quot;2007-12-15 18:16:27&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;Tytu&#322; artyku&#322;u&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Merb&lt;/h2&gt;


	&lt;p&gt;Tu wpierw trzeba wybra&#263; jaki &lt;span class="caps"&gt;ORM&lt;/span&gt; chcemy u&#380;ywa&#263; (domy&#347;lnie Merb nie ma w&#322;aczonej obs&#322;ugi &#380;adnego). Operacja jest bardzo prosta. W pliku config/dependencies.rb odkomentujemy linijk&#281; tak aby by&#322;o:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;use_orm&lt;/span&gt; &lt;span class="symbol"&gt;:sequel&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Modele generujemy identycznymi generatorami jak w Rails.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_shell "&gt;$ script/generate model User
-&amp;gt; app/models/user.rb
...
-&amp;gt; schema/migrations/001_add_model_users.rb

$ script/generate model Post
-&amp;gt; app/models/post.rb
...
-&amp;gt; schema/migrations/002_add_model_posts.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Definicja modeli.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;one_to_one&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:from&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:Post&lt;/span&gt;
  &lt;span class="comment"&gt;# To samo co:&lt;/span&gt;
  &lt;span class="comment"&gt;# def user&lt;/span&gt;
  &lt;span class="comment"&gt;#   User.filter(:id=&amp;gt; user_id).first&lt;/span&gt;
  &lt;span class="comment"&gt;# end  &lt;/span&gt;
  &lt;span class="comment"&gt;# def user=(obj)&lt;/span&gt;
  &lt;span class="comment"&gt;#   self.user_id = obj.id&lt;/span&gt;
  &lt;span class="comment"&gt;# end  &lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;# Merb nie ma automagicznego wype&#322;niania tre&#347;ci&#261;&lt;/span&gt;
  &lt;span class="comment"&gt;# p&#243;l o nazwach created_at czy updated_at&lt;/span&gt;
  &lt;span class="comment"&gt;# Ale posiada wywo&#322;ania zwrotne (te&#380; jak Rails)&lt;/span&gt;
  &lt;span class="ident"&gt;after_create&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:created_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:updated_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="ident"&gt;after_update&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:updated_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;one_to_many&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:from&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;
  &lt;span class="comment"&gt;# To samo co:&lt;/span&gt;
  &lt;span class="comment"&gt;# def posts&lt;/span&gt;
  &lt;span class="comment"&gt;#   Post.filter :user_id =&amp;gt; pk&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W przeciwie&#324;stwie do Active Record, w Sequelu mo&#380;na zdefiniowa&#263; (&lt;a href="http://code.google.com/p/ruby-sequel/wiki/SequelModels"&gt;metod&#261; set_schema&lt;/a&gt;) struktur&#281; tabel w modelu (wtedy nie trzeba np. zagl&#261;da&#263; do migracji ani bazy, aby sobie przypomnie&#263; struktur&#281; tabeli). Ale aby oszcz&#281;dzi&#263; sobie pisania, zda&#322;em si&#281; tu na automatyczne rozpoznanie struktury tabel przez Rubiego.&lt;/p&gt;


	&lt;p&gt;Teraz pora na migracje. Sequel te&#380; je posiada, cho&#263; r&#243;&#380;ni&#261; si&#281; troszk&#281; sk&#322;adni&#261; do tych w Active Record.&lt;/p&gt;


	&lt;p&gt;Plik schema/migrations/001_add_mode_users.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AddModelUsers&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table!&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="ident"&gt;primary_key&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt;
      &lt;span class="ident"&gt;varchar&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:size&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;      
    &lt;span class="keyword"&gt;end&lt;/span&gt;  
    &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;down&lt;/span&gt;
    &lt;span class="ident"&gt;execute&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;DROP TABLE users&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik schema/migrations/002_add_mode_posts.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AddModelPosts&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table!&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;      
      &lt;span class="ident"&gt;primary_key&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt; 
      &lt;span class="ident"&gt;integer&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;varchar&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
      &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt;
      &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="symbol"&gt;:created_at&lt;/span&gt; 
      &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="symbol"&gt;:updated_at&lt;/span&gt; 
    &lt;span class="keyword"&gt;end&lt;/span&gt;    
    &lt;span class="ident"&gt;post&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tytu&#322; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tre&#347;&#263; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;down&lt;/span&gt;
    &lt;span class="ident"&gt;execute&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;DROP TABLE posts&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Uruchomienie migracji dzia&#322;a w Sequelu tak samo jak w Active Record (nawet parametr &lt;span class="caps"&gt;VERSION&lt;/span&gt; te&#380; tu dzia&#322;a).&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rake sequel:db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;No to pora na test z interaktywnej konsoli. Odpala si&#281; j&#261; przez:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -i&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;all&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;User:0x19477e8 @changed_columns=[], @values={:name=&amp;gt;&amp;quot;Jarek&amp;quot;, :id=&amp;gt;1}, newfalse]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class 
&lt;/span&gt;&lt;span class="class"&gt;#&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="ident"&gt;MySQL&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="ident"&gt;Dataset&lt;/span&gt;
&lt;span class="comment"&gt;# User.first.posts.sql&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;SELECT * FROM posts WHERE (`user_id` = 1)&amp;quot;        &lt;/span&gt;
&lt;span class="ident"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;Tytu\305\202 artyku\305\202u&amp;quot;      &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sequel nie tylko jest szybszy i u&#380;ywa iterator&#243;w (oszcz&#281;dzaj&#261;&#263; przez to pami&#281;&#263;). Jest te&#380; wielow&#261;tkowy (u&#380;ywa puli w&#261;tk&#243;w) oraz pozwala na krokowy podgl&#261;d kodu &lt;span class="caps"&gt;SQL&lt;/span&gt; &lt;strong&gt;przed&lt;/strong&gt; jakimkolwiek przeslaniem kwerendy do bazy danych. Sequel r&#243;wnie&#380; nie zwraca liste obiektow &lt;span class="caps"&gt;ORM&lt;/span&gt; z bazy (jak Active Record) ale jeden, specjalny obiekt proxy. Pozwala to na interaktywne budowanie kodu w stopniu o wiele lepszym ni&#380; pozwala na to Active Record (czy nawet  DataMapper). Sequel ma r&#243;wnie&#380; &lt;a href="http://code.google.com/p/ruby-sequel/wiki/SequelModels"&gt;wbudowany cache modeli&lt;/a&gt; wsp&#243;&#322;pracuj&#261;cy z szybkim serwerem memcached.&lt;/p&gt;


	&lt;h3&gt;Pylons&lt;/h3&gt;


	&lt;p&gt;Poni&#380;sza konfiguracja jest inspirowana tekstem &lt;a href="http://wiki.pylonshq.com/display/pylonscookbook/SQLAlchemy+0.4+for+people+in+a+hurry"&gt;SQLAlchemy 0.4 for people in a hurry&lt;/a&gt;. Pylons nie wymaga aby ka&#380;dy model by&#322; w oddzielnym pliku, zatem u&#380;yjemy jednego. W pliku pylons_app/model/&lt;i&gt;init&lt;/i&gt;.py wpisujemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# -*- coding: utf8 -*-&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;datetime&lt;/span&gt;

&lt;span class="comment"&gt;# Zgodnie z filozofi&#261; Pythona, importujemy tylko tylko interesuj&#261;ce nas symbole&lt;/span&gt;
&lt;span class="comment"&gt;# aby nie za&#347;mieca&#263; sobie przestrzeni nazw:&lt;/span&gt;

&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;config&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;ForeignKey&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;MetaData&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;orm&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;relation&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;orm&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;scoped_session&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sessionmaker&lt;/span&gt;

&lt;span class="constant"&gt;Session&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;scoped_session&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;sessionmaker&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;autoflush&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;transactional&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;pylons.g&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;sa_engine&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
&lt;span class="ident"&gt;metadata&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MetaData&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;

&lt;span class="comment"&gt;# Tworzymy definicje tabel:&lt;/span&gt;

&lt;span class="ident"&gt;table_users&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;primary_key&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;String&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
  &lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;table_posts&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;primary_key&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;user_id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;ForeignKey&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;users.id&lt;/span&gt;&lt;span class="punct"&gt;')),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;title&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Unicode&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;)),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;body&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Unicode&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;created_at&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;DateTime&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;default&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;datetime&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;updated_at&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;DateTime&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;default&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;datetime&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="comment"&gt;# Zamiast tego mo&#380;na automatycznie wci&#261;gn&#261;&#263; istniej&#261;c&#261; struktur&#281;:&lt;/span&gt;
&lt;span class="comment"&gt;#&lt;/span&gt;
&lt;span class="comment"&gt;# table_users = Table('users', metadata, autoload=True)&lt;/span&gt;
&lt;span class="comment"&gt;# table_posts = Table('posts', metadata, autoload=True)&lt;/span&gt;

&lt;span class="comment"&gt;# Tworzymy definicje modeli.&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User(object):&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post(object):&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;

&lt;span class="comment"&gt;# Mapowanie ORM do klas SQLAlchemy i ustawienie&lt;/span&gt;
&lt;span class="comment"&gt;# relacji jeden-do-wielu&lt;/span&gt;
&lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;table_users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;properties&lt;/span&gt;&lt;span class="punct"&gt;={'&lt;/span&gt;&lt;span class="string"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:relation&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;backref&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;')})&lt;/span&gt;
&lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class