<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CEQGRnY7eyp7ImA9WhRVGEQ.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483</id><updated>2012-01-18T15:12:07.803+02:00</updated><category term="ruby" /><category term="haml" /><category term="qtruby" /><category term="bundler" /><category term="podcast" /><category term="icecast2" /><category term="funny" /><category term="news" /><category term="vkontakte" /><category term="tmux" /><category term="eval" /><category term="ruby1.9" /><category term="irb" /><category term="benchmark" /><category term="redcar" /><category term="regexp" /><category term="merb" /><category term="e-book" /><category term="rack" /><category term="gem" /><category term="oauth2" /><category term="tips" /><category term="rails" /><category term="torrent" /><category term="internet" /><category term="mpd" /><category term="video" /><category term="link" /><category term="windows" /><category term="rubinius" /><category term="vim" /><category term="csv" /><category term="mechanize" /><category term="padrino" /><category term="warden" /><category term="linux" /><category term="apache" /><category term="facebook" /><category term="tk" /><category term="librmpd" /><category term="translation" /><category term="ajax" /><category term="tutorial" /><category term="rubyua" /><category term="rvm" /><category term="ruby2" /><category term="game" /><category term="bash" /><category term="d-bus" /><category term="gui" /><category term="netbeans" /><category term="life" /><category term="jquery" /><category term="uaenv" /><category term="android" /><category term="delayed_job" /><category term="omniauth" /><category term="rails2" /><category term="cURL" /><category term="ruby-shout" /><category term="rubyforge" /><category term="ruboto" /><category term="nokogiri" /><category term="sinatra" /><category term="slim" /><category term="heroku" /><category term="jruby" /><category term="ubuntu" /><category term="datamapper" /><category term="json" /><category term="google" /><category term="wx" /><category term="screencast" /><title>Записки про Ruby</title><subtitle type="html">5.times { print "We *love* Ruby -- it's outrageous!" }</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://ruby-ua.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>164</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/ruby-ua" /><feedburner:info uri="blogspot/ruby-ua" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0cHSHo8eSp7ImA9WhRVE0w.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-6721574952154994023</id><published>2012-01-11T23:57:00.000+02:00</published><updated>2012-01-11T23:57:19.471+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-11T23:57:19.471+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="oauth2" /><category scheme="http://www.blogger.com/atom/ns#" term="vkontakte" /><title>Проблема з авторизацією ВКонтакте через OAuth2</title><content type="html">Сьогодні стикнувся з помилкою при авторизації по OAuth ВКонтакте:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;{&amp;quot;error&amp;quot;:&amp;quot;invalid_request&amp;quot;,&amp;quot;error_description&amp;quot;:&amp;quot;redirect_uri is incorrect&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;Виявляється, треба просто вказати правильний домен. Раніше якимось чином все працювало з невірним доменом.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-E4c7a_rOhac/Tw4Ei8NXVuI/AAAAAAAAIH0/V6YCKQW42IY/s1600/vk_oauth_error.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="311" width="400" src="http://3.bp.blogspot.com/-E4c7a_rOhac/Tw4Ei8NXVuI/AAAAAAAAIH0/V6YCKQW42IY/s400/vk_oauth_error.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-6721574952154994023?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/6721574952154994023/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=6721574952154994023" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6721574952154994023?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6721574952154994023?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/AIMSPDogeKs/oauth2.html" title="Проблема з авторизацією ВКонтакте через OAuth2" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-E4c7a_rOhac/Tw4Ei8NXVuI/AAAAAAAAIH0/V6YCKQW42IY/s72-c/vk_oauth_error.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2012/01/oauth2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04ESH88eyp7ImA9WhRVEUQ.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-129120672419056230</id><published>2012-01-10T14:51:00.002+02:00</published><updated>2012-01-10T14:51:49.173+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-10T14:51:49.173+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby2" /><title>Іменовані аргументи функції в Ruby 2.0</title><content type="html">В Ruby 1.9 іменовані аргументи представляють із себе просто останній аргумент з хешем, як значенням по замовчуванню, і розширення граматики, за допомогою якого ініціалізується цей хеш. Мало хто знає, що в 1.9 можна зробити метод, наприклад:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def a(opts = {}); end
&lt;/code&gt;&lt;/pre&gt;і викликати його як&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;a(go: true, what: &amp;quot;string&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
В trunk Ruby 2.0 &lt;a href="a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&amp;revision=34136"&gt;додали&lt;/a&gt; іменовані аргументи(&lt;i&gt;keyword arguments&lt;/i&gt;) - простий спосіб вказати такий запис при визначенні методу. Наприклад:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def step (by: step, to: limit)
  ...
end

1.step (by: 2, to: 20) do &amp;#124;i&amp;#124;
  p i
end
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-129120672419056230?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/129120672419056230/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=129120672419056230" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/129120672419056230?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/129120672419056230?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/Sd9NBOdi7pU/ruby-20.html" title="Іменовані аргументи функції в Ruby 2.0" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2012/01/ruby-20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIGRno8eip7ImA9WhRWE0g.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-1774213766879433277</id><published>2011-12-31T20:34:00.000+02:00</published><updated>2011-12-31T20:35:27.472+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-31T20:35:27.472+02:00</app:edited><title>З Новим Роком!</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-iUFzcUZQuAI/Tv9QdsTaKjI/AAAAAAAAIHM/IxDJiXMxLf0/s1600/2012.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="271" src="http://2.bp.blogspot.com/-iUFzcUZQuAI/Tv9QdsTaKjI/AAAAAAAAIHM/IxDJiXMxLf0/s400/2012.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;Ruby-ua&lt;/b&gt; вітає усіх з Новим 2012 Роком, який настане вже через кілька годин!&lt;br /&gt;
&lt;br /&gt;
Бажаю в новому році творчих успіхів, гарного коду, відкритих API, швидкого заліза і щоб кваліфікація ваша тільки росла.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$ ruby -e 'def a;10.times{puts " "*rand(79)+"*"};end;99.times{a;puts " "*34+"З Новим 2012 роком!";a;sleep 0.1;puts "\e[2J"}'

&lt;/code&gt;&lt;/pre&gt;
Ура! З наступаючим!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-1774213766879433277?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/1774213766879433277/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=1774213766879433277" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/1774213766879433277?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/1774213766879433277?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/Br0XHFS2dg4/blog-post.html" title="З Новим Роком!" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-iUFzcUZQuAI/Tv9QdsTaKjI/AAAAAAAAIHM/IxDJiXMxLf0/s72-c/2012.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/12/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4BSXw5fCp7ImA9WhRWEEU.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-2454533331890834260</id><published>2011-12-28T16:40:00.001+02:00</published><updated>2011-12-28T16:52:38.224+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-28T16:52:38.224+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><title>Ретроспектива 2011</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-iZzib4r8SDM/TvsoBY1UUAI/AAAAAAAAIG8/fksyZlCJ1Go/s1600/rubyxmas1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="185" src="http://3.bp.blogspot.com/-iZzib4r8SDM/TvsoBY1UUAI/AAAAAAAAIG8/fksyZlCJ1Go/s400/rubyxmas1.png" width="185" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
2011 рік добігає кінця, і я згадав &lt;a href="http://ruby-ua.blogspot.com/2011/02/im-alive-2011.html"&gt;запис&lt;/a&gt;, у якому згадував про найбільш значущі події в світі Ruby, що відбулися в 2010. Хотілось вірити, що тенденція збережеться. Так і сталося.&lt;br /&gt;
&lt;br /&gt;
Цей рік приніс декілька приємних новин:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;У 2011 році Ruby став &lt;a href="http://www.rubyinside.com/happy-18th-birthday-ruby-4416.html"&gt;повнолітнім&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Реліз &lt;a href="http://www.ruby-lang.org/en/news/2011/10/31/ruby-1-9-3-p0-is-released/"&gt;1.9.3&lt;/a&gt; - основної реалізації мови програмування &lt;i&gt;Ruby&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ruby/ruby/commit/6b8d4ab840b2d76d356ba30dbccfef4f5fd10767"&gt;Оголошено&lt;/a&gt; про початок робіт над &lt;i&gt;Ruby 2.0&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/44691"&gt;Опублікований&lt;/a&gt; план підготовки релізу &lt;i&gt;Ruby 2.0&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Matz автор мови &lt;i&gt;Ruby&lt;/i&gt; в інтерв'ю виданню InfoWorld &lt;a href="http://www.infoworld.com/d/application-development/infoworld-interview-ruby-creator-sets-sights-mobile-171503"&gt;повідомив&lt;/a&gt;, що працює над діалектом мови для мобільних пристроїв&lt;/li&gt;
&lt;li&gt;Yukihiro Matsumoto тепер працює в &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.engineyard.com/blog/2011/engine-yards-plans-for-ruby-1-8-6/"&gt;Припинена&lt;/a&gt; підтримка Ruby 1.8.6&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Розвиток альтернативних реалізації мови &lt;i&gt;Ruby&lt;/i&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Реліз &lt;a href="https://github.com/MagLev/maglev"&gt;MagLev 1.0&lt;/a&gt;, альтернативної реалізації &lt;i&gt;Ruby VM&lt;/i&gt; з вбудованим NoSQL-сховищем, побудованої на основі використання 64-розрядної віртуальної машини &lt;i&gt;VMware GemStone/S&lt;/i&gt;, початково створеної для мови &lt;i&gt;Smalltalk&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;Реліз &lt;a href="http://www.rubyinside.com/jruby-1-6-released-ruby-1-9-2-support-and-more-4524.html"&gt;JRuby 1.6&lt;/a&gt; - реалізації мови &lt;i&gt;Ruby&lt;/i&gt;, написаної цілком на &lt;i&gt;Java&lt;/i&gt; і призначеної для виконання у віртуальній машині &lt;i&gt;JVM&lt;/i&gt; з підтримкою &lt;i&gt;Ruby 1.9.2&lt;/i&gt;. &lt;a href="http://blog.jruby.org/2011/12/getting_started_with_jruby_and_java_7/"&gt;Прискорення&lt;/a&gt; JRuby 1.7 у три рази після установки &lt;i&gt;OpenJDK 7 update 2&lt;/i&gt; &lt;/li&gt;
&lt;li&gt;Успіхи спільноти розробників &lt;a href="https://github.com/rubinius/rubinius"&gt;Rubinius&lt;/a&gt; - альтернативної реалізація мови програмування &lt;i&gt;Ruby&lt;/i&gt;, написаної на &lt;i&gt;C++&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.macruby.org/blog/2011/03/23/macruby010.html"&gt;MacRuby 0.10&lt;/a&gt; - реалізація мови програмування &lt;i&gt;Ruby&lt;/i&gt;, написаної на &lt;i&gt;Objective-C&lt;/i&gt; і фреймворку &lt;i&gt;CoreFoundation&lt;/i&gt;. Розроблена компанією &lt;i&gt;Apple Inc.&lt;/i&gt; Базується на версії &lt;i&gt;Ruby&lt;/i&gt; 1.9.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Також хочеться відмітити декілька цікавих проектів:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Бібліотека &lt;a href="https://github.com/sstephenson/rbenv"&gt;rbenv&lt;/a&gt; від &lt;a href="http://37signals.com/"&gt;37signals&lt;/a&gt;: проста і легка альтернатива &lt;a href="http://beginrescueend.com/"&gt;RVM&lt;/a&gt; для керування версіями Ruby&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ruboto.org/"&gt;Ruboto&lt;/a&gt; - фреймворк для написання повноцінних програми для Android на Ruby&lt;/li&gt;
&lt;li&gt;У 2011 склалася тенденція, що &lt;a href="http://travis-ci.org/#!/rails/rails"&gt;кожен&lt;/a&gt; &lt;a href="http://travis-ci.org/#!/rspec/rspec-core"&gt;проект&lt;/a&gt; &lt;a href="http://travis-ci.org/#!/sinatra/sinatra"&gt;на Ruby&lt;/a&gt; приєднується до &lt;a href="http://travis-ci.org/"&gt;Travis&lt;/a&gt;. Travis - дуже проста, система безперервної інтеграції, яка розповсюджується у вигляді відкритих вихідних кодів.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Інші значущі релізи:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://weblog.rubyonrails.org/2011/8/31/rails-3-1-0-has-been-released"&gt;Rails 3.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://intridea.com/2011/11/2/omniauth-1-0"&gt;OmniAuth 1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.engineyard.com/blog/2011/railsinstaller-2-for-windows-released/"&gt;RailsInstaller 2&lt;/a&gt; для Windows&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sinatrarb.com/2011/09/30/sinatra-1.3.0"&gt;Sinatra 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://datamapper.org/articles/datamapper-120-released.html"&gt;DataMapper 1.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.segment7.net/2011/06/27/mechanize-2-0"&gt;Mechanize 2.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
P.S. З наступаючим Новим Роком!&lt;br /&gt;
P.P.S. Якщо вам є що додати, пишіть в коментарі.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-2454533331890834260?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/2454533331890834260/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=2454533331890834260" title="1 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2454533331890834260?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2454533331890834260?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/isDXx5ywA74/ruby-2011.html" title="Ретроспектива 2011" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-iZzib4r8SDM/TvsoBY1UUAI/AAAAAAAAIG8/fksyZlCJ1Go/s72-c/rubyxmas1.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/12/ruby-2011.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUHRXo7cCp7ImA9WhRXFkk.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-2490598620187571408</id><published>2011-12-23T15:17:00.000+02:00</published><updated>2011-12-23T15:17:14.408+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-23T15:17:14.408+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery" /><category scheme="http://www.blogger.com/atom/ns#" term="haml" /><category scheme="http://www.blogger.com/atom/ns#" term="ajax" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><category scheme="http://www.blogger.com/atom/ns#" term="translation" /><title>Створення простого AJAX-сайту з Sinatra та JQuery</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;За основу цієї статті взятий скрінкаст &lt;a href="http://screencasts.org/episodes/ajax-website-with-sinatra-jquery"&gt;Building a Simple AJAX Website with Sinatra &amp;amp; jQuery&lt;/a&gt;. Зараз у вільний час я працюю над сайтом &lt;a href="http://isit.heroku.com/"&gt;isit.heroku.com&lt;/a&gt;, який основну свою ідею почерпнув саме цього скрінкасту.&lt;br /&gt;
&lt;br /&gt;
У цій статті ви дізнаєтеся:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Як створити свій власний веб-сайт із таймером зворотного відліку&lt;/li&gt;
&lt;li&gt;Як визначити в &lt;i&gt;Sinatra&lt;/i&gt;, якщо запит &lt;i&gt;XMLHttpRequest&lt;/i&gt; чи ні&lt;/li&gt;
&lt;li&gt;Як відключити шаблони(layouts) для &lt;i&gt;XHR&lt;/i&gt; запитів у &lt;i&gt;Sinatra&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;У цьому епізоді ми будемо використовувати &lt;i&gt;Sinatra&lt;/i&gt;, &lt;i&gt;HAML&lt;/i&gt; і &lt;i&gt;JQuery&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;"Is It" веб-сайт&lt;/h3&gt;Ви можливо зустрічали цей жанр сайтів раніше. Це прості веб-сайти з "Так" або "Ні" в середині сторінки. Вони відповідають на питання типу "Це Різдво?", "Це Новий Рік?" або інші термінові питання. Іноді на сторінці також є таймер зворотного відліку.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-dKCy6PPUbG8/TjVAkxJ6DjI/AAAAAAAAHek/t_BTqjQvRSs/s1600/1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="151" src="http://1.bp.blogspot.com/-dKCy6PPUbG8/TjVAkxJ6DjI/AAAAAAAAHek/t_BTqjQvRSs/s400/1.png" width="249" /&gt;&lt;/a&gt;&lt;/div&gt;Розробку нашого "Is It" веб-сайту розпочнемо з огляду структури додатку на &lt;i&gt;Sinatra&lt;/i&gt;.&lt;br /&gt;
&lt;i&gt;app.rb&lt;/i&gt; - це головний файл нашого додатку, який містить єдиний маршрут до кореневої URL-адреси. Також ви помітили, у ньому підключається файл &lt;i&gt;lib/countdown.rb&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;
## &lt;b&gt;app.rb&lt;/b&gt;
# -*- encoding: utf-8 -*-
require 'sinatra'
require 'haml'

require_relative 'lib/countdown.rb'

get '/' do

end
&lt;/code&gt;&lt;/pre&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Якщо подивитися у клас &lt;i&gt;BirthdayCountdown&lt;/i&gt;, ми побачимо кілька методів. Але використовувати ми будемо тільки конструктор &lt;i&gt;initialize&lt;/i&gt; , і методи &lt;i&gt;isit?&lt;/i&gt; і &lt;i&gt;seconds_to_go&lt;/i&gt;. Інші методи є допоміжними для цих трьох методів і використовуються для кращої читабельності коду.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;
## &lt;b&gt;countdown.rb&lt;/b&gt;
# -*- encoding: utf-8 -*-

require 'date'

class BirthdayCountdown

  # Cache @month, @day and @year on initialization
  def initialize(month, day)
    @birthday_month = month
    @birthday_day   = day

    # Current date
    @month = DateTime.now.month
    @day   = DateTime.now.day
    @year  = DateTime.now.year
  end
  
  # Is it birthday?
  def isit?
    @month == @birthday_month &amp;amp;&amp;amp; @day == @birthday_day
  end

  # For the countdown
  def seconds_to_go
    ( (next_birthday - DateTime.now) * 24 * 60 * 60 ).to_i
  end

  :private
 
  # Is is the current month after the birthday month?
  def passed_birthday_month?
    @month &amp;gt; @birthday_month
  end
  
  # Is the current month the same month as the birthday month
  # and the day
  def passed_birthday_day?
     @month == @birthday_month &amp;amp;&amp;amp; @day &amp;gt; @birthday_day
  end
  
  # Happened this year
  def already_happend?
    passed_birthday_month? || passed_birthday_day?
  end
  
  # Returns the next birthday
  def next_birthday
    if already_happend?
      # Add 1 year if it's already happened
      DateTime.new(@year + 1 , @birthday_month, @birthday_day) 
    else
      # Create this years date
      DateTime.new(@year, @birthday_month, @birthday_day)
    end
  end
 
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Конструктор приймає два аргументи &lt;i&gt;month&lt;/i&gt; і &lt;i&gt;day&lt;/i&gt;, які запам'ятовуються як &lt;i&gt;@birthday_month&lt;/i&gt; і &lt;i&gt;@birthday_day&lt;/i&gt; відповідно. Крім того для зручності, щоб постійно не повторювати &lt;i&gt;Time.now&lt;/i&gt;, запам'ятовуємо &lt;i&gt;@month&lt;/i&gt;, &lt;i&gt;@day&lt;/i&gt; і &lt;i&gt;@year&lt;/i&gt; для поточної дати.&lt;br /&gt;
&lt;br /&gt;
У методі &lt;i&gt;isit?&lt;/i&gt; ми перевіряємо чи поточний місяць і день співпадають з &lt;i&gt;@birthday_month&lt;/i&gt; і &lt;i&gt;@birthday_day&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Метод &lt;i&gt;seconds_to_go&lt;/i&gt; повертає скільки секунд залишилося до святкування. Він використовує один з допоміжних методів &lt;i&gt;next_birthday&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Ви помітили, що у каталозі &lt;i&gt;views&lt;/i&gt; є макет &lt;i&gt;layout.haml&lt;/i&gt; і два представлення: &lt;i&gt;yes.haml&lt;/i&gt; та &lt;i&gt;no.haml&lt;/i&gt;, один відображається коли день народження, інший - коли ні.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;-# &lt;b&gt;layout.haml&lt;/b&gt;
!!!
%html
  %head
    %title Зворотній відлік
  %body
    =yield
&lt;/code&gt;&lt;/pre&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;-# &lt;b&gt;yes.haml&lt;/b&gt;
%h2 Так!
&lt;/code&gt;&lt;/pre&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;-# &lt;b&gt;no.haml&lt;/b&gt;
%h2 Ні!
%p= "Time to Go: #{@countdown.seconds_to_go}"
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Додамо деяку логіку, у маршрут до кореневої URL-адреси, щоб показати представлення &lt;i&gt;:yes&lt;/i&gt; або &lt;i&gt;:no&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Ініціалізуємо &lt;i&gt;BirthdayCountdown&lt;/i&gt;, шляхом передачі йому 1, 1, як місяць і день:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;get '/' do
   @countdown = BirthdayCountdown.new(1, 1)
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тепер для представлення потрібно відобразити &lt;i&gt;:yes&lt;/i&gt; або &lt;i&gt;:no&lt;/i&gt;. Для цього реалізуємо метод &lt;i&gt;to_view&lt;/i&gt; у класі &lt;i&gt;BirthdayCountdown&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;def to_view
  isit? ? :yes : :no
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
І змінюємо наш маршрут в &lt;i&gt;app.rb&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;get '/' do
  @countdown = BirthdayCountdown.new(1, 1)
  haml @countdown.to_view
end 
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тепер запустимо наш додаток, набравши &lt;i&gt;ruby app.rb&lt;/i&gt; і перейдемо за адресою &lt;a href="http://localhost:4567/"&gt;http://localhost:4567&lt;/a&gt;. Ми побачимо, що код працює. Оскільки сьогодні не Новий рік, він говорить "Ні!".&lt;br /&gt;
&lt;br /&gt;
Ми бачимо зворотній відлік знизу сторінки.  Але він є статичним на даний момент. Так що давайте додамо JQuery , щоб зворотній відлік змінювався кожну секунду, тому що ми просто не можемо чекати!&lt;br /&gt;
&lt;br /&gt;
Підключаємо бібліотеку &lt;i&gt;JQuery&lt;/i&gt; у файлі шаблону &lt;i&gt;layout.haml&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;!!!
%html
  %head
    %title Зворотній відлік
    %script(src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js")
    :javascript
      
  %body= yield
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Під фільтром &lt;i&gt;:javascript&lt;/i&gt; пишемо код JavaScript.&lt;br /&gt;
&lt;br /&gt;
Створимо функцію &lt;i&gt;getUpdate()&lt;/i&gt;, в всередині неї будемо завантажувати кореневий шлях у елемент $("body"). І встановимо таймаут 1000 мілісекунд, або 1 секунду, щоб викликати метод &lt;i&gt;getUpdate&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$(getUpdate);
function getUpdate(){
  $("body").load("/");
  setTimeout(getUpdate,1000);
}
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Якщо ми оновлюємо вікно браузера, ми побачимо, що таймер оновлюється. Це все, що нам потрібно було отримати.&lt;br /&gt;
&lt;br /&gt;
Ну майже все. Якщо ви подивитесь у веб-інспектор, ви побачите, що &lt;i&gt;Sinatra&lt;/i&gt; відсилає повну сторінку, шаблон і представлення, під час кожного запиту &lt;i&gt;Ajax&lt;/i&gt;. Це може мати небажані побічні ефекти у майбутньому.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-m24WREkrMn4/ToxlV_rL_FI/AAAAAAAAH9g/Be0dvAc3ZYs/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="292" src="http://1.bp.blogspot.com/-m24WREkrMn4/ToxlV_rL_FI/AAAAAAAAH9g/Be0dvAc3ZYs/s400/1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;Все, що ми хочемо зробити, це відправляти представлення без шаблону. Щоб вирішити цю проблему нам потрібно вимкнути шаблон, коли виконується &lt;i&gt;XHR&lt;/i&gt; запит.&lt;br /&gt;
&lt;br /&gt;
За допомогою методу &lt;i&gt;request.xhr?&lt;/i&gt; &lt;i&gt;Sinatra&lt;/i&gt; дозволяє з'ясувати чи є запит &lt;i&gt;Ajax&lt;/i&gt; запитом?&lt;br /&gt;
&lt;br /&gt;
Також &lt;i&gt;Sinatra&lt;/i&gt; дозволяє відключити або вказати розташування шаблону. Це робиться шляхом встановлення параметру &lt;i&gt;:layout&lt;/i&gt; у &lt;i&gt;false&lt;/i&gt;, щоб відключити шаблон, або можна передати ім'я шаблону, як символ, щоб включити його.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;get '/' do
  @countdown = BirthdayCountdown.new(1, 1)
  haml @countdown.to_view, :layout =&amp;gt; (request.xhr? ? false : :layout)
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
ОК, давайте перезапустимо додаток &lt;i&gt;Sinatra&lt;/i&gt;, і повернемося до нашого веб-інспектор. Тепер ми бачимо всі нові запити містять тільки частину розмітки з представлення. Чудово.&lt;br /&gt;
&lt;br /&gt;
На цьому це все!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-2490598620187571408?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/2490598620187571408/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=2490598620187571408" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2490598620187571408?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2490598620187571408?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/ady449oVT9g/ajax-sinatra-jquery.html" title="Створення простого AJAX-сайту з Sinatra та JQuery" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-dKCy6PPUbG8/TjVAkxJ6DjI/AAAAAAAAHek/t_BTqjQvRSs/s72-c/1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/ajax-sinatra-jquery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ABSHg9eSp7ImA9WhRQGUk.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-2738254947838233052</id><published>2011-12-13T16:06:00.000+02:00</published><updated>2011-12-15T12:42:39.661+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-15T12:42:39.661+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><title>Асоціації в DataMapper</title><content type="html">Прочитавши заголовок цієї статті, читач мабуть зрозуміє про що піде мова нижче. У далекому 2009 я писав &lt;a href="http://ruby-ua.blogspot.com/2009/11/datamapper.html"&gt;статтю&lt;/a&gt; про DataMapper, у якій згадувались асоціації між моделями. Сьогодні з власного досвіду спробую описати найбільш поширені асоціації та роботу з ними.&lt;br /&gt;
Для початку освіжимо пам'ять.&lt;br /&gt;
&lt;blockquote&gt;&lt;i&gt;DataMapper&lt;/i&gt; - це &lt;i&gt;ORM&lt;/i&gt; бібліотека (англ. Object-relational mapping, Обє'ктно-реляційна проекція - технологія, яка зв'язую бази даних з концепцією об'єктно-орієнтовного програмування, створюючи "віртуальну об'єктну базу даних").&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Асоціації&lt;/i&gt; - це спосіб оголошення відносин між моделями. Вони надають ряд методів, які дозволяють створювати відносини та отримувати пов'язані моделі.&lt;/blockquote&gt;&lt;br /&gt;
Зараз ORM використовуються повсюдно - ніхто не намагається працювати з базою вручну. Функціонал дозволяє зробити багато речей простіше. Робота з асоціаціями стала в рази легшою. Можна не використовувати SQL-запити, а працювати з даними, як зі звичайними об'єктами.&lt;br /&gt;
&lt;br /&gt;
Я писав цю статтю виключно для себе, тому методика викладання навряд чи сподобається вам своєю легкістю і доступністю :))&lt;br /&gt;
Картинка для затравки.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-X3N4rI5Nz9U/TudUc90YUuI/AAAAAAAAIDk/DsTqukymWio/s1600/pizdec.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="269" src="http://1.bp.blogspot.com/-X3N4rI5Nz9U/TudUc90YUuI/AAAAAAAAIDk/DsTqukymWio/s400/pizdec.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;Зацікавило? Тоді ласкаво прошу під кат.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Вхідні дані&lt;/h3&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Користувач(&lt;i&gt;Account&lt;/i&gt;).&lt;/li&gt;
&lt;li&gt;Подія(&lt;i&gt;Event&lt;/i&gt;).&lt;/li&gt;
&lt;li&gt;Коментар(&lt;i&gt;Comment&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Лайк(&lt;em&gt;Like&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;u&gt;1 асоціація&lt;/u&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;Подія має одного користувача(&lt;i&gt;Event.owner =&amp;gt; Account&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Користувач є власником безлічі подій(&lt;i&gt;Account.events =&amp;gt; Event&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;u&gt;2 асоціація&lt;/u&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;Коментар має одного користувача(&lt;i&gt;Comment.owner =&amp;gt; Account&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Користувач є власником безлічі коментарів(&lt;i&gt;Account.comments =&amp;gt; Comment&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;u&gt;3 асоціація&lt;/u&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;Подія має безліч коментарів(&lt;i&gt;Event.comments =&amp;gt; Comment&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Коментар належить одній події(&lt;i&gt;Comment.event =&amp;gt; Event&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;u&gt;4 асоціація&lt;/u&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;Користувач може "лайкати" подію(&lt;i&gt;Account.likeds =&amp;gt; Event&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Подія має безліч лайків(&lt;i&gt;Event.likes =&amp;gt; Account&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;h3&gt;Моделі та асоціації&lt;/h3&gt;Визначаємо моделі для таблиць &lt;i&gt;accounts&lt;/i&gt;, &lt;i&gt;events&lt;/i&gt;, &lt;i&gt;comments&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Account
  include DataMapper::Resource

  property :id, Serial
  property :name, String
end

class Event
  include DataMapper::Resource

  property :id, Serial
  property :name, String
end

class Comment
  include DataMapper::Resource

  property :id, Serial
  property :body, Text
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
На малюнку нижче приведена схема бази даних, а цифрами позначені асоціації між її таблицями.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nYliCcN2K6Q/TunMblGxxKI/AAAAAAAAIDw/qvkc2ZJKx3w/s1600/schema.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="202" width="400" src="http://3.bp.blogspot.com/-nYliCcN2K6Q/TunMblGxxKI/AAAAAAAAIDw/qvkc2ZJKx3w/s400/schema.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Далі по черзі описуємо наші асоціації:&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;1 асоціація&lt;/h4&gt;&lt;u&gt;Подія має одного користувача, а користувач може бути власником безлічі подій.&lt;/u&gt;&lt;br /&gt;
Тут потрібно використовувати зв'язок "один-до-багатьох", який реалізовується через додаткову таблицю &lt;i&gt;authorships&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Account
  include DataMapper::Resource

  has n, :authorships
  has n, :events, :through =&amp;gt; :authorships

end

class Event
  include DataMapper::Resource

  has n, :authorships
  has 1, :owner, :model =&amp;gt; 'Account', :through =&amp;gt; :authorships, :via =&amp;gt; :account
end

class Authorship
  include DataMapper::Resource

  belongs_to :account, :key =&amp;gt; true
  belongs_to :event, :key =&amp;gt; true
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Створимо користувача Anton і подію, автором якої буде цей користувач:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;account = Account.create(:name =&amp;gt; 'Anton')
account.save

event = Event.create(:name =&amp;gt; 'Everyone invited!')
event.owner = account
event.save
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Події, автором яких є Anton:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;account.events.each do &amp;#124;event&amp;#124;
  puts &amp;quot;#{event.owner.name}: #{event.name}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;2 асоціація&lt;/h4&gt;&lt;u&gt;Коментар має одного користувача, а користувач може бути власником безлічі коментарів.&lt;/u&gt;&lt;br /&gt;
Як і у попередній асоціації використовуємо зв'язок "один-до-багатьох", який реалізовується через додаткову таблицю &lt;i&gt;commentators&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Account
  include DataMapper::Resource

  has n, :commentators
  has n, :comments, :through =&amp;gt; :commentators
end

class Comment
  include DataMapper::Resource

  has n, :commentators
  has 1, :owner, :model =&amp;gt; 'Account', :through =&amp;gt; :commentators, :via =&amp;gt; :account
end

class Commentator
  include DataMapper::Resource

  belongs_to :account, :key =&amp;gt; true
  belongs_to :comment, :key =&amp;gt; true
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;3 асоціація&lt;/h4&gt;&lt;u&gt;Подія має безліч коментарів.&lt;/u&gt;&lt;br /&gt;
Тут все просто. Використовуємо зв'язок "один-до-багатьох".&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Event
  include DataMapper::Resource

  has n, :comments
end

class Comment
  include DataMapper::Resource

  belongs_to :event
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Створимо двох користувачів Zoriana та Olia, які прокоментують подію створену користувачем Anton:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;guest1 = Account.create(:name =&amp;gt; 'Zoriana')
guest1.save

guest2 = Account.create(:name =&amp;gt; 'Olia')
guest2.save

comment1 = Comment.create(:body =&amp;gt; 'Right here!')
comment1.owner = guest1
event.comments &amp;lt;&amp;lt; comment1
comment1.save

comment2 = Comment.create(:body =&amp;gt; 'Right now!')
comment2.owner = guest2
event.comments &amp;lt;&amp;lt; comment2
comment2.save
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Коментарі до події:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;event.comments.each do &amp;#124;comment&amp;#124;
  puts &amp;quot;#{comment.owner.name}: #{comment.body}&amp;quot;
end

&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Події, які коментувала Zoriana:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;guest1.comments.each{ &amp;#124;comment&amp;#124; puts &amp;quot;#{comment.event.name} - #{comment.body}&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h4&gt;4 асоціація&lt;/h4&gt;&lt;u&gt;Користувач може "лайкати" подію, а подія може мати безліч лайків від користувачів.&lt;/u&gt;&lt;br /&gt;
Тут будемо використовувати зв’язок "багато-до-багатьох", який реалізовується через додаткову таблицю &lt;i&gt;likeables&lt;/i&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Account
  include DataMapper::Resource

  has n, :likeables
  has n, :likeds, :model =&amp;gt; 'Event', :through =&amp;gt; :likeables, :via =&amp;gt; :event
end

class Event
  include DataMapper::Resource

  has n, :likeables
  has n, :likes, :model =&amp;gt; 'Account', :through =&amp;gt; :likeables, :via =&amp;gt; :account
end

class Likeable
  include DataMapper::Resource

  belongs_to :account, :key =&amp;gt; true
  belongs_to :event, :key =&amp;gt; true
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Користувачам Anton та Zoriana сподобалась подія:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;event.likes &amp;lt;&amp;lt; account
event.likes &amp;lt;&amp;lt; guest1
event.save
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Користувачі, яким сподобалась подія:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;event.likes.each{&amp;#124;like&amp;#124; puts like.name}
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Події, які сподобалися користувачу Zoriana:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;guest1.likeds.each{ &amp;#124;like&amp;#124; puts &amp;quot;#{like.name}&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Нижче наведений повний код моделей з асоціаціями між ними:&lt;br /&gt;
&lt;script src="https://gist.github.com/1472336.js?file=models.rb"&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Замість постскриптуму. Офіційна документація про &lt;a href="http://datamapper.org/docs/associations.html"&gt;асоціації&lt;/a&gt; в DataMapper.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-2738254947838233052?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/2738254947838233052/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=2738254947838233052" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2738254947838233052?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2738254947838233052?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/SY0fnRFSqhQ/datamapper.html" title="Асоціації в DataMapper" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-X3N4rI5Nz9U/TudUc90YUuI/AAAAAAAAIDk/DsTqukymWio/s72-c/pizdec.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/12/datamapper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEMR3g-fSp7ImA9WhRQFkw.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-4450532903910270388</id><published>2011-12-11T13:35:00.001+02:00</published><updated>2011-12-11T16:44:46.655+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-11T16:44:46.655+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tk" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="rvm" /><category scheme="http://www.blogger.com/atom/ns#" term="gui" /><title>Ruby/Tk в RVM</title><content type="html">Так як &lt;a href="http://wxruby.rubyforge.org/"&gt;wxRuby&lt;/a&gt; не розвивається більше 2-ох років, а &lt;a href="http://rubyforge.org/projects/korundum/"&gt;Qt4&lt;/a&gt; надмірний для моїх задач. Вибір впав на бібліотеку &lt;a href="http://www.tcl.tk/"&gt;Tk&lt;/a&gt;, яка поставляється разом з Ruby.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;i&gt;Tk&lt;/i&gt; (від англ. Toolkit — "набір інструментів", "інструментарій") - кросплатформна бібліотека базових елементів графічного інтерфейсу, яка розповсюджується відкритими вихідними текстами.&lt;/blockquote&gt;&lt;br /&gt;
Для того щоб почати використовувати &lt;i&gt;Tk&lt;/i&gt; достатньо імпортувати бібліотеку для роботи з нею:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;require 'tk'
&lt;/code&gt;&lt;/pre&gt;Якщо ви отримаєте помилку&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;LoadError: cannot load such file -- tk
&lt;/code&gt;&lt;/pre&gt;значить &lt;i&gt;Tk&lt;/i&gt; не скомпільована з вашим &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
Якщо у вас &lt;i&gt;RVM&lt;/i&gt;, ласкаво прошу під кат.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Інсталяція Tk з RVM&lt;/h3&gt;Загалом, в системі повинна бути встановлена зв'язка &lt;i&gt;Tcl/Tk&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$ sudo apt-get install tcl-dev tk-dev
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Щоб скористатися &lt;i&gt;Tk&lt;/i&gt; з &lt;i&gt;RVM&lt;/i&gt; потрібно перевстановити &lt;i&gt;Ruby&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$ rvm install 1.9.3 --enable-pthread
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Після того як ви успішно встановили &lt;i&gt;Tk&lt;/i&gt; і прив'язку &lt;i&gt;Tk&lt;/i&gt; для &lt;i&gt;Ruby&lt;/i&gt;, гарна ідея перевірити її та переконатися, що вона працює.&lt;br /&gt;
Наступна програма буде створювати нове вікно за допомогою &lt;i&gt;Tk&lt;/i&gt;. Коли ви запустите її, ви повинні побачити нове вікно.&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;require 'tk'
 
root = TkRoot.new do
  title "Ruby/Tk Test"
end
 
Tk.mainloop
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-4450532903910270388?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/4450532903910270388/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=4450532903910270388" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4450532903910270388?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4450532903910270388?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/M86-4eRojsA/rubytk-rvm.html" title="Ruby/Tk в RVM" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/12/rubytk-rvm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8GR3s-cSp7ImA9WhdaFkk.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-7203190512215523311</id><published>2011-10-26T17:51:00.002+03:00</published><updated>2011-10-26T17:53:46.559+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-26T17:53:46.559+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="warden" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><title>Модель User в DataMapper(з BCryptHash) для Warden</title><content type="html">В процесі написанні статті &lt;a href="http://ruby-ua.blogspot.com/2011/10/user-datamapper-warden.html"&gt;Модель User в DataMapper для Warden&lt;/a&gt; я натрапив на цікавий тип даних &lt;i&gt;BCryptHash&lt;/i&gt;. В &lt;i&gt;DataMapper&lt;/i&gt; він стає доступний, якщо включити гем &lt;a href="https://github.com/datamapper/dm-types"&gt;dm-types&lt;/a&gt;. &lt;i&gt;BCryptHash&lt;/i&gt; зберігається у базі даних як рядок, що представляє сіль, хеш і вартість паролю, використовуючи алгоритм &lt;i&gt;bcrypt&lt;/i&gt;. Він пропонує альтернативу більш звичної пари значень хеш і сіль, які зберігаються у базі даних.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Змінюємо нашу модель &lt;i&gt;User&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class User
  include DataMapper::Resource

  property :id,              Serial
  property :name,            String
  property :password,        BCryptHash

  timestamps :at

  attr_accessor :password_confirmation

  validates_presence_of     :name
  validates_uniqueness_of   :name
  validates_confirmation_of :password

  validates_with_method :password_non_blank
  
private

  def password_non_blank
    if password_confirmation.nil? &amp;#124;&amp;#124; password_confirmation.empty?
      [ false, 'Missing password']
    else
      true
    end
  end

end

&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Нам залишилось лише, написати відкритий метод &lt;i&gt;User#authenticate&lt;/i&gt;, який повертатиме екземпляр класу &lt;i&gt;User&lt;/i&gt;, якщо передане коректне ім'я користувача і пароль.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def self.authenticate(name, password)
  user = first(:name =&amp;gt; name)
  if user
    if user.password != password
      user = nil
    end
  end
  user
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Всю роботу з хешованим паролями бере на себе &lt;i&gt;BCryptHash&lt;/i&gt;. Ми ж працюємо з паролем(&lt;i&gt;password&lt;/i&gt;), як зі звичайним текстовим полем.&lt;br /&gt;
А у базі даних він зберігається зашифрованим. Давайте перевіримо це:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ sqlite3 -line project.db &amp;quot;select * from users&amp;quot;
        id = 1
      name = root
  password = $2a$10$YTc0yuAN/gGyws0cAgWh7.sXGsrTxi/XGGSBeDReIrSsBrzZCOtm6
created_at = 2011-10-26T17:21:21+03:00
updated_at = 2011-10-26T17:21:21+03:00

        id = 2
      name = user
  password = $2a$10$oyt4lSXR1QDMUuARQVDGn.ETroB6fvS0SvtsINtMIBIjPuDZ7wxPS
created_at = 2011-10-26T17:21:28+03:00
updated_at = 2011-10-26T17:21:28+03:00
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Ця модель буде без змін працювати з кодом із &lt;a href="http://ruby-ua.blogspot.com/2011/10/user-datamapper-warden.html"&gt;попередньої статті&lt;/a&gt;. &lt;a href="https://gist.github.com/1316534#file_with_b_crypt_hash.diff"&gt;Тут&lt;/a&gt; можна подивитись на різницю коду. Як бачите вона не значна.&lt;br /&gt;
&lt;br /&gt;
Повний код додатку можна подивитись &lt;a href="https://gist.github.com/1316534"&gt;тут&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-7203190512215523311?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/7203190512215523311/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=7203190512215523311" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7203190512215523311?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7203190512215523311?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/J54V6Nr25Bg/user-datamapper-bcrypthash-warden.html" title="Модель User в DataMapper(з BCryptHash) для Warden" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/user-datamapper-bcrypthash-warden.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UBSXk9fyp7ImA9WhdaGEU.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-4057356987397181056</id><published>2011-10-26T00:12:00.000+03:00</published><updated>2011-10-29T14:54:18.767+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-29T14:54:18.767+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="warden" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><title>Модель User в DataMapper для Warden</title><content type="html">В минулій статті &lt;a href="http://ruby-ua.blogspot.com/2011/10/warden-sinatra-datamapper.html"&gt;Інтеграції Warden з Sinatra і DataMapper&lt;/a&gt; ми написали тестовий додаток, який використовує аутентифікацію по імені і паролю. Уважний читач не міг не помітити, що паролі у базі даних зберігаються у відкритому вигляді. Це все робилося, щоб не завантажувати статтю зайвими сутностями.&lt;br /&gt;
Але очевидно, з точки зору безпеки паролі у базі даних повинні зберігатися в зашифрованому вигляді. Цю тему ми і розглянемо у цій статті.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-mpOfHNaaG5E/TqvpYk0C_nI/AAAAAAAAH_A/JiqblFkMxrQ/s1600/warden.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="152" width="400" src="http://2.bp.blogspot.com/-mpOfHNaaG5E/TqvpYk0C_nI/AAAAAAAAH_A/JiqblFkMxrQ/s400/warden.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
За основу взята 11 глава &lt;i&gt;"Task F: Administration"&lt;/i&gt; з книги &lt;a href="http://pragprog.com/book/rails3/agile-web-development-with-rails"&gt;Agile Web Development with Rails (3rd edition)&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Тут основний упор буде на роботу з &lt;i&gt;DataMapper&lt;/i&gt;. Крім того у другій частині статті ми закладемо фундамент адміністративного інтерфейсу для керування користувачами.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Замість того, щоб зберігати паролі у вигляді звичайного тексту, ми будемо пропускати їх через алгоритм &lt;i&gt;SHA1&lt;/i&gt;, в результаті чого отримаємо 160-бітне хеш-значення. Перевіряти паролі ми будемо шляхом обробки отриманого від користувача пароля, порівнюючи його хешоване значення із значенням, що зберігається в базі даних. Ця система стане ще більш безпечною, шляхом "соління" (&lt;a href="http://en.wikipedia.org/wiki/Salt_(cryptography)"&gt;Salt&lt;/a&gt;) паролю, що змінює початкове число(при генерації псевдовипадкових чисел), яке використовуються при створенні хешу, поєднуючи пароль з псевдовипадковим рядком.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Додавання користувачів&lt;/h3&gt;Для початку нам необхідно змінити нашу модель &lt;i&gt;User&lt;/i&gt; для користувачів. Складність полягає у тому, що вона повинна працювати з текстовою версією паролю(&lt;i&gt;password&lt;/i&gt;), але значення "солі"(&lt;i&gt;salt&lt;/i&gt;) і хешований пароль(&lt;i&gt;hashed_password&lt;/i&gt;) зберігати у базі даних. Отже, наша модель &lt;i&gt;User&lt;/i&gt; разом з перевірками матиме наступний вигляд:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class User
  include DataMapper::Resource

  property :id,              Serial
  property :name,            String
  property :hashed_password, String
  property :salt,            String

  timestamps :at

  attr_accessor :password_confirmation

  validates_presence_of     :name
  validates_uniqueness_of   :name
  validates_confirmation_of :password

  validates_with_method :password_non_blank

  private

  def password_non_blank
    if hashed_password.nil? &amp;#124;&amp;#124; hashed_password.empty?
      [ false, 'Missing password']
    else
      true
    end
  end

end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тут досить багато перевірок, як для такої простої моделі. Ми перевіряємо, що ім'я(&lt;i&gt;name&lt;/i&gt;) присутнє і унікальне (тобто, два користувачі не можуть мати таке ж ім'я в базі даних).&lt;br /&gt;
&lt;br /&gt;
Далі йде таємниче &lt;i&gt;validates_confirmation_of&lt;/i&gt;. Вам, напевне, знайомі такі форми, у яких пропонується ввести пароль і його підтвердження, щоб переконатися, що ви не помилися. &lt;i&gt;DataMapper&lt;/i&gt; може автоматично перевіряти чи два паролі збігаються. Ми побачимо, як це працює за хвилину. А зараз ми просто повинні знати, що нам потрібно два поля для паролів: одне для фактичного паролю(&lt;i&gt;password&lt;/i&gt;), інше для його підтвердження(&lt;i&gt;password_confirmation&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
Нарешті, ми перевіряємо, чи пароль був встановлений. Але ми не перевіряємо атрибут &lt;i&gt;password&lt;/i&gt;. Чому? Бо насправді його не існує, принаймні не в базі даних. Замість цього, ми перевіряємо наявність його посередника, хешованого паролю(&lt;i&gt;hashed_password&lt;/i&gt;). Але щоб зрозуміти це, ми повинні подивитися на те, як ми звертаємося до паролів.&lt;br /&gt;
&lt;br /&gt;
Перш за все, давайте подивимося, як створюється зашифрований пароль. Фокус в тому, щоб створити унікальне значення "солі"(&lt;i&gt;salt&lt;/i&gt;), об'єднавши його з текстовим паролем(&lt;i&gt;password&lt;/i&gt;) в один рядок, а потім запустити SHA1 дайджест. В результаті отримаємо 40-символьний рядок шістнадцяткових цифр.&lt;br /&gt;
Це все ми напишемо, як приватний метод класу:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def self.encrypted_password(password, salt)
  string_to_hash = password + &amp;quot;wibble&amp;quot; + salt
  Digest::SHA1.hexdigest(string_to_hash)
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
"Сіль"(&lt;i&gt;salt&lt;/i&gt;) ми створимо шляхом об'єднання випадкового числа з ідентифікатором об'єкта &lt;i&gt;user&lt;/i&gt;. Не має великого значення якої довжини "сіль", головне це її непередбачуваність (наприклад, використання часу, в якості "солі" має меншу ентропію ніж випадкові рядки). Ми зберігаємо цю нову "сіль" в атрибут &lt;i&gt;salt&lt;/i&gt; моделі об'єкта. Так як це приватний метод, помістимо його після ключового слова &lt;i&gt;privat&lt;/i&gt; :&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;private

def create_new_salt
  self.salt = self.object_id.to_s + rand.to_s
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тепер нам потрібно написати код так, щоб всякий раз як новий текстовий пароль(&lt;i&gt;password&lt;/i&gt;) зберігається в об'єкті &lt;i&gt;User&lt;/i&gt;, ми автоматично створюємо його хешовану версію(&lt;i&gt;hashed_password&lt;/i&gt;), яка зберігатиметься в базі даних.&lt;br /&gt;
Зробимо текстовий пароль(&lt;i&gt;password&lt;/i&gt;) віртуальним атрибутом моделі. Для нашого додатку він виглядатиме, як атрибут, але не зберігатиметься в базі даних.&lt;br /&gt;
&lt;br /&gt;
Якби не було необхідності створювати хешований пароль, ми просто могли б написати:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;attr_accessor :password
&lt;/code&gt;&lt;/pre&gt;За лаштунками, &lt;i&gt;attr_accessor&lt;/i&gt; генерує два методи: для читання &lt;i&gt;password&lt;/i&gt; і для запису &lt;i&gt;password=&lt;/i&gt;. Ми ж напишемо свої власні публічні методи:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def password
  @password
end

def password=(pwd)
  @password = pwd
  return if pwd.empty?
  create_new_salt
  self.hashed_password = User.encrypted_password(self.password, self.salt)
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Нам залишилось лише, написати відкритий метод &lt;i&gt;User#authenticate&lt;/i&gt;, який повертатиме екземпляр класу &lt;i&gt;User&lt;/i&gt;, якщо передане коректне ім'я користувача і пароль. Оскільки вхідний пароль є у вигляді простого тексту, ми повинні знайти запис користувача, використовуючи ім'я(&lt;i&gt;name&lt;/i&gt;) в якості ключа. А потім використати значення "солі"(&lt;i&gt;salt&lt;/i&gt;) в цьому записі, щоб відтворити зашифрований пароль(&lt;i&gt;expected_password&lt;/i&gt;). І повернути об'єкт &lt;i&gt;user&lt;/i&gt;, якщо зашифровані паролі співпадають.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def self.authenticate(name, password)
  user = first(:name =&amp;gt; name)
  if user
    expected_password = encrypted_password(password, user.salt)
    if user.hashed_password != expected_password
      user = nil
    end
  end
  user
end
&lt;/code&gt;&lt;/pre&gt;Як ви пам'ятаєте з попередньої &lt;a href="http://ruby-ua.blogspot.com/2011/10/warden-sinatra-datamapper.html"&gt;статті&lt;/a&gt;, &lt;i&gt;Warden&lt;/i&gt; використовує цей метод для перевірки аутентифікації користувачів.&lt;br /&gt;
&lt;br /&gt;
На всяк випадок, викладу повний код моделі перш ніж ми перейдемо до наступної частини статті.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class User
  include DataMapper::Resource

  property :id,              Serial
  property :name,            String
  property :hashed_password, String
  property :salt,            String

  timestamps :at

  attr_accessor :password_confirmation

  validates_presence_of     :name
  validates_uniqueness_of   :name
  validates_confirmation_of :password

  validates_with_method :password_non_blank

  def self.authenticate(name, password)
    user = first(:name =&amp;gt; name)
    if user
      expected_password = encrypted_password(password, user.salt)
      if user.hashed_password != expected_password
        user = nil
      end
    end
    user
  end

  def password
    @password
  end

  def password=(pwd)
    @password = pwd
    return if pwd.empty?
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end

  private

  def password_non_blank
    if hashed_password.nil? &amp;#124;&amp;#124; hashed_password.empty?
      [ false, 'Missing password']
    else
      true
    end
  end

  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end

  def self.encrypted_password(password, salt)
    string_to_hash = password + &amp;quot;wibble&amp;quot; + salt
    Digest::SHA1.hexdigest(string_to_hash)
  end

end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Адміністрування користувачів&lt;/h3&gt;В &lt;i&gt;Sinаtra&lt;/i&gt; визначимо маршрути для роботи з моделлю &lt;i&gt;User&lt;/i&gt;, реалізувавши 7 стандартних методів:  &lt;i&gt;index&lt;/i&gt;, &lt;i&gt;show&lt;/i&gt;, &lt;i&gt;new&lt;/i&gt;, &lt;i&gt;create&lt;/i&gt;, &lt;i&gt;edit&lt;/i&gt;, &lt;i&gt;update&lt;/i&gt; і &lt;i&gt;delete&lt;/i&gt;.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;# index
get '/users/?' do
  @users = User.all(:order =&amp;gt; [ :name.asc ])

  slim :'/users/index'
end

# new
get '/users/new' do
  @user = User.new

  slim :'/users/new'
end

# show
get '/users/:id' do
  @user = User.first(params[:id])

  slim :'/users/show'
end

# edit
get '/users/:id/edit' do
  @user = User.first(params[:id])
end

# create
post '/users' do
  @user = User.create(:name =&amp;gt; params[:name], :password =&amp;gt; params[:password], :password_confirmation =&amp;gt; params[:password_confirmation])

  if @user.save
    redirect '/users'
  else
    slim :'/users/new'
  end
end

# update
put '/users/:id' do
  @user = User.first(params[:id])

  if @user.update(:name =&amp;gt; params[:name], :password =&amp;gt; params[:password], :password_confirmation =&amp;gt; params[:password_confirmation])
    redirect '/users'
  else
    slim :'/users/edit'
  end
end

# destroy
delete '/users/:id' do
  @user = User.first(params[:id])
  @user.destroy!

  redirect '/users'
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
І на сам кінець, представлення з формою для додавання нових користувачів.&lt;br /&gt;
&lt;b&gt;new.slim&lt;/b&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;form method='post' action='/users'
  fieldset
    legend Enter User Details
    div
      label Name:
      input type='text' name='name'
    div
      label Password:
      input type='password' name='password'
    div
      label Confirm:
      input type='password' name='password_confirmation'

  input type='submit' value='Add User'
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
У цій статті я не буду зупинятися на інших представленнях.&lt;br /&gt;
Повний код додатку можна подивитись &lt;a href="https://gist.github.com/1314246"&gt;тут&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-4057356987397181056?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/4057356987397181056/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=4057356987397181056" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4057356987397181056?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4057356987397181056?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/1h9E98ctDyc/user-datamapper-warden.html" title="Модель User в DataMapper для Warden" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-mpOfHNaaG5E/TqvpYk0C_nI/AAAAAAAAH_A/JiqblFkMxrQ/s72-c/warden.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/user-datamapper-warden.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UMSXs5fip7ImA9WhdaFEo.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-352482541245185275</id><published>2011-10-24T18:48:00.000+03:00</published><updated>2011-10-24T18:48:08.526+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T18:48:08.526+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby2" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><title>Ruby 2.0</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
19 жовтня 2011 &lt;i&gt;Matz&lt;/i&gt;, відомий як розробник мови програмування &lt;i&gt;Ruby&lt;/i&gt;, &lt;a href="https://github.com/ruby/ruby/commit/6b8d4ab840b2d76d356ba30dbccfef4f5fd10767"&gt;оголосив&lt;/a&gt; про початок робіт над версією &lt;i&gt;2.0&lt;/i&gt;.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-9cVOJbr4fl0/Tp757XOmvDI/AAAAAAAAH-I/JGEeiHIClbk/s1600/ruby2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://4.bp.blogspot.com/-9cVOJbr4fl0/Tp757XOmvDI/AAAAAAAAH-I/JGEeiHIClbk/s320/ruby2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Також &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/44691"&gt;з'явився&lt;/a&gt; попередній графік випусків для &lt;i&gt;Ruby 2.0.0&lt;/i&gt;. Як і очікувалось,&amp;nbsp; фінальну версію варто чекати 2 лютого 2013 року на 20-у річницю від дня народження &lt;i&gt;Ruby&lt;/i&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-352482541245185275?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/352482541245185275/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=352482541245185275" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/352482541245185275?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/352482541245185275?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/2wXB3HNhm6E/ruby-20.html" title="Ruby 2.0" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-9cVOJbr4fl0/Tp757XOmvDI/AAAAAAAAH-I/JGEeiHIClbk/s72-c/ruby2.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/ruby-20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8CRXoycSp7ImA9WhdaGEU.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-2409556158993240338</id><published>2011-10-24T18:07:00.001+03:00</published><updated>2011-10-29T14:47:44.499+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-29T14:47:44.499+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="warden" /><category scheme="http://www.blogger.com/atom/ns#" term="rack" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><title>Інтеграції Warden з Sinatra і DataMapper</title><content type="html">В Інтернеті можна знайти багато статей на тему аутентифікації з допомогою &lt;i&gt;Warden&lt;/i&gt; у &lt;i&gt;Sinatra&lt;/i&gt;. Я не буду оригінальним, і напишу ще одну, щоб самому розібратися з особливостями цього інструменту. Ціллю цієї статті не є показати повністю готовий механізм аутентифікації. А лише продемонструвати основні можливості інтеграції &lt;i&gt;Warden&lt;/i&gt; з &lt;i&gt;Sinatra&lt;/i&gt; і &lt;i&gt;Datamapper&lt;/i&gt;.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-8gyiiMky3zM/TqvnqSm2ueI/AAAAAAAAH-0/vgO52uwq5yw/s1600/warden.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="152" width="400" src="http://1.bp.blogspot.com/-8gyiiMky3zM/TqvnqSm2ueI/AAAAAAAAH-0/vgO52uwq5yw/s400/warden.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;a href="https://github.com/hassox/warden"&gt;Warden&lt;/a&gt; - це Rack middleware, що забезпечує механізм аутентифікації для веб-додатків на &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
&lt;i&gt;Warden&lt;/i&gt; вимагає деяких налаштувань для &lt;i&gt;Sinatra&lt;/i&gt;. Цього можна уникнути, використовуючи плагін &lt;a href="https://github.com/jsmestad/sinatra_warden"&gt;Sinatra::Warden&lt;/a&gt;. Але ми ж не шукаємо простих шляхів.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3&gt;Налаштування DataMapper&lt;/h3&gt;Для початку створимо модель і таблицю бази даних для зберігання імені користувача і паролю:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class User
  include DataMapper::Resource

  property :id,       Serial
  property :username, String, :unique =&amp;gt; true
  property :password, String

end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Налаштування Rack&lt;/h3&gt;Повинен бути оголошений додаток для невдач, а також, які стратегії аутентифікації використовуватимуться по замовчуванню.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;use Rack::Session::Cookie, :secret =&amp;gt; &amp;quot;bla-bla-bla&amp;quot;

use Warden::Manager do &amp;#124;manager&amp;#124;
  manager.default_strategies :password
  manager.failure_app = FailureApp.new
end
&lt;/code&gt;&lt;/pre&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class FailureApp
  def call(env)
    uri = env['REQUEST_URI']
    puts &amp;quot;failure #{env['REQUEST_METHOD']} #{uri}&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Налаштування сесії&lt;/h3&gt;Одним з результатів використання будь-якого об'єкта, наприклад об'єкта &lt;i&gt;User&lt;/i&gt;, є те, що ви повинні сказати &lt;i&gt;Warden&lt;/i&gt;, як серіалізувати його у та із сесії. Це потрібно налаштувати:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Warden::Manager.serialize_into_session do &amp;#124;user&amp;#124;
  user.id
end

Warden::Manager.serialize_from_session do &amp;#124;id&amp;#124;
  User.get(id)
end
&lt;/code&gt;&lt;/pre&gt;Після успішної аутентифікації в сесії буде зберігатися ідентифікатор користувача.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Стратегія аутентифікації&lt;/h3&gt;Стратегія у &lt;i&gt;Warden&lt;/i&gt; містить логіку для перевірки аутентифікації запиту.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Warden::Strategies.add(:password) do
  def valid?
    params['username'] &amp;#124;&amp;#124; params['password']
  end
  
  def authenticate!
    u = User.authenticate(params['username'], params['password'])
    u.nil? ? fail!('Could not login in') : success!(u)
  end
end
&lt;/code&gt;&lt;/pre&gt;Вище ми оголосили стратегію під назвою &lt;i&gt;:password&lt;/i&gt;, яка містить два стандартні методи &lt;i&gt;#valid?&lt;/i&gt; і &lt;i&gt;#authenticate!&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Необов'язковий метод &lt;i&gt;#valid?&lt;/i&gt; діє в якості охорони для стратегії. Якщо ви не визначите його, стратегія завжди буде працювати. В іншому випадку стратегія виконуватиметься тільки якщо &lt;i&gt;#valid?&lt;/i&gt; поверне значення &lt;i&gt;true&lt;/i&gt;.&lt;br /&gt;
Стратегія, яку ми оголосили вище передбачає, що якщо переданий хоча б один з параметрів '&lt;i&gt;username'&lt;/i&gt; чи &lt;i&gt;'password'&lt;/i&gt;, то користувач намагається увійти. Якщо є тільки один з ним, то далі виклик &lt;i&gt;User#authenticate&lt;/i&gt; закінчиться невдачею.&lt;br /&gt;
&lt;br /&gt;
У методі &lt;i&gt;#authenticate!&lt;/i&gt; відбувається аутентифікація. Він містить логіку для перевірки аутентифікації запитів.&lt;br /&gt;
&lt;br /&gt;
Тут же і містяться дві стандартні дії: &lt;i&gt;fail!&lt;/i&gt; і &lt;i&gt;success!&lt;/i&gt;.&lt;br /&gt;
&lt;i&gt;success!&lt;/i&gt; встановлює успішну аутентифікацію. Екземпляром класу &lt;i&gt;User&lt;/i&gt; серіалізується у сесію.&lt;br /&gt;
&lt;i&gt;fail!&lt;/i&gt; встановлює, що стратегію пройшла безуспішно.&lt;br /&gt;
&lt;br /&gt;
Для перевірки аутентифікації будемо використовувати відкритий метод &lt;i&gt;User#authenticate&lt;/i&gt;, який повертатиме об'єкт &lt;i&gt;User&lt;/i&gt;, якщо передане коректне ім'я користувача і пароль:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class User
  include DataMapper::Resource
  # ...

  def self.authenticate(username, password)
    user = first(:username =&amp;gt; username)
    if user
      if user.password != password
        user = nil
      end
    end
    user
  end
end
&lt;/code&gt;&lt;/pre&gt;Звичайно, цей метод написаний з метою демонстрації. Насправді, логіка аутентифікації може бути настільки складною, наскільки це необхідно.&lt;br /&gt;
&lt;br /&gt;
Після успішної аутентифікації, екземпляр класу &lt;i&gt;User&lt;/i&gt; серіалізується (&lt;i&gt;Warden::Manager.serialize_into_session&lt;/i&gt;) у сесію. Далі його можна отримати через змінну оточення &lt;i&gt;env['warden'].user&lt;/i&gt;, шляхом десеріалізації (&lt;i&gt;Warden::Manager.serialize_from_session&lt;/i&gt;) по ідентифікатору.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Маршрути Sinatra&lt;/h3&gt;Ось ми і дісталися до завершальної стадії нашої статті. Настав час визначити маршрути для для нашого веб-додатку.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;get '/' do
  # ...
end

get '/login/?' do
  # ...
end

post '/login/?' do
  # ...
end

get '/logout/?' do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
На головній сторінці виводитиметься привітання для користувача, якщо він автентифікований на сайті. Інакше переправлятиметься на сторінку &lt;i&gt;'/login'&lt;/i&gt; з формою для аутентифікації.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;get '/' do
  redirect '/login' unless env['warden'].user
  slim :index
end

get '/login/?' do
  slim :login
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Головна сторінка:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;p Welcome, #{env['warden'].user.username}
a href='/logout' Log out
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Форма для аутентифікації містить для текстових поля 'username' і 'password'.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;form action='/login' method='post'
  ul
    li#username
      label Username:
      br
      input name='username' type='text'
    li#password
      label Password:
      br
      input name='password' type='text'

  input type='submit' value='Log in'
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Після того як користувач введе ім'я і пароль відбувається перевірка аутентифікації. І якщо вона пройшла успішно, користувач переправляється на головну сторінку з привітанням. Ця ж сторінка містить посиланням для виходу.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;post '/login/?' do
  if env['warden'].authenticate
    redirect '/'
  else
    redirect '/login'
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;get '/logout/?' do
  env['warden'].logout
  redirect '/'
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
На всяк випадок, викладу тут повний код додатку.&lt;br /&gt;
&lt;script src="https://gist.github.com/1309189.js?file=sinatra-warden.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-2409556158993240338?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/2409556158993240338/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=2409556158993240338" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2409556158993240338?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/2409556158993240338?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/MoR9U1wLK2c/warden-sinatra-datamapper.html" title="Інтеграції Warden з Sinatra і DataMapper" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-8gyiiMky3zM/TqvnqSm2ueI/AAAAAAAAH-0/vgO52uwq5yw/s72-c/warden.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/warden-sinatra-datamapper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08FSHc7fSp7ImA9WhdaEE4.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-6150507240423247397</id><published>2011-10-19T17:50:00.000+03:00</published><updated>2011-10-19T17:50:19.905+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-19T17:50:19.905+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="link" /><category scheme="http://www.blogger.com/atom/ns#" term="internet" /><title>RubyMonk - ще один браузерний самовчитель Ruby</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-8b8_UBoElvU/Tp7geq9e38I/AAAAAAAAH9w/nMrw-hRLZ7g/s1600/rubymonk.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-8b8_UBoElvU/Tp7geq9e38I/AAAAAAAAH9w/nMrw-hRLZ7g/s1600/rubymonk.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;em&gt;&lt;a href="http://rubymonk.com/"&gt;RubyMonk&lt;/a&gt;&lt;/em&gt; — це інтерактивна платформа, яка допоможе вам освоїти основи мови програмування &lt;i&gt;Ruby&lt;/i&gt;. Вона поєднує в собі переваги навчання з книгою і наставником. І дає навички практичного програмування в ігровій формі.&lt;br /&gt;
&lt;em&gt;RubyMonk&lt;/em&gt; можна рекомендувати початківцям, які тільки відкривають для себе мову &lt;em&gt;Ruby&lt;/em&gt;. &lt;br /&gt;
&lt;br /&gt;
Навчання проходить у двох формах:&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;
&lt;li&gt;&lt;u&gt;Уроки&lt;/u&gt;. Користувач знайомиться з основами мови &lt;em&gt;Ruby&lt;/em&gt; (масиви, ітерації, стрічки тощо). Всі уроки забезпечені докладним описом з прикладами коду, а також доповнені прекрасною можливістю самостійно виконати код.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Проблеми&lt;/u&gt;. Користувачу дається можливість самостійно написати код для вирішення певної проблеми, використовуючи знання, отримані на уроках.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-6150507240423247397?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/6150507240423247397/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=6150507240423247397" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6150507240423247397?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6150507240423247397?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/kuCHCUsqWN8/rubymonk-ruby.html" title="RubyMonk - ще один браузерний самовчитель Ruby" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-8b8_UBoElvU/Tp7geq9e38I/AAAAAAAAH9w/nMrw-hRLZ7g/s72-c/rubymonk.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/rubymonk-ruby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIGR3s5fip7ImA9WhdbEko.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-7827325136794201018</id><published>2011-10-07T12:19:00.001+03:00</published><updated>2011-10-10T21:15:26.526+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-10T21:15:26.526+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rubinius" /><category scheme="http://www.blogger.com/atom/ns#" term="jruby" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby1.9" /><category scheme="http://www.blogger.com/atom/ns#" term="benchmark" /><title>Тестування швидкодії Time і Date в різних версіях Ruby</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-nv6y-hWXYGE/TpM2MsTj5iI/AAAAAAAAH9s/4_zqlPdEbuw/s1600/makes_eat_time.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="198" width="300" src="http://3.bp.blogspot.com/-nv6y-hWXYGE/TpM2MsTj5iI/AAAAAAAAH9s/4_zqlPdEbuw/s400/makes_eat_time.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;Вчора задався питанням швидкодії бібліотек для роботи з датою і часом, які входять до складу &lt;i&gt;Ruby&lt;/i&gt; - &lt;i&gt;Time&lt;/i&gt; і &lt;i&gt;Date&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Для для тестування був написаний простий скрипт з використанням модуля &lt;i&gt;Benchmark&lt;/i&gt;, який надає методи для вимірювання та звітності часу, що був затрачений на виконання коду &lt;i&gt;Ruby&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;require 'benchmark'
require 'date'

puts RUBY_DESCRIPTION
n = 10_000

puts
Benchmark.bm(10) do &amp;#124;x&amp;#124;
  x.report(&amp;quot;Time:&amp;quot;)     { n.times{Time.now} }
  x.report(&amp;quot;DateTime:&amp;quot;) { n.times{DateTime.now} }
end

puts
Benchmark.bm(10) do &amp;#124;x&amp;#124;
  x.report(&amp;quot;Time:&amp;quot;)     { n.times{Time.mktime(2012, 12, 23)} }
  x.report(&amp;quot;DateTime:&amp;quot;) { n.times{DateTime.new(2012, 12, 23)} }
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
У тестуванні будуть брати участь наступні версії &lt;i&gt;Ruby&lt;/i&gt;: &lt;i&gt;1.8.7&lt;/i&gt;, &lt;i&gt;1.9.2&lt;/i&gt; та &lt;i&gt;1.9.3-rc1&lt;/i&gt;, а також альтернативні реалізації інтерпретатора: &lt;i&gt;Rubinius&lt;/i&gt; написаного на мові &lt;i&gt;C++&lt;/i&gt; та &lt;i&gt;JRuby&lt;/i&gt; - на &lt;i&gt;Java&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Тепер подивимося на результат виконання цього скрипта:&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]&lt;/b&gt;

                user     system      total        real
Time:       0.010000   0.000000   0.010000 (  0.032526)
DateTime:   2.910000   0.030000   2.940000 (  4.371719)

                user     system      total        real
Time:       0.040000   0.060000   0.100000 (  0.190266)
DateTime:   1.040000   0.000000   1.040000 (  1.326671)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux]&lt;/b&gt;

                user     system      total        real
Time:       0.020000   0.000000   0.020000 (  0.040165)
DateTime:   0.580000   0.040000   0.620000 (  0.818230)

                user     system      total        real
Time:       0.070000   0.070000   0.140000 (  0.251188)
DateTime:   0.210000   0.000000   0.210000 (  0.280489)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;ruby 1.9.3dev (2011-09-23 revision 33323) [i686-linux]&lt;/b&gt;

                 user     system      total        real
Time:        0.020000   0.000000   0.020000 (  0.029162)
DateTime:    0.020000   0.000000   0.020000 (  0.055203)

                 user     system      total        real
Time:        0.110000   0.040000   0.150000 (  0.195542)
DateTime:    0.010000   0.000000   0.010000 (  0.021322)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;rubinius 1.2.5dev (1.8.7 560efecd yyyy-mm-dd JI) [i686-pc-linux-gnu]&lt;/b&gt;

                user     system      total        real
Time:       0.004001   0.004000   0.008001 (  0.028069)
DateTime:   1.840115   0.028002   1.868117 (  5.183743)

                user     system      total        real
Time:       0.128008   0.040002   0.168010 (  0.429770)
DateTime:   0.896056   0.000000   0.896056 (  3.165078)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;rubinius 2.0.0dev (1.8.7 553ead30 yyyy-mm-dd JI) [i686-pc-linux-gnu]&lt;/b&gt;

                user     system      total        real
Time:       0.008001   0.000000   0.008001 (  0.025819)
DateTime:   2.236140   0.068005   2.304145 (  6.604527)

                user     system      total        real
Time:       0.116007   0.060004   0.176011 (  0.477415)
DateTime:   0.928058   0.004000   0.932058 (  3.251413)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;b&gt;jruby 1.6.4 (ruby-1.8.7-p330) (2011-08-23 17ea768) (OpenJDK Client VM 1.6.0_23) [linux-i386-java]&lt;/b&gt;

                user     system      total        real
Time:       0.364000   0.000000   0.364000 (  0.195000)
DateTime:   2.117000   0.000000   2.117000 (  2.118000)

                user     system      total        real
Time:       0.311000   0.000000   0.311000 (  0.311000)
DateTime:   1.639000   0.000000   1.639000 (  1.639000)
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
P.S. В &lt;i&gt;Ruby 1.9.3&lt;/i&gt; бібліотека &lt;i&gt;'date'&lt;/i&gt; була переписана на мові &lt;i&gt;C&lt;/i&gt; з метою збільшення продуктивності.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-7827325136794201018?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/7827325136794201018/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=7827325136794201018" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7827325136794201018?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7827325136794201018?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/pCF3Ah9NCCI/time-date-ruby.html" title="Тестування швидкодії Time і Date в різних версіях Ruby" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-nv6y-hWXYGE/TpM2MsTj5iI/AAAAAAAAH9s/4_zqlPdEbuw/s72-c/makes_eat_time.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/time-date-ruby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8GQXg5fSp7ImA9WhdUGU0.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-6141806889905973163</id><published>2011-10-06T16:13:00.001+03:00</published><updated>2011-10-06T16:13:40.625+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-06T16:13:40.625+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="mechanize" /><title>Mechanize 2.0 довідник</title><content type="html">&lt;i&gt;Mechanize&lt;/i&gt; - це бібліотека для сканування веб-сайтів для будь-якої автоматизації або з метою тестування. Довідник по &lt;i&gt;Mechanize 2.0&lt;/i&gt; являє собою докладний посібник для отримання речей які можна зробити в &lt;i&gt;Mechanize&lt;/i&gt;. Це більше ніж документація, але менше ніж книга. Робота над нею вже &lt;a href="http://ruby.about.com/od/tasks/a/The-Mechanize-2-0-Handbook.htm"&gt;йде&lt;/a&gt;, і вона буде опублікована &lt;a href="http://ruby.about.com/od/mechanize20handbook/The-Mechanize-2-0-Handbook.htm"&gt;тут&lt;/a&gt; безкоштовно дуже скоро!&lt;br /&gt;&lt;br /&gt;

&lt;i&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/i&gt; Анонс на &lt;a href="http://ruby.about.com/b/2011/07/21/coming-soon-the-mechanize-2-0-handbook.htm"&gt;ruby.about.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-6141806889905973163?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/6141806889905973163/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=6141806889905973163" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6141806889905973163?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6141806889905973163?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/k7dUCYGYOnk/mechanize-20.html" title="Mechanize 2.0 довідник" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/mechanize-20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4CQns_fip7ImA9WhdUF04.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-7767295413400401044</id><published>2011-10-04T13:43:00.001+03:00</published><updated>2011-10-04T15:22:43.546+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-04T15:22:43.546+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="tutorial" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><category scheme="http://www.blogger.com/atom/ns#" term="slim" /><category scheme="http://www.blogger.com/atom/ns#" term="delayed_job" /><title>Приклад роботи Delayed_job з DataMapper у Sinatra</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;i&gt;Delayed_job&lt;/i&gt; (або &lt;i&gt;DJ&lt;/i&gt;) бібліотека асинхронної черги фонових завдань написана на &lt;i&gt;Ruby&lt;/i&gt;.
Може знадобитись для таких типових задач як:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;поштова розсилка&lt;/li&gt;
&lt;li&gt;зміна розмірів зображень&lt;/li&gt;
&lt;li&gt;конвертування аудіо/відео&lt;/li&gt;
&lt;li&gt;HTTP завантаження&lt;/li&gt;
&lt;li&gt;оновлення інформації&lt;/li&gt;
&lt;li&gt;перевірка спаму&lt;/li&gt;
&lt;/ul&gt;
Спочатку написана &lt;a href="https://github.com/tobi"&gt;Tobias Lütke&lt;/a&gt; як плагін для веб-фреймворка &lt;i&gt;Rails&lt;/i&gt; з &lt;i&gt;Active Record&lt;/i&gt;. На даний час підтримується компанією &lt;a href="http://collectiveidea.com/"&gt;Collective Idea&lt;/a&gt;, і дозволяє використовувати ряд інших &lt;a href="https://github.com/collectiveidea/delayed_job/wiki/backends"&gt;бекендів&lt;/a&gt; для збереження черги завдань.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;h3&gt;

&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;

Інсталяція&lt;/h3&gt;
У цій статті &lt;i&gt;Delayed_Job&lt;/i&gt; буде використовуватись разом з &lt;i&gt;DataMapper&lt;/i&gt;.&lt;br /&gt;
Встановлюємо наступні gem'и:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$ gem install delayed_job delayed_job_data_mapper_ste
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;


Вступ в Delayed_job&lt;/h3&gt;
Бібліотека &lt;i&gt;Delayed_job&lt;/i&gt; розвивається навколо таблиці &lt;i&gt;delayed_jobs&lt;/i&gt;, яка має наступну структуру:
&lt;br /&gt;
&lt;table border="2" cellpadding="4"&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;id&lt;/i&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;priority&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Дозволяє завданню перейти до початку черги&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;attempts&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Забезпечує повтори. По замовчуванню 0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;handler&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Серіалізований у &lt;i&gt;YAML&lt;/i&gt; об'єкт, який буде оброблений&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;last_error&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Причина останньої помилки&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;run_at&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Коли виконати. Може бути &lt;i&gt;Time.zone.now&lt;/i&gt; для негайного виконання, або у майбутньому&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;locked_at&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Встановлюється, якщо клієнт працює на цьому об'єкті, тобто заблокований&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;failed_at&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Встановлюється, якщо всі спроби закінчилися невдачею (по замовчуванню, запис буде видалений)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;i&gt;locked_by&lt;/i&gt;&lt;/td&gt;&lt;td&gt;Хто працює на цьому об'єкті (якщо заблокований)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
У разі невдачі, завдання повторюється кожні &lt;i&gt;[5 секунд + N ** 4]&lt;/i&gt;, де &lt;i&gt;N&lt;/i&gt; - це число повторів.&lt;br /&gt;
&lt;br /&gt;
По замовчуванню &lt;i&gt;Worker.max_attempts&lt;/i&gt; рівне &lt;i&gt;25&lt;/i&gt;. Після цього завдання видаляється(по замовчуванню), або залишається у базі зі значенням у полі &lt;i&gt;failed_at&lt;/i&gt;. Із встановленими по замовчуванню 25 спробами, останній повтор буде через 20 днів з останнім інтервалом майже 100 годин.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Worker.max_run_time&lt;/i&gt; по замовчуванню становить 4 години. Якщо завдання вимагає більше часу, доречним буде встановити це значення довшим.&lt;br /&gt;
Невдалі завдання по замовчуванню будуть видалятися (успішні видаляються завжди). Якщо бажаєте зберігати інформацію про невдалі завдання встановіть &lt;i&gt;Delayed::Worker.destroy_failed_jobs = false&lt;/i&gt;. Невдалі завдання будуть позначені у полі &lt;i&gt;failed_at&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
По замовчуванню всі завдання плануються з пріоритетом 0, який є головним. Ви можете це змінити, встановивши &lt;i&gt;Delayed::Worker.default_priority&lt;/i&gt;. Нижчі значення мають вищий пріоритет.&lt;br /&gt;
&lt;br /&gt;
Можна відкласти виконання завдань з метою тестування, встановивши &lt;i&gt;Delayed::Worker.delay_jobs = false&lt;/i&gt;, для виконання всіх завдань в реальному часі.&lt;br /&gt;
&lt;br /&gt;
Ось приклади зміни параметрів завдань:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.max_attempts = 3
Delayed::Worker.max_run_time = 5 * 360
Delayed::Worker.delay_jobs = false&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;

&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;

Розбір коду&lt;/h3&gt;
Ось ми і підійшли до найцікавішого.
Практично весь отриманий код легко зрозумілий і знайти його можна на &lt;a href="https://github.com/mamantoha/sinatra-datamapper-delayed_job"&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Для початку розберемо структуру проекту, вона дуже проста:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;/
|-  Rakefile
|-  app.rb
|-  initializer.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Файл &lt;i&gt;initializer.rb&lt;/i&gt; містить в собі моделі, конфігурацію бази даних і все що стосується роботи фоновими завданнями.&lt;br /&gt;
&lt;i&gt;app.rb&lt;/i&gt; містить весь код для &lt;i&gt;Sinatra&lt;/i&gt;.&lt;br /&gt;
&lt;i&gt;Rakefile&lt;/i&gt; містить виконуваний код &lt;i&gt;Ruby&lt;/i&gt; для фонових завдань.&lt;br /&gt;
&lt;br /&gt;
Для прикладу роботи з &lt;i&gt;Delayed_job&lt;/i&gt;, ми створимо простий &lt;i&gt;Sinatra&lt;/i&gt;-додаток.&lt;br /&gt;
Отже, почнемо зі структури &lt;i&gt;URL&lt;/i&gt;'ів.&lt;br /&gt;
Головна сторінка &lt;i&gt;('/')&lt;/i&gt; по методу &lt;i&gt;GET&lt;/i&gt; видає список фраз та їх переклад. Вона ж і займається введенням нових фраз по &lt;i&gt;POST&lt;/i&gt;'у.&lt;br /&gt;
Сторінка &lt;i&gt;'/translation'&lt;/i&gt; записує текст у базу даних.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;# app.rb
require 'sinatra'
require 'slim'
require_relative 'initializer'

get '/' do
  @translations = Translation.all
  slim :index
end

post '/translation' do
  translation = Translation.create(:input =&amp;gt; params[:input])
  translation.save
  redirect '/'
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Нижче поміщаємо код шаблону на &lt;i&gt;Slim&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;# app.rb
__END__

@@index
h1 Translations
- @translations.each do |translation|
  ul
    li
      span= translation.input
      span &amp;amp;rarr;
      span= translation.output || '...pending...'

h2 New Translation
form method='post' action='/translation'
  ul
    li#input
      label for='translation_input' Input:
      br
      input type='text' id='translation_input' name='input'

  input type='submit' value='New'
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Тепер подивимося, що міститься у файлі &lt;i&gt;initializer.rb&lt;/i&gt;.&lt;br /&gt;
Наступний рядок вказує &lt;i&gt;DJ&lt;/i&gt; використовувати &lt;i&gt;DataMapper&lt;/i&gt; для збереження черги завдань:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Delayed::Worker.backend = :data_mapper
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Підключаємо базу даних &lt;i&gt;SQLite3&lt;/i&gt;:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/db.sqlite3")
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Настав час написати клас моделі:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;class Translation
  include DataMapper::Resource

  property :id,     Serial
  property :input,  Text
  property :output, Text
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Таблиця &lt;i&gt;delayed_jobs&lt;/i&gt; для збереження черги завдань створюватиметься автоматично під час запуску додатку.&lt;br /&gt;
&lt;br /&gt;
Прийшов час поговорити про винуватця бенкету.&lt;br /&gt;
Завданням(&lt;i&gt;Job&lt;/i&gt;) є об'єкт &lt;i&gt;Ruby&lt;/i&gt;, який має метод &lt;i&gt;perform&lt;/i&gt;. Тобто будь-який об'єкт, який відповідає на &lt;i&gt;perform&lt;/i&gt; може бути доданий у таблицю &lt;i&gt;delayed_jobs&lt;/i&gt;. Об'єкти серіалізуються у YAML, так що в майбутньому вони можуть бути відновлені до початкового об'єкта.&lt;br /&gt;
&lt;br /&gt;
Відразу після того як користувач натисне на кнопку "New", дані з параметру &lt;i&gt;input&lt;/i&gt; запишуться в однойменне поле в таблиці &lt;i&gt;translations&lt;/i&gt;. Після цього відбувається постановка об'єкта у чергу завдань для подальшого опрацювання методом &lt;i&gt;Translation#perform&lt;/i&gt;.
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;class Translations
  # ...
  after :create do
    Delayed::Job.enqueue(self)
  end

  def perform
    puts 'Perform some job...'
    self.update( :output =&amp;gt; input.reverse )
  end
end

&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Також можна визначити ряд інших методів для класу моделі, які будуть викликатися на різних стадіях процесу.
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;enqueue(job)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;perform&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;before(job)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;after(job)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;success(job)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;error(job, exception)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;failure&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
В процесі роботи з &lt;i&gt;Delayed_job&lt;/i&gt; я зіткнувся з проблемою десеріалізації об'єктів &lt;i&gt;DataMapper&lt;/i&gt;. Як виявилось проблема &lt;a href="https://github.com/collectiveidea/delayed_job_data_mapper/pull/7"&gt;відома&lt;/a&gt; і після мого запиту виправлений &lt;a href="https://github.com/collectiveidea/delayed_job_data_mapper/commit/9751a93e3cdead6ddc6fb5f7d1c6b9bfcde16697"&gt;код&lt;/a&gt; був доданий в основну гілку &lt;i&gt;delayed_job_data_mapper&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Використовуємо monkey patching в &lt;i&gt;initializer.rb&lt;/i&gt;:&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;module DataMapper
  module Resource
    def self.yaml_new(klass, tag, val)
      klass.get(val['id'])
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Для працездатності нашого коду слід також реалізувати метод &lt;a href="http://api.rubyonrails.org/classes/Enumerable.html#method-i-sum"&gt;sum&lt;/a&gt; з &lt;i&gt;Active Support&lt;/i&gt;:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;class Array; def sum; self.inject(:+); end; end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Файл під ім'ям &lt;i&gt;Rakefile&lt;/i&gt;, розташований в кореневій директорії, містить наступне:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;require_relative 'initializer'

namespace :dj do

  desc "Start DelayedJob worker"
  task :work do
    DataMapper::Logger.new($stdout, :info)
    Delayed::Worker.backend = :data_mapper
    Delayed::Worker.backend.auto_upgrade!
    Delayed::Worker.new.start
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Утиліта rake дозволяє створювати так звані завдання, які виконуються командою &lt;i&gt;rake ІМЯ_ЗАВДАННЯ&lt;/i&gt;.

&lt;br /&gt;
&lt;h3&gt;



&lt;/h3&gt;
&lt;h3&gt;

&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;

Запуск&lt;/h3&gt;
Щоб запустити, виконайте наступні дії:
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;В одному терміналі виконати: &lt;i&gt;rake dj:work&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;В іншому: &lt;i&gt;ruby server.rb&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Перейти у переглядачі за адресою &lt;a href="http://localhost:4567/"&gt;http://localhost:4567&lt;/a&gt; і якщо все зроблено правильно, то насолоджуватися результатом.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;



&lt;/h3&gt;
&lt;h3&gt;

&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;

Посилання&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/collectiveidea/delayed_job"&gt;Delayed::Job&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/collectiveidea/delayed_job_data_mapper"&gt;delayed_job DataMapper backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Код з статті на &lt;a href="https://github.com/mamantoha/sinatra-datamapper-delayed_job"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-7767295413400401044?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/7767295413400401044/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=7767295413400401044" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7767295413400401044?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/7767295413400401044?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/2QynlNPVqYU/delayedjob-datamapper-sinatra.html" title="Приклад роботи Delayed_job з DataMapper у Sinatra" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/delayedjob-datamapper-sinatra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcFSX06eip7ImA9WhdUF08.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-3844034256144993006</id><published>2011-10-03T10:27:00.001+03:00</published><updated>2011-10-04T14:33:38.312+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-04T14:33:38.312+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><title>Реліз Sinatra 1.3.0</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Світ побачила версія 1.3.0 фреймворка &lt;i&gt;Sinatra&lt;/i&gt;.

Найбільш помітне нововведення в цьому релізі - додавання &lt;i&gt;streaming API&lt;/i&gt;. Цікавим моментом є те, що використовувати цю можливість можна незалежно від того, на якому сервері запущено додаток.&lt;br /&gt;
Приклад коду:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;get '/' do
  stream do |out|
    out &amp;lt;&amp;lt; "It's gonna be legen -\n"
    sleep 0.5
    out &amp;lt;&amp;lt; " (wait for it) \n"
    sleep 1
    out &amp;lt;&amp;lt; "- dary!\n"
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Крім того додали підтримку HTTP-методу &lt;a href="http://tools.ietf.org/html/rfc5789"&gt;PATCH&lt;/a&gt;:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;patch '/' do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Про інші зміни читайте в офіційному прес-релізі &lt;a href="http://www.sinatrarb.com/2011/09/30/sinatra-1.3.0"&gt;New feature release, Contrib and Recipes&lt;/a&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-3844034256144993006?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/3844034256144993006/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=3844034256144993006" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3844034256144993006?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3844034256144993006?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/IWfbBHJQavM/sinatra-130.html" title="Реліз Sinatra 1.3.0" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/10/sinatra-130.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUGRHg9fSp7ImA9WhdUF04.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-8540914457826099275</id><published>2011-09-20T10:20:00.000+03:00</published><updated>2011-10-04T17:07:05.665+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-04T17:07:05.665+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="slim" /><title>Коротке введення в шаблонізатор Slim</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-YlFpJ-lMJFU/TnbzQfPBnqI/AAAAAAAAH9Y/KtXhRoQRN8Q/s1600/slim.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="341" src="http://3.bp.blogspot.com/-YlFpJ-lMJFU/TnbzQfPBnqI/AAAAAAAAH9Y/KtXhRoQRN8Q/s400/slim.png" width="312" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;Давно хотів написати статтю про &lt;i&gt;Haml&lt;/i&gt;, та все ніяк не доходили руки. Починаючи з  1.2 &lt;i&gt;Sinatra&lt;/i&gt; підтримує новий шаблонізатор &lt;i&gt;Slim&lt;/i&gt;. Вирішив познайомитися з ним, і він мені відразу сподобався. &lt;i&gt;Slim&lt;/i&gt; взяв найкраще від &lt;i&gt;Haml&lt;/i&gt;, і основне його завдання - зменшити об'єм коду.&lt;br /&gt;
&lt;br /&gt;
Шаблони &lt;i&gt;Slim&lt;/i&gt; можуть виглядати як &lt;i&gt;Haml&lt;/i&gt;, використовуючи ярлики &lt;i&gt;id&lt;/i&gt; і &lt;i&gt;class&lt;/i&gt;, але їх використання не є обов'язковим. Як і в &lt;i&gt;Haml&lt;/i&gt; форматування тут відбувається відступами.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Ось так виглядає приклад шаблону з використанням &lt;i&gt;Slim&lt;/i&gt;:
&lt;script src="https://gist.github.com/1226118.js?file=example.slim"&gt;
&lt;/script&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Якщо &lt;i&gt;Haml&lt;/i&gt; – це &lt;i&gt;HTML&lt;/i&gt; на стероїдах, тоді &lt;i&gt;Slim&lt;/i&gt; – це &lt;i&gt;Haml&lt;/i&gt; на дієті.&lt;/blockquote&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;h3&gt;

Інсталяція:&lt;/h3&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;$ gem install slim
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;




&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;




Список операторів:&lt;/h3&gt;
&lt;table border="2" cellpadding="4"&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;|&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Вертикальна риска повідомляє шаблонізатору, що потрібно просто вивести текст. При цьому всі "небезпечні" символи фільтруються.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;'&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Одинарна лапка працює як і попередній оператор, але додає в кінці пробіл.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;-&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Дефіс працює як в &lt;i&gt;Haml&lt;/i&gt;, використовується для циклів, умов та іншого.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;=&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Знак рівності використовується для виводу результату виконання коду &lt;i&gt;Ruby&lt;/i&gt; в &lt;i&gt;html&lt;/i&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;='&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Працює як і попередній оператор, але додає в кінці пробіл.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;==&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Працює як і знак рівності, але виводить текст "як є", без обробки методом &lt;i&gt;escape_html&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;=='&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Працює як і попередній оператор, але додає в кінці пробіл.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Код не буде виконуватись і не потрапить в &lt;i&gt;html&lt;/i&gt; взагалі.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;/!&lt;/b&gt; &lt;/td&gt;
&lt;td&gt;Знак для &lt;i&gt;html&lt;/i&gt; коментарів (&amp;lt;!-- --&amp;gt;), які потраплять у вивід.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;




&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;




Атрибути та коментарі.&lt;/h3&gt;
Позначати &lt;i&gt;id&lt;/i&gt; і &lt;i&gt;class&lt;/i&gt; можна ось так:
&lt;script src="https://gist.github.com/1226118.js?file=id-class.slim"&gt;
&lt;/script&gt;

Для порівняння в &lt;i&gt;Haml&lt;/i&gt;:
&lt;script src="https://gist.github.com/1226118.js?file=id-class.haml"&gt;
&lt;/script&gt;

Крім того, Slim допускає кілька варіантів синтаксису:
&lt;script src="https://gist.github.com/1226118.js?file=syntax_01.slim"&gt;
&lt;/script&gt;

Допускається на вибір використання наступних обгорток для атрибутів: &lt;i&gt; {...}, [...], (...)&lt;/i&gt;
&lt;script src="https://gist.github.com/1226118.js?file=attribute_wrappers.slim"&gt;
&lt;/script&gt;

Ще одна приємна штука - динамічний контент в атрибуті. Якщо в атрибуті не вказані лапки, буде використана змінна.
&lt;script src="https://gist.github.com/1226118.js?file=dynamic_content.slim"&gt;
&lt;/script&gt;

Подобається, як працюють коментарі. Якщо є блок коду, який потрібно закоментувати, достатньо додати всього один рядок, що вплине на весь блок:
&lt;script src="https://gist.github.com/1226118.js?file=comments.slim"&gt;
&lt;/script&gt;

Завдяки &lt;i&gt;Tilt&lt;/i&gt;, &lt;i&gt;Slim&lt;/i&gt; має підтримку інших шаблонізаторів:
&lt;br /&gt;
&lt;table border="2" cellpadding="4"&gt;
	  &lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Двигун&lt;/td&gt;&lt;td&gt;Фільтр&lt;/td&gt;&lt;td&gt;Необхідні бібліотеки&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ruby&lt;/td&gt;&lt;td&gt;ruby:&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Javascript&lt;/td&gt;&lt;td&gt;javascript:&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CSS&lt;/td&gt;&lt;td&gt;css:&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ERB&lt;/td&gt;&lt;td&gt;erb:&lt;/td&gt;&lt;td&gt;none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Haml&lt;/td&gt;&lt;td&gt;haml:&lt;/td&gt;&lt;td&gt;haml&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Sass&lt;/td&gt;&lt;td&gt;sass:&lt;/td&gt;&lt;td&gt;haml/sass&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Scss&lt;/td&gt;&lt;td&gt;scss:&lt;/td&gt;&lt;td&gt;haml/sass&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LessCSS&lt;/td&gt;&lt;td&gt;less:&lt;/td&gt;&lt;td&gt;less&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Builder&lt;/td&gt;&lt;td&gt;builder:&lt;/td&gt;&lt;td&gt;builder&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Liquid&lt;/td&gt;&lt;td&gt;liquid:&lt;/td&gt;&lt;td&gt;liquid&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;RDiscount&lt;/td&gt;&lt;td&gt;markdown:&lt;/td&gt;&lt;td&gt;rdiscount/kramdown&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;RedCloth&lt;/td&gt;&lt;td&gt;textile:&lt;/td&gt;&lt;td&gt;redcloth&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;RDoc&lt;/td&gt;&lt;td&gt;rdoc:&lt;/td&gt;&lt;td&gt;rdoc&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Radius&lt;/td&gt;&lt;td&gt;radius:&lt;/td&gt;&lt;td&gt;radius&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Markaby&lt;/td&gt;&lt;td&gt;markaby:&lt;/td&gt;&lt;td&gt;markaby&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Nokogiri&lt;/td&gt;&lt;td&gt;nokogiri:&lt;/td&gt;&lt;td&gt;nokogiri&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CoffeeScript&lt;/td&gt;&lt;td&gt;coffee:&lt;/td&gt;&lt;td&gt;coffee-script (+node coffee)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
На сам кінець кілька слів про продуктивність. Інформація взята з офіційної сторінки автора &lt;a href="http://stonean.com/slim-update"&gt;stonean.com/slim-update&lt;/a&gt;:
&lt;br /&gt;
&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;                           user     system      total        real
 erb                    0.560000   0.010000   0.570000 (  0.574373)
 erubis                 0.480000   0.000000   0.480000 (  0.501512)
 fast erubis            0.470000   0.000000   0.470000 (  0.481918)
 slim                   0.610000   0.000000   0.610000 (  0.612794)
 haml                   3.930000   0.010000   3.940000 (  3.939419)
 haml ugly              3.790000   0.010000   3.800000 (  3.798528)
 erb (cached)           0.190000   0.000000   0.190000 (  0.188593)
 erubis (cached)        0.160000   0.000000   0.160000 (  0.159869)
 fast erubis (cached)   0.140000   0.000000   0.140000 (  0.135476)
 slim (cached)          0.150000   0.000000   0.150000 (  0.153698)
 haml (cached)          0.430000   0.000000   0.430000 (  0.436980)
 haml ugly (cached)     0.370000   0.000000   0.370000 (  0.372770)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;



Корисні посилання:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://slim-lang.com/"&gt;slim-lang.com&lt;/a&gt; — офіційна сторінка&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stonean/slim"&gt;github.com/stonean/slim&lt;/a&gt; — сторінка на GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-8540914457826099275?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/8540914457826099275/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=8540914457826099275" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/8540914457826099275?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/8540914457826099275?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/20sDempDfaw/slim.html" title="Коротке введення в шаблонізатор Slim" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-YlFpJ-lMJFU/TnbzQfPBnqI/AAAAAAAAH9Y/KtXhRoQRN8Q/s72-c/slim.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/09/slim.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUBQXs_fyp7ImA9WhdWGU0.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-3817873337668436870</id><published>2011-09-13T12:30:00.004+03:00</published><updated>2011-09-13T12:30:50.547+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-13T12:30:50.547+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="life" /><title>Happy Programmer's Day</title><content type="html">&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ ruby -r date -e &amp;quot;puts %q^Happy Programmer's Day^ if Date.today.yday == 0x100&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

З Днем програміста, друзі!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-3817873337668436870?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/3817873337668436870/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=3817873337668436870" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3817873337668436870?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3817873337668436870?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/K88Q2GegBMY/happy-programmers-day.html" title="Happy Programmer's Day" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/09/happy-programmers-day.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQERXk7fCp7ImA9WhdWFEU.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-508195221003976862</id><published>2011-09-08T14:45:00.000+03:00</published><updated>2011-09-08T14:45:04.704+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-08T14:45:04.704+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Реліз RailsInstaller 2.0</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Запуск &lt;em&gt;Ruby&lt;/em&gt; і &lt;em&gt;Rails&lt;/em&gt; в середовищі ОС &lt;em&gt;Windows&lt;/em&gt; не найпростіша річ у світі. Навіть з такими речами як &lt;a href="http://rubyinstaller.org/"&gt;RubyInstaller&lt;/a&gt;/, можна часто зіткнутися з проблемами при установці певних gem-ів, які вимагають компіляції. Що вже казати про інструменти сторонніх розробників. А як щодо &lt;em&gt;Git&lt;/em&gt;? &lt;em&gt;OpenSSH&lt;/em&gt;? Вам потрібно багато речей, щоб отримати "повноцінне" &lt;em&gt;Rails&lt;/em&gt; середовище для розробки. І &lt;em&gt;RailsInstaller&lt;/em&gt; робить це все для вас в один клік.&lt;br /&gt;
&lt;br /&gt;
Хочу представити вашій увазі реліз &lt;a href="http://railsinstaller.org/"&gt;RailsInstaller&lt;/a&gt; версії 2.0. У попередніх версіях &lt;i&gt;RailsInstaller&lt;/i&gt; використовув &lt;em&gt;1.8.7&lt;/em&gt;. Тепер доступна і версія &lt;em&gt;Ruby&lt;/em&gt; 1.9.2. Крім того доступний реліз-кандидат Rails 3.1. А також включені наступні пакети:&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;
&lt;li&gt;&lt;i&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;a href="http://gembundler.com/"&gt;Bundler&lt;/a&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;a href="http://sqlite.org/"&gt;SQLite&lt;/a&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;gem-и для взаємодії з &lt;i&gt;&lt;a href="https://github.com/rails-sqlserver/activerecord-sqlserver-adapter"&gt;Microsoft SQL Server&lt;/a&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;a href="https://github.com/oneclick/rubyinstaller/wiki/Development-Kit"&gt;DevKit&lt;/a&gt;&lt;/i&gt; - компілятор для ОС Windows, що дозволить встановити gem-и, яким потрібно скомпілювати C код.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-508195221003976862?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/508195221003976862/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=508195221003976862" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/508195221003976862?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/508195221003976862?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/HHVpFjy0TxI/railsinstaller-20.html" title="Реліз RailsInstaller 2.0" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/09/railsinstaller-20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cBRXY7fSp7ImA9WhdWFEU.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-5848265461247428265</id><published>2011-09-08T14:24:00.000+03:00</published><updated>2011-09-08T14:24:14.805+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-08T14:24:14.805+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><title>Інтерв'ю з Юкіхіро Мацумото</title><content type="html">Юкіхіро Мацумото (Yukihiro Matsumoto), автор мови програмування Ruby, в &lt;a href="http://www.infoworld.com/d/application-development/infoworld-interview-ruby-creator-sets-sights-mobile-171503"&gt;інтерв'ю&lt;/a&gt; виданню &lt;i&gt;InfoWorld&lt;/i&gt; згадав про те, що він в даний час займається розробкою альтернативного підмножини або діалекту мови Ruby, спеціально адаптованої для створення програм для портативних пристроїв. Перший публічний випуск мобільного Ruby планується представити на початку наступного року. Крім того, в інтерв'ю згадується те, що після випуску релізу Ruby 1.9.3, який зараз знаходиться на етапі тестування, розробники переключаться на підготовку версії Ruby 2.0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-5848265461247428265?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/5848265461247428265/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=5848265461247428265" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/5848265461247428265?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/5848265461247428265?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/_oq4wozH4nQ/blog-post.html" title="Інтерв'ю з Юкіхіро Мацумото" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/09/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MBQHk9fyp7ImA9WhdXGUg.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-9085947791601453933</id><published>2011-09-02T13:30:00.001+03:00</published><updated>2011-09-02T13:30:51.767+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-02T13:30:51.767+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="datamapper" /><category scheme="http://www.blogger.com/atom/ns#" term="sinatra" /><title>will_paginate 3.0: Sinatra і DataMapper</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-w5DeSAMfJy0/TmCvv_dytPI/AAAAAAAAH7c/0PAsv0kJ4Tk/s1600/3274006362_4ecc2f67ac.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="266" width="400" src="http://4.bp.blogspot.com/-w5DeSAMfJy0/TmCvv_dytPI/AAAAAAAAH7c/0PAsv0kJ4Tk/s400/3274006362_4ecc2f67ac.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

Після більше року розробки вийшла фінальна версія &lt;a href="https://github.com/mislav/will_paginate/wiki"&gt;will_paginate 3.0&lt;/a&gt;.
Основні зміни:
&lt;ul&gt;
&lt;li&gt;Підтримка Rails 3.0 і 3.1&lt;/li&gt;
&lt;li&gt;Підтримка Sinatra і Merb&lt;/li&gt;
&lt;li&gt;Інтеграція з DataMapper і Sequel&lt;/li&gt;
&lt;li&gt;Переклад із бібліотекою i18n&lt;/li&gt;
&lt;li&gt;Припинена підтримка Rails версій 1.2 - 2.3&lt;/li&gt;
&lt;/ul&gt;

Встановлення:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;gem install will_paginate
&lt;/code&gt;&lt;/pre&gt;

&lt;i&gt;Sinatra&lt;/i&gt; додаток потребує наступні бібліотеки:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;require 'will_paginate'
require 'will_paginate/data_mapper'  # &amp;#1072;&amp;#1073;&amp;#1086; active_record/sequel
&lt;/code&gt;&lt;/pre&gt;

Вносимо зміни до дії &lt;i&gt;index&lt;/i&gt;, щоб виводити по 5 записів на сторінку. Номер сторінки передаватиметься у рядку запиту (наприклад, &lt;a href="http://localhost:4567/posts?page=3"&gt;http://localhost:4567/posts?page=3&lt;/a&gt;)
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;# index
get &amp;quot;/posts&amp;quot; do
  @posts = Post.paginate :page =&amp;gt; params[:page], :per_page =&amp;gt; 5
  haml :&amp;quot;posts/index&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;

Додаємо помічник &lt;i&gt;will_paginate&lt;/i&gt; для виведення посилань на сторінки:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#header
  %h1 &amp;#1052;&amp;#1110;&amp;#1081; &amp;#1073;&amp;#1083;&amp;#1086;&amp;#1075;

%a{:href =&amp;gt; &amp;quot;posts/new&amp;quot;}&amp;gt; New Post
#content
  - @posts.each do &amp;#124;post&amp;#124;
    .container
      %h3= post.title
      %p= post.body
      %p= post.created_at

  #pagination
    = will_paginate @posts
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-9085947791601453933?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/9085947791601453933/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=9085947791601453933" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/9085947791601453933?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/9085947791601453933?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/r5PMqkR8Ed4/willpaginate-30-sinatra-datamapper.html" title="will_paginate 3.0: Sinatra і DataMapper" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-w5DeSAMfJy0/TmCvv_dytPI/AAAAAAAAH7c/0PAsv0kJ4Tk/s72-c/3274006362_4ecc2f67ac.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/09/willpaginate-30-sinatra-datamapper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AGQHg9cCp7ImA9WhdQFkg.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-4846833531777280821</id><published>2011-08-18T12:28:00.000+03:00</published><updated>2011-08-18T12:28:41.668+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-18T12:28:41.668+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="internet" /><title>Compilr - онлайн-IDE для C#, PHP, C/C++, Ruby, VB, Java</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-bWiw5XxU6LI/TkzFyF3bsxI/AAAAAAAAHfQ/80cFy7YMO7A/s1600/compilr.png" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="340" width="108" src="http://2.bp.blogspot.com/-bWiw5XxU6LI/TkzFyF3bsxI/AAAAAAAAHfQ/80cFy7YMO7A/s400/compilr.png" /&gt;&lt;/a&gt;&lt;/div&gt;

Натрапив на досить цікавий проект – &lt;a href="http://compilr.com/"&gt;Compilr&lt;/a&gt;. Сервіс являє собою онлайн-IDE, що дозволяє писати і компілювати код для різних платформ під будь-яким сучасним веб-браузером. &lt;i&gt;Compilr&lt;/i&gt; постійно розвивається в ногу зі змінами у світі розробки, інтегрує новітні і найбільш актуальні платформ і мови програмування. На даний момент заявлена підтримка наступні мови: C#, PHP, C/C++, Ruby, VB, Java.

Після безкоштовної реєстрації вам буде доступно 250 мегабайт вільного простору для трьох публічних проектів.
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-4846833531777280821?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/4846833531777280821/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=4846833531777280821" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4846833531777280821?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/4846833531777280821?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/7FLq3DJtVpM/compilr-ide-c-php-cc-ruby-vb-java.html" title="Compilr - онлайн-IDE для C#, PHP, C/C++, Ruby, VB, Java" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-bWiw5XxU6LI/TkzFyF3bsxI/AAAAAAAAHfQ/80cFy7YMO7A/s72-c/compilr.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/08/compilr-ide-c-php-cc-ruby-vb-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIMRXk6eSp7ImA9WhdRFks.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-6405657356334938836</id><published>2011-08-06T23:21:00.001+03:00</published><updated>2011-08-06T23:29:44.711+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-06T23:29:44.711+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="oauth2" /><title>OAuth2 0.5.0</title><content type="html">Нещодавно вийшла версія &lt;i&gt;0.5.0&lt;/i&gt; бібліотеки &lt;a href="https://github.com/intridea/oauth2"&gt;OAuth2&lt;/a&gt; - Ruby-обгортки для протоколу &lt;i&gt;OAuth 2.0&lt;/i&gt;. У порівнянні з попередньою версією, код зазнав значних змін. Зокрема були змінені назви функцій та їх параметрів. І раніше написаний код втратив свою працездатність. У зв'язку з цим я оновив дві статті:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://ruby-ua.blogspot.com/2011/04/oauth-20-ruby-sinatra.html"&gt;Авторизація ВКонтакте використовуючи OAuth 2.0 на прикладі Ruby і Sinatra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ruby-ua.blogspot.com/2011/06/standalone-oauth-20-ruby-mechanize.html"&gt;Авторизація Standalone-додатків використовуючи OAuth 2.0 на прикладі Ruby і Mechanize&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
За цим &lt;a href="https://github.com/mamantoha/vkontakte/commit/1881b85bff40e2930e2cf1e6cb7bcbb1b4eed7ff#diff-0"&gt;посиланням&lt;/a&gt; наочно і зрозуміло проілюстровані зміни у коді при роботі з новою версією &lt;i&gt;OAuth2&lt;/i&gt;.&lt;br /&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-6405657356334938836?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/6405657356334938836/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=6405657356334938836" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6405657356334938836?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/6405657356334938836?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/bMf1aPRqLrU/oauth2-050.html" title="OAuth2 0.5.0" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/08/oauth2-050.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQNRXg7cCp7ImA9WhdbEEo.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-3972698281269236219</id><published>2011-08-05T12:38:00.001+03:00</published><updated>2011-10-08T14:13:14.608+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-08T14:13:14.608+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rubinius" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="rvm" /><title>#rbxday</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-2MUyeaWC8ww/Tju2irV59lI/AAAAAAAAHes/pkpZCHTKZLc/s1600/rubinius_diecut_sticker.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="285" src="http://1.bp.blogspot.com/-2MUyeaWC8ww/Tju2irV59lI/AAAAAAAAHes/pkpZCHTKZLc/s400/rubinius_diecut_sticker.png" width="304" /&gt;&lt;/a&gt;&lt;/div&gt;5 серпня 2011 команда &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt; проводить масштабне тестування своєї альтернативної реалізація мови програмування &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
Ну ось, ще один привід спробувати в дії &lt;i&gt;Rubinius&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Подробиці тут: &lt;a href="http://rbxday.rubini.us/"&gt;http://rbxday.rubini.us&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Для тестування досить встановити &lt;i&gt;Rubinius&lt;/i&gt; з допомогою &lt;i&gt;RVM&lt;i&gt;&lt;/i&gt;&lt;/i&gt; і спробувати запустити ваш код.&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ sudo rvm get head
$ sudo rvm reload
$ sudo rvm install rbx
$ rbx-master --version
rubinius 1.2.5dev (1.8.7 560efecd yyyy-mm-dd JI) [i686-pc-linux-gnu]

&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-3972698281269236219?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/3972698281269236219/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=3972698281269236219" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3972698281269236219?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/3972698281269236219?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/NtaRaz_XryU/rbxday.html" title="#rbxday" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-2MUyeaWC8ww/Tju2irV59lI/AAAAAAAAHes/pkpZCHTKZLc/s72-c/rubinius_diecut_sticker.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/08/rbxday.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYCQn86fCp7ImA9WhdbEEo.&quot;"><id>tag:blogger.com,1999:blog-4152168096498110483.post-876316315716901593</id><published>2011-08-02T10:00:00.001+03:00</published><updated>2011-10-08T14:09:23.114+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-08T14:09:23.114+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="news" /><category scheme="http://www.blogger.com/atom/ns#" term="rvm" /><category scheme="http://www.blogger.com/atom/ns#" term="ruby1.9" /><title>Ruby 1.9.3 preview1</title><content type="html">Вийшла у світ &lt;i&gt;Ruby 1.9.3 preview1&lt;/i&gt;.&lt;br /&gt;
Попередні версії &lt;i&gt;Ruby&lt;/i&gt; були під ліцензією &lt;a href="http://www.gnu.org/licenses/gpl-2.0.html"&gt;GPLv2&lt;/a&gt; та &lt;a href="http://www.ruby-lang.org/en/about/license.txt/"&gt;Ruby&lt;/a&gt;. У цій версії вона замінена ліцензією типу &lt;i&gt;BSD&lt;/i&gt; з &lt;a href="http://en.wikipedia.org/wiki/BSD_licenses#2-clause_license_.28.22Simplified_BSD_License.22_or_.22FreeBSD_License.22.29"&gt;2 пунктів&lt;/a&gt; і &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Для отримання додаткової інформації дивіться &lt;a href="http://www.ruby-lang.org/en/news/2011/08/01/ruby-1-9-3-preview1-has-been-released/"&gt;офіційний анонс&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Спробувати &lt;i&gt;1.9.3&lt;/i&gt; можна вже сьогодні.  З &lt;i&gt;RVM&lt;/i&gt; це просто:&lt;br /&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;rvm get head
rvm reload
rvm install 1.9.3
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4152168096498110483-876316315716901593?l=ruby-ua.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://ruby-ua.blogspot.com/feeds/876316315716901593/comments/default" title="Дописати коментарі" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=4152168096498110483&amp;postID=876316315716901593" title="0 коментарі(в)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/876316315716901593?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4152168096498110483/posts/default/876316315716901593?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ruby-ua/~3/T86RTt8HM0w/ruby-193-preview1.html" title="Ruby 1.9.3 preview1" /><author><name>Anton Maminov</name><uri>https://profiles.google.com/113707018347190717526</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-YHCbjrzjsF4/AAAAAAAAAAI/AAAAAAAAAAA/w97xtx9vaBg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://ruby-ua.blogspot.com/2011/08/ruby-193-preview1.html</feedburner:origLink></entry></feed>

