<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4152168096498110483</id><updated>2026-07-24T09:00:39.832+03:00</updated><category term="ruby"/><category term="news"/><category term="ruby1.9"/><category term="sinatra"/><category term="tips"/><category term="vkontakte"/><category term="linux"/><category term="datamapper"/><category term="tutorial"/><category term="life"/><category term="mechanize"/><category term="internet"/><category term="link"/><category term="e-book"/><category term="rails"/><category term="gui"/><category term="ruby2"/><category term="wx"/><category term="ubuntu"/><category term="haml"/><category term="jruby"/><category term="rack"/><category term="rvm"/><category term="nokogiri"/><category term="oauth2"/><category term="omniauth"/><category term="padrino"/><category term="qtruby"/><category term="regexp"/><category term="apache"/><category term="gem"/><category term="irb"/><category term="rails2"/><category term="rubinius"/><category term="rubyforge"/><category term="translation"/><category term="uaenv"/><category term="warden"/><category term="windows"/><category term="bootstrap"/><category term="bundler"/><category term="d-bus"/><category term="icecast2"/><category term="json"/><category term="magento"/><category term="mpd"/><category term="netbeans"/><category term="screencast"/><category term="slim"/><category term="vim"/><category term="will_paginate"/><category term="ajax"/><category term="android"/><category term="bash"/><category term="benchmark"/><category term="cURL"/><category term="carrierwave"/><category term="csv"/><category term="delayed_job"/><category term="eval"/><category term="facebook"/><category term="funny"/><category term="game"/><category term="google"/><category term="heroku"/><category term="javascript"/><category term="jquery"/><category term="kvm"/><category term="last.fm"/><category term="librmpd"/><category term="merb"/><category term="oauth"/><category term="opal"/><category term="openshift"/><category term="podcast"/><category term="presto"/><category term="redcar"/><category term="ruboto"/><category term="ruby-shout"/><category term="rubyua"/><category term="tk"/><category term="tmux"/><category term="torrent"/><category term="video"/><category term="xml-rpc"/><title type='text'>Записки про Ruby</title><subtitle type='html'>5.times { print &quot;We *love* Ruby -- it&#39;s outrageous!&quot; }</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='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.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'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>200</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7041187220479340026</id><published>2013-10-29T14:27:00.002+02:00</published><updated>2013-10-29T14:33:22.744+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jruby"/><category scheme="http://www.blogger.com/atom/ns#" term="magento"/><category scheme="http://www.blogger.com/atom/ns#" term="rubinius"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><category scheme="http://www.blogger.com/atom/ns#" term="xml-rpc"/><title type='text'>Magento XML-RPC API і Ruby</title><content type='html'>Після написання першої статті &lt;a href=&quot;http://ruby-ua.blogspot.com/2013/10/magento-rest-api-oauth-ruby.html&quot;&gt;Magento REST API і OAuth в Ruby&lt;/a&gt;, захотілося продовжити вивчення можливостей &lt;i&gt;Magento API&lt;/i&gt;.&lt;br /&gt;
Весь сир-бор через те, що можливості &lt;i&gt;REST&lt;/i&gt; в &lt;i&gt;Magento&lt;/i&gt; просто жалюгідні.&lt;br /&gt;
На сьогодні &lt;i&gt;Magento&lt;/i&gt; підтримує всі найбільш поширені способи доступу до API сайтів: &lt;i&gt;REST&lt;/i&gt;, &lt;i&gt;XML-RPC&lt;/i&gt;, &lt;i&gt;SOAP&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Magento SOAP/XML-RPC API&lt;/i&gt; дає вам можливість керувати своїми магазинами електронної комерції, забезпечуючи методи для роботи з ресурсами, такими як клієнти, категорій, продукти і замовлення.&lt;br /&gt;
&lt;br /&gt;
Про &lt;i&gt;SOAP&lt;/i&gt; можна говорити багато і довго.&lt;br /&gt;
Для мене основними мінусами стали складність протоколу і відсутність вбудованої підтримки в &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
Натомість стандарт &lt;i&gt;XML-RPC&lt;/i&gt; зачарував мене своєю надзвичайною простотою.&lt;br /&gt;
В базову поставку &lt;i&gt;Ruby&lt;/i&gt; вже входить бібліотека для роботи з &lt;i&gt;XML-RPC&lt;/i&gt;, відповідно вам не доведеться замислюватися про структуру запитів і обробку відповідей в XML.&lt;br /&gt;
&lt;br /&gt;
Тому саме &lt;i&gt;XML-RPC&lt;/i&gt; в основному і буде присвячена ця стаття.&lt;br /&gt;
Не буду зупинятися на питанні, що таке &lt;i&gt;XML-RPC&lt;/i&gt; і навіщо він потрібен. У мережі багато статей на цю тему.&lt;br /&gt;
&lt;br /&gt;
Просто постараюся коротко показати, яким простим способом можливе створення клієнта до &lt;i&gt;XML-RPC&lt;/i&gt; веб-сервісу на &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;xmlrpc/client&#39;

config = {
  api_user: &#39;user&#39;,
  api_key:  &#39;secret&#39;,
  host:     &#39;example.com&#39;,
  path:     &#39;/api/xmlrpc&#39;,
  port:     80,
}
client = XMLRPC::Client.new(config[:host], config[:path], config[:port])

# If somestuff requires api authentification,
# we should get session token
session = client.call(&#39;login&#39;, config[:api_user], config[:api_key])

parent_id = 1
store_view = 1
client.call(&#39;call&#39;, session, &#39;catalog_category.tree&#39;, [parent_id , store_view])

# If you don&#39;t need the session anymore
client.call(&#39;endSession&#39;, session)
&lt;/pre&gt;&lt;br /&gt;
Все просто: ми підключаємося до сервера, отримуємо ключ сесії і виконуємо запити.&lt;br /&gt;
&lt;br /&gt;
Документацію по всіх запитах &lt;i&gt;Magento API&lt;/i&gt; можна знайти на &lt;a href=&quot;http://www.magentocommerce.com/api/soap/introduction.html&quot;&gt;офіційному сайті&lt;/a&gt;.&lt;br /&gt;
&lt;i&gt;XML-RPC&lt;/i&gt; підтримується тільки першою версією &lt;i&gt;Magento API&lt;/i&gt;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
А тепер найцікавіше! Цей код не працюватиме або працюватиме з перемінних успіхом по різному в усіх трьох основних реалізація мови: &lt;i&gt;MRI Ruby&lt;/i&gt;, &lt;i&gt;Rubinius&lt;/i&gt; і &lt;i&gt;JRuby&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;MRI Ruby&lt;/i&gt; і &lt;i&gt;Rubinius&lt;/i&gt; викликають наступну помилку:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;Wrong size. Was 0, should be 147 (RuntimeError)
&lt;/pre&gt;&lt;br /&gt;
Недовге гуглення приводить до &lt;a href=&quot;http://bugs.ruby-lang.org/issues/8182&quot;&gt;баги&lt;/a&gt;.&lt;br /&gt;
Додамо наступний рядок після ініціалізації клієнта:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;client.http_header_extra = {&quot;accept-encoding&quot; =&gt; &quot;identity&quot;}
&lt;/pre&gt;&lt;br /&gt;
Але і це ще не все. Для деяких запитів &lt;i&gt;XML-RPC&lt;/i&gt; в усіх трьох реалізаціях інколи з&#39;являється помилка:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;wrong/unknown XML-RPC type &#39;nil&#39; (RuntimeError)
&lt;/pre&gt;&lt;br /&gt;
Рішення проблеми було знайдене &lt;a href=&quot;https://github.com/timmatheson/Magento#issues-&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;XMLRPC::Config.module_eval {
  remove_const(:ENABLE_NIL_PARSER)     # so that we&#39;re not warned about reassigning to a constant
  const_set(:ENABLE_NIL_PARSER, true)  # so that we don&#39;t get &quot;RuntimeError: wrong/unknown XML-RPC type &#39;nil&#39;&quot;
}
&lt;/pre&gt;&lt;br /&gt;
На цьому все.</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7041187220479340026/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7041187220479340026' title='2 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7041187220479340026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7041187220479340026'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/10/magento-xml-rpc-api-ruby.html' title='Magento XML-RPC API і Ruby'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-3101723330697202228</id><published>2013-10-20T14:43:00.000+03:00</published><updated>2013-10-20T14:52:19.697+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="magento"/><category scheme="http://www.blogger.com/atom/ns#" term="oauth"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><title type='text'>Magento REST API і OAuth в Ruby</title><content type='html'>У цій статті я хочу поділитися прикладом роботи з &lt;i&gt;Magento REST API&lt;/i&gt; використовуючи &lt;i&gt;Ruby&lt;/i&gt; і &lt;i&gt;oauth&lt;/i&gt; gem. У свій час пошуки подібного ні до чого не привели.&lt;br /&gt;
&lt;br /&gt;
Докладна документація по &lt;i&gt;Magento REST API&lt;/i&gt; &lt;a href=&quot;http://www.magentocommerce.com/api/rest/introduction.html&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Реєстрація та уповноваженому додатку&lt;/h3&gt;&lt;br /&gt;
Отже, приступимо. Першим ділом, потрібно отримати всі потрібні параметри для авторизації. Зокрема ключі &lt;i&gt;consumer_key&lt;/i&gt; і &lt;i&gt;consumer_secret&lt;/i&gt;. І, власне хост(&lt;i&gt;magentohost&lt;/i&gt;), на якому встановлене Magento.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Скажу відразу&lt;/b&gt;, налаштування платформи &lt;i&gt;Magento&lt;/i&gt; для &lt;i&gt;REST API&lt;/i&gt; не розглядається в рамках цієї статті.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;json&#39;
require &#39;oauth&#39;

auth = {
  consumer_key:    &#39;***&#39;,
  consumer_secret: &#39;***&#39;,
}

magentohost = &#39;http://example.com&#39;

@consumer = OAuth::Consumer.new(auth[:consumer_key], auth[:consumer_secret], {
  :site               =&gt; magentohost,
  :request_token_path =&gt; &#39;/oauth/initiate&#39;,
  :access_token_path  =&gt; &#39;/oauth/token&#39;,
  :authorize_path     =&gt; &#39;/admin/oauth_authorize&#39;,
})
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Отримання токена&lt;/h3&gt;&lt;br /&gt;
Для отримання &lt;i&gt;access_token&lt;/i&gt; потрібно перейти за наступним посиланням, увійти(якщо потрібно) і уповноважити додаток.&lt;br /&gt;
Якщо автентифікація пройдена успішно, потрібно ввести отриманий код верифікації. Після цього будуть отримані &lt;i&gt;token&lt;/i&gt; і &lt;i&gt;token_secret&lt;/i&gt;, які використовуватимуться для здійснення HTTP запитів.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;request_token = @consumer.get_request_token

puts request_token.authorize_url

print &#39;Код перевірки: &#39;
verifier = gets.strip

access_token = request_token.get_access_token(:oauth_verifier =&gt; verifier)

auth[:token]        = access_token.token
auth[:token_secret] = access_token.secret
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Запити до API&lt;/h3&gt;&lt;br /&gt;
Ми вже отримали &lt;i&gt;access_token&lt;/i&gt; і можемо виконувати HTTP запити.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;response = access_token.request(:get, &#39;/api/rest/products&#39;)
rsp = JSON.load(response.body)
&lt;/pre&gt;&lt;br /&gt;
Раніше отримані &lt;i&gt;token&lt;/i&gt; і &lt;i&gt;token_secret&lt;/i&gt; можна зберегти для того, щоб виконувати запити без попередньої автентифікації.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;auth[:token]        = &quot;***&quot;
auth[:token_secret] = &quot;***&quot;

access_token = OAuth::AccessToken.new(@consumer, auth[:token], auth[:token_secret])

response = access_token.request(:get, &#39;/api/rest/products&#39;)
rsp = JSON.load(response.body)
&lt;/pre&gt;&lt;br /&gt;
На цьому все.</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/3101723330697202228/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/3101723330697202228' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3101723330697202228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3101723330697202228'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/10/magento-rest-api-oauth-ruby.html' title='Magento REST API і OAuth в Ruby'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2891206421121277325</id><published>2013-09-13T11:44:00.000+03:00</published><updated>2013-09-13T11:44:01.578+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="life"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby2"/><title type='text'>Зі святом, програмісти!</title><content type='html'>П&#39;ятниця 13-го. День програміста. Програмістів з відьмами об&#39;єднує не тільки бубен для магічної тряски, а і святкова п&#39;ятницю для шабашу.&lt;br /&gt;
Зі Святом, товариші!&lt;br /&gt;
&lt;br /&gt;
Наскільки часто буває такий збіг?&lt;br /&gt;
Відповідь під катом.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Вивести наступних 13 Днів Програміста у п&#39;ятницю 13-го.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;date&#39;
puts (Date.new(2013)..Date.new(9999)).lazy.select{|d| d.yday == 256 &amp;&amp; d.day == 13 &amp;&amp; d.friday?}.first(13)
&lt;/pre&gt;&lt;br /&gt;
&lt;pre class=&quot;brush&quot;&gt;2013-09-13
2019-09-13
2030-09-13
2041-09-13
2047-09-13
2058-09-13
2069-09-13
2075-09-13
2086-09-13
2097-09-13
2109-09-13
2115-09-13
2126-09-13
&lt;/pre&gt;&lt;br /&gt;
Не лінивий читач помітив, що в коді використовується лінивий &lt;i&gt;Enumerator&lt;/i&gt;, який з&#39;явився в &lt;i&gt;Ruby 2.0&lt;/i&gt;.&lt;br /&gt;
Провів простий бенчмарк для визначення порівняльних характеристик продуктивності.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;date&#39;
require &#39;benchmark&#39;

iterations = 100

Benchmark.bm(20) do |bm|
  bm.report(&#39;Enumerator#lazy&#39;) do
    iterations.times do
      (Date.new(2013)..Date.new(9999)).lazy.select{|d| d.yday == 256 &amp;&amp; d.day == 13 &amp;&amp; d.friday?}.first(13)
    end
  end

  bm.report(&#39;Enumerator&#39;) do
    iterations.times do
      (Date.new(2013)..Date.new(9999)).select{|d| d.yday == 256 &amp;&amp; d.day == 13 &amp;&amp; d.friday?}.first(13)
    end
  end
end

&lt;/pre&gt;&lt;br /&gt;
Висновки робіть самі.&lt;br /&gt;
&lt;pre class=&quot;brush&quot;&gt;                           user     system      total        real
Enumerator#lazy        2.240000   0.000000   2.240000 (  2.256149)
Enumerator           163.970000   0.000000 163.970000 (164.479462)
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2891206421121277325/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2891206421121277325' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2891206421121277325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2891206421121277325'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/09/blog-post.html' title='Зі святом, програмісти!'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-3227516735579656688</id><published>2013-07-15T22:59:00.002+03:00</published><updated>2013-07-15T22:59:49.186+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="e-book"/><category scheme="http://www.blogger.com/atom/ns#" term="link"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby2"/><title type='text'>Книга по Ruby 2.0</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;https://github.com/Krugloff&quot; target=&quot;_blank&quot;&gt;Алекcандр Круглов&lt;/a&gt; виклав у вільний доступ книгу &quot;Ruby&quot; по мові програмування Ruby 2.0.&lt;br /&gt;
&lt;br /&gt;
Якщо я не помиляюся, це перша опенсорс книга про Ruby російською мовою.&lt;br /&gt;
&lt;br /&gt;
Текст книги у форматі PDF доступний за &lt;a href=&quot;http://dl.dropbox.com/u/75172405/Ruby.pdf&quot;&gt;наступним посиланням&lt;/a&gt;. Зі змістом можна ознайомитися &lt;a href=&quot;http://bpaste.net/show/114445/&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Книгу можна зібрати з вихідних кодів:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Встановити Ruby.&lt;/li&gt;
&lt;li&gt;Встановити необхідні пакети: &lt;em&gt;gem install redcarpet&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Завантажити &lt;a href=&quot;http://gist.github.com/Krugloff/5491182&quot; target=&quot;_blank&quot;&gt;скрипт&lt;/a&gt; для перетворення Markdown в LaTeX.&lt;/li&gt;
&lt;li&gt;Встановити XeLaTeX.&lt;/li&gt;
&lt;li&gt;Завантажити &lt;a href=&quot;http://gist.github.com/Krugloff/5491168&quot; target=&quot;_blank&quot;&gt;стиль&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Зібрати pdf: &lt;em&gt;xelatex book.tex&lt;/em&gt; (за замовчуванням використовуються шрифти сімейства Liberation).&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; Новина взята з &lt;a href=&quot;http://www.linux.org.ru/news/doc/9364033&quot; target=&quot;_blank&quot;&gt;LOR&lt;/a&gt;.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/3227516735579656688/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/3227516735579656688' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3227516735579656688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3227516735579656688'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/07/ruby-20.html' title='Книга по Ruby 2.0'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-3715272740211223378</id><published>2013-04-30T16:37:00.001+03:00</published><updated>2013-04-30T16:37:51.461+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="last.fm"/><category scheme="http://www.blogger.com/atom/ns#" term="mechanize"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="vkontakte"/><title type='text'>Отримання улюблених аудіозаписів з Last.fm</title><content type='html'>Почитав тут статтю &lt;a href=&quot;http://habrahabr.ru/post/178215/&quot;&gt;Получение любимых аудиозаписей с pandora.com&lt;/a&gt;, подумав і придумав subj.&lt;br /&gt;
Отже, з &lt;i&gt;Last.fm&lt;/i&gt; будемо отримувати список назв пісень і виконавців, потім за допомогою &lt;i&gt;API ВКонтакте&lt;/i&gt; будемо їх скачувати.&lt;br /&gt;
&lt;br /&gt;
Крок 1. Йдем на &lt;i&gt;Last.fm&lt;/i&gt;, і витягуємо список улюблених пісень користувача.&lt;br /&gt;
&lt;br /&gt;
Для тих хто не знає, &lt;i&gt;Last.fm&lt;/i&gt; має &lt;i&gt;API&lt;/i&gt;, що дозволяє будь-якому користувачеві створювати свої власні програми з використанням даних Last.fm. Для роботи з API потрібно отримати &lt;i&gt;API Key&lt;/i&gt; і &lt;i&gt;Secret&lt;/i&gt;. Йдемо на &lt;a href=&quot;http://www.last.fm/api&quot;&gt;http://www.last.fm/api&lt;/a&gt; і створюємо новий аккаунт для некомерційного використання.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/youpy/ruby-lastfm&quot;&gt;ruby-lastfm&lt;/a&gt; - інтерфейс для Web-сервісів Last.fm v2.0.&lt;br /&gt;
Тепер нам потрібно отримати token:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;lastfm = Lastfm.new(lastfm_api_key, lastfm_api_secret)
lastfm_token = lastfm.auth.get_token
&lt;/pre&gt;&lt;br /&gt;
Далі нам пропонують відкрити &lt;i&gt;&#39;http://www.last.fm/api/auth/?api_key=xxxxxxxxxxx&amp;token=xxxxxxxx&#39;&lt;/i&gt; і надати права додатку.&lt;br /&gt;
&lt;br /&gt;
Спробуємо змоделювати цей запит. Але спочатку потрібно авторизуватися на сайті &lt;i&gt;Last.fm&lt;/i&gt; за допомогою імені і паролю. Використовуємо бібліотеку &lt;a href=&quot;https://github.com/sparklemotion/mechanize&quot;&gt;Mechanize&lt;/a&gt;:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;mech = Mechanize.new do |a|
  a.user_agent_alias = &#39;Linux Firefox&#39;
  a.verify_mode = OpenSSL::SSL::VERIFY_NONE
  a.follow_meta_refresh = true
end

login_page = mech.get(&#39;https://last.fm/login&#39;)
login_form = login_page.form_with(action: &#39;/login&#39;)

login_form.username = lastfm_username
login_form.password = lastfm_password

page = login_form.submit

if page.uri.to_s == &#39;http://www.last.fm/home&#39;
  puts &quot;Login successful!&quot;
else
  puts page.uri.to_s
  exit
end
&lt;/pre&gt;&lt;br /&gt;
Якщо авторизація пройшла успішно, надаємо права додатку:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;grantaccess_url = &quot;http://www.last.fm/api/auth/?api_key=#{lastfm_api_key}&amp;token=#{lastfm_token}&quot;
grantaccess_page = mech.get(grantaccess_url)

grantaccess_form = grantaccess_page.form_with(action: &#39;/api/grantaccess&#39;)
grantaccess_form.submit
&lt;/pre&gt;&lt;br /&gt;
Отже, тепер ми можемо витягнути всю цікаву для нас інформацію:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;lastfm.session = lastfm.auth.get_session(:token =&gt; lastfm_token)[&#39;key&#39;]
tracks = lastfm.user.get_loved_tracks(user: lastfm_username)
&lt;/pre&gt;&lt;br /&gt;
Перший крок пройдений! :)&lt;br /&gt;
&lt;br /&gt;
Крок другий. Пошук і скачування записів з &lt;i&gt;vk.com&lt;/i&gt;.&lt;br /&gt;
Авторизуємося ВКонаткте:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;vk = Vkontakte::Client.new(vk_client_id)
vk.login!(vk_email, vk_password, scope = &#39;audio&#39;)
&lt;/pre&gt;&lt;br /&gt;
Використовуємо API функцію пошуку аудіо:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;str = &quot;#{track[&#39;artist&#39;][&#39;name&#39;]} - #{track[&#39;name&#39;]}&quot;
audio = vk.api.audio_search(q: str, sort: 2)[1]
&lt;/pre&gt;&lt;br /&gt;
Вона повертає найпопулярніший результат пошуку рядка &lt;i&gt;str&lt;/i&gt; (серед аудіозаписів).&lt;br /&gt;
&lt;br /&gt;
Тепер ми знаємо &lt;i&gt;url&lt;/i&gt; для скачування. Завантажити можна за допомогою стандартної функції.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;path = &quot;#{downloaded_folder}/&quot; + &quot;#{audio[&#39;artist&#39;]} - #{audio[&#39;title&#39;]}.mp3&quot;
File.open(path, &#39;wb&#39;) do |saved_file|
  open(audio[&#39;url&#39;], &#39;rb&#39;) do |read_file|
    saved_file.write(read_file.read)
  end
end
&lt;/pre&gt;&lt;br /&gt;
В результаті вийшов ось такий скрипт:&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/mamantoha/5488722&quot;&gt;https://gist.github.com/mamantoha/5488722&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Як з ним працювати:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Скрипт вимагає встановленого Ruby і гемів &lt;a href=&quot;https://github.com/sparklemotion/mechanize&quot;&gt;mechanize&lt;/a&gt;, &lt;a href=&quot;https://github.com/youpy/ruby-lastfm&quot;&gt;ruby-lastfm&lt;/a&gt;, &lt;a href=&quot;https://github.com/mamantoha/vkontakte&quot;&gt;vkontakte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Потрібно отримати ключі для &lt;i&gt;Last.fm&lt;/i&gt;(&lt;i&gt;lastfm_api_key&lt;/i&gt;, &lt;i&gt;lastfm_secret&lt;/i&gt;) і &lt;i&gt;ВКонтакте&lt;/i&gt;(&lt;i&gt;vk_client_id&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;&lt;i&gt;downloaded_folder&lt;/i&gt; - директорія, куди буде зберігатися скачана музика&lt;/li&gt;
&lt;li&gt;&lt;i&gt;lastfm_username&lt;/i&gt; і &lt;i&gt;lastfm_password&lt;/i&gt; - ваш логін і пароль на &lt;i&gt;Last.fm&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;vk_email&lt;/i&gt; і &lt;i&gt;vk_password&lt;/i&gt; - ваш логін і пароль на &lt;i&gt;Vk.com&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Відповідні параметри прописати в тілі скрипта.</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/3715272740211223378/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/3715272740211223378' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3715272740211223378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/3715272740211223378'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/04/lastfm.html' title='Отримання улюблених аудіозаписів з Last.fm'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-288671320678402588</id><published>2013-02-24T11:27:00.000+02:00</published><updated>2013-02-24T11:27:59.924+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="news"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby2"/><title type='text'>Реліз Ruby 2.0.0-p0</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWVSwh4a4L9z___l6L2N1Rub79LqlN18d7iukLJyiVwoYZfaUE54HvxvxCDTmDOtPuXjpYeUjhAga2ergaza-YdRgVVara5WigsbPKE3xPWAiTS8J5wwk9D5A2lRm81O-qmOhhj-nC6dY/s1600/ruby.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWVSwh4a4L9z___l6L2N1Rub79LqlN18d7iukLJyiVwoYZfaUE54HvxvxCDTmDOtPuXjpYeUjhAga2ergaza-YdRgVVara5WigsbPKE3xPWAiTS8J5wwk9D5A2lRm81O-qmOhhj-nC6dY/s200/ruby.jpg&quot; width=&quot;199&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
У нас свято!&lt;br /&gt;
Точно за оперативним планом 24 лютого &lt;a href=&quot;http://www.ruby-lang.org/en/news/2013/02/24/ruby-2-0-0-p0-is-released/&quot; target=&quot;_blank&quot;&gt;анонсовано&lt;/a&gt; реліз Ruby 2.0.0-p0. Були включені нові можливості, які роблять розробку на Ruby ще приємнішою.&lt;br /&gt;
&lt;br /&gt;
Анонсовані можливості:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Уточнення (Refinements) &lt;sup&gt;[1]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Іменовані аргументи в методах &lt;sup&gt;[2]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Enumerator#lazy&lt;/i&gt; &lt;sup&gt;[3]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Module#prepend&lt;/i&gt; &lt;sup&gt;[4]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;#to_h&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;%i&lt;/i&gt; для масивів символів&lt;/li&gt;
&lt;li&gt;Двигун регулярних виразів змінений на Onigmo &lt;sup&gt;[5]&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Підтримка DTrace &lt;sup&gt;[6]&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Всі програми, які написані на ruby 1.9 будуть працювати на ruby 2.0, якщо в них не буде особливої магії.&lt;br /&gt;
&lt;br /&gt;
Несумісності:&lt;br /&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Кодування за замовчуванням для скриптів Ruby стало UTF-8.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;String#lines&lt;/i&gt;, &lt;i&gt;#chars&lt;/i&gt;, &lt;i&gt;#codepoints&lt;/i&gt; і &lt;i&gt;#bytes&lt;/i&gt; тепер повертають &lt;i&gt;Array&lt;/i&gt; замість &lt;i&gt;Enumerator&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;Iconv був остаточно видалений. Він був оголошений застарілим ще для Ruby 1.9.x. Тепер Ви повинні використовувати можливості M17N, такі як &lt;i&gt;String#encode.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;[1] &lt;a href=&quot;http://timelessrepo.com/refinements-in-ruby&quot;&gt;Refinements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[2] &lt;a href=&quot;http://bugs.ruby-lang.org/issues/5474&quot;&gt;Keyword arguments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[3] &lt;a href=&quot;http://railsware.com/blog/2012/03/13/ruby-2-0-enumerablelazy/&quot;&gt;Enumerator#lazy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[4] &lt;a href=&quot;http://bugs.ruby-lang.org/issues/1102&quot;&gt;Module#prepend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[5] &lt;a href=&quot;https://github.com/k-takata/Onigmo&quot;&gt;Onigmo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[6] &lt;a href=&quot;http://tenderlovemaking.com/2011/06/29/i-want-dtrace-probes-in-ruby.html&quot;&gt;DTrace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
В 2.0.0 preview1 був включений &lt;a href=&quot;http://bugs.ruby-lang.org/issues/7158&quot;&gt;чарівних патч&lt;/a&gt;, який прискорює роботу Rails в 2.2 рази&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/288671320678402588/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/288671320678402588' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/288671320678402588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/288671320678402588'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/02/ruby-200-p0.html' title='Реліз Ruby 2.0.0-p0'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWVSwh4a4L9z___l6L2N1Rub79LqlN18d7iukLJyiVwoYZfaUE54HvxvxCDTmDOtPuXjpYeUjhAga2ergaza-YdRgVVara5WigsbPKE3xPWAiTS8J5wwk9D5A2lRm81O-qmOhhj-nC6dY/s72-c/ruby.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-8710830698849914269</id><published>2013-01-19T18:10:00.000+02:00</published><updated>2013-01-20T23:22:45.792+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Використовуємо life:) API за допомогою Ruby</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuAbcUCXM1v4D-23_2VOIUl5tPZVHQX6yn4SSl2jNFmJAkFhiNSL6rWRGkVQw5LvQTCZ4nvTi2sxgdOep7TPSQlUByR03MCCeKgxB30NtGiDKtOAIgw7l4KbNBD90qd5FRMijsNhSjWko/s1600/rubyloveslife.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;132&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuAbcUCXM1v4D-23_2VOIUl5tPZVHQX6yn4SSl2jNFmJAkFhiNSL6rWRGkVQw5LvQTCZ4nvTi2sxgdOep7TPSQlUByR03MCCeKgxB30NtGiDKtOAIgw7l4KbNBD90qd5FRMijsNhSjWko/s400/rubyloveslife.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
У цій статті я хочу розповісти Вам, як на мові Ruby налагодити взаємодію з life:) API. Для тих хто не в курсі, life:) — український GSM-оператор мобільного зв&#39;язку.&lt;br /&gt;
&lt;br /&gt;
Все почалося тоді, що коли у офіційному твітері life:) з&#39;явилося &lt;a href=&quot;https://twitter.com/lifeua/status/278785580941324288&quot;&gt;повідомлення&lt;/a&gt; про додаток &quot;Мій life:)&quot; для Android. Мені відразу стало цікаво — а як вони отримують інформацію, якщо не через свій сайт системи самообслуговування для індивідуальних абонентів &lt;a href=&quot;https://my.life.com.ua&quot;&gt;Мій life:)&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Добрі люди підказали мені, як декомпілювати файл apk. Але це не тема цієї статті.&lt;br /&gt;
&lt;br /&gt;
Трохи покопавшись в горах Java-коду, мені вдалося зрозуміти за яким принципом здійснюється робота з сервісом life:). Варто зауважити, що офіційно нікого API у life:) немає. Тому все нижче написане використовуйте &lt;i&gt;на свій страх і ризик&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Результатом цієї роботи стала бібліотека для Ruby - &lt;i&gt;life-api&lt;/i&gt;, яка реалізує деякі методи API. Ви можете знайти її на &lt;a href=&quot;https://github.com/mamantoha/life-api&quot;&gt;Github&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Отже, що нам знадобиться щоб виконувати запити?&lt;br /&gt;
Розглянемо все по порядку.&lt;br /&gt;
&lt;br /&gt;
Всі запити, включаючи авторизацію виконується до адреси &lt;a href=&quot;https://api.life.com.ua/mobile&quot;&gt;https://api.life.com.ua/mobile&lt;/a&gt;.&lt;br /&gt;
З кожним запитом передається постійний ключ API &lt;i&gt;accessKeyCode&lt;/i&gt;. А &lt;i&gt;applicationKey&lt;/i&gt; використовується, як секретний ключ для підписання запиту. Про це трохи пізніше.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
А зараз просто визначимо ці три змінні:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;@access_key_code = &#39;7&#39;
@application_key = &#39;E6j_$4UnR_)0b&#39;
@api_url         = &#39;https://api.life.com.ua/mobile/&#39;
&lt;/pre&gt;&lt;br /&gt;
Для отримання токена потрібно передати методу &lt;i&gt;signIn&lt;/i&gt; наступні параметри:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;i&gt;msisdn&lt;/i&gt; - номер телефону, що почитається з &quot;380&quot;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;superPassword&lt;/i&gt; - ваш суперпароль&lt;/li&gt;
&lt;/ul&gt;Пам&#39;ятаєте, параметр &lt;i&gt;accessKeyCode&lt;/i&gt; є обов&#39;язковим для всіх методів.&lt;br /&gt;
&lt;br /&gt;
Також обов&#39;язково необхідно підписати запит. Значення параметра &lt;b&gt;signature&lt;/b&gt; рівне криптографічній хеш-функції HMAC(SHA1) від конкатенації наступних рядків:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;назва методу&lt;/li&gt;
&lt;li&gt;пар &lt;i&gt;&quot;parameter_name=parameter_value&quot;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;рядок &quot;&amp;signature=&quot;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Наступний метод повертатиме валідний url для запиту. У якості параметрів він отримує назву функції і хеш параметрів з парами &lt;i&gt;&quot;ключ =&gt; значення&quot;&lt;/i&gt;.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;openssl&#39;
require &#39;base64&#39;

def create_signed_url(method, params)
  query = create_param(params)
  str = method + &#39;?&#39; + query + &#39;&amp;signature=&#39;

  digest = OpenSSL::Digest::Digest.new(&#39;sha1&#39;)
  hash = OpenSSL::HMAC.digest(digest, @application_key, str)

  hash = Base64.encode64(hash).chomp

  str += hash

  return @api_url + str
end
&lt;/pre&gt;&lt;br /&gt;
Зверніть увагу на метод &lt;i&gt;create_param&lt;/i&gt;, який перетворює хеш параметрів у текстовий рядок, придатний для використання в рядку запиту url.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;def create_param(params)
  params.map do |key, value|
    &quot;#{key}=#{value}&quot;
  end.sort * &#39;&amp;&#39;
end
&lt;/pre&gt;&lt;br /&gt;
Наступний метод власне і виконує запит за допомогою вбудованої у Ruby бібліотеки &#39;net/https&#39;:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;net/https&#39;

def request(method, params)
  params.merge!(accessKeyCode: @access_key_code)
  url = create_signed_url(method, params)

  uri = URI(url)
  request = Net::HTTP::Get.new(uri.request_uri)

  response = Net::HTTP.start(uri.host, uri.port, :use_ssl =&gt; true) do |http|
    http.request(request)
  end

end
&lt;/pre&gt;&lt;br /&gt;
Виконуємо запит для отримання токена:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;request(&#39;signId&#39;, { msisdn: &#39;380631234567&#39;, superPassword: &#39;1234&#39;})
&lt;/pre&gt;&lt;br /&gt;
Приклад запиту:&lt;br /&gt;
&lt;a href=&quot;https://api.life.com.ua/mobile/signIn?accessKeyCode=7&amp;msisdn=380631234567&amp;superPassword=1234&amp;signature=KmLILbck40UJbCvlZMDOTtC2Z6o%3D&quot;&gt;https://api.life.com.ua/mobile/signIn?accessKeyCode=7&amp;msisdn=380631234567&amp;superPassword=1234&amp;signature=KmLILbck40UJbCvlZMDOTtC2Z6o%3D&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Приклад успішної відповіді від сервера у форматі XML:&lt;br /&gt;
&lt;pre class=&quot;brush: xml&quot;&gt;&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;response method=&quot;signIn&quot;&gt;&lt;responsecode&gt;0&lt;/responseCode&gt;&lt;token&gt;ghkIU9j&lt;/token&gt;&lt;subid&gt;u4i7Qlh&lt;/subId&gt;&lt;/response&gt;
&lt;/pre&gt;&lt;br /&gt;
Після отримання токена взаємодія з іншими методами life:) API проводиться шляхом створення HTTP-запиту (GET) до адреси API-сервісу &lt;a href=&quot;https://api.life.com.ua/mobile&quot;&gt;https://api.life.com.ua/mobile&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
На цьому все. Сподіваюся, я досить докладно описав кожний свій крок. Буду радий відповісти на Ваші запитання, якщо такі виникнуть.&lt;br /&gt;
&lt;br /&gt;
Дякую за увагу.</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/8710830698849914269/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/8710830698849914269' title='2 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8710830698849914269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8710830698849914269'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/01/life-api-ruby.html' title='Використовуємо life:) API за допомогою Ruby'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuAbcUCXM1v4D-23_2VOIUl5tPZVHQX6yn4SSl2jNFmJAkFhiNSL6rWRGkVQw5LvQTCZ4nvTi2sxgdOep7TPSQlUByR03MCCeKgxB30NtGiDKtOAIgw7l4KbNBD90qd5FRMijsNhSjWko/s72-c/rubyloveslife.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-8433238393641954983</id><published>2013-01-08T11:41:00.001+02:00</published><updated>2013-01-08T11:48:14.144+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="kvm"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="windows"/><title type='text'>Встановлення Windows XP на віртуальну машину KVM</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Процедури установки і налаштування хост-сервера не розглядається в рамках у цієї статті.&lt;br /&gt;
&lt;br /&gt;
Що дано:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Хост-система Ubuntu Server 12.04 LTS&lt;/li&gt;
&lt;li&gt;KVM&lt;/li&gt;
&lt;li&gt;Гостьова система Windows XP&lt;/li&gt;
&lt;/ul&gt;
Під час інсталяції &lt;i&gt;Windows XP&lt;/i&gt; на віртуальну машину &lt;i&gt;KVM&lt;/i&gt; стикнувся з дуже низьким дисковим I/O. Метод спроб і помилок бажаний результат був досягнутий.&lt;br /&gt;
&lt;br /&gt;
Створення образу гостьової машини розміром 20 гігабайт у форматі &lt;i&gt;qcow2&lt;/i&gt;. Серед підтримуваних форматів &lt;i&gt;QEMU&lt;/i&gt;, цей — найбільш універсальний.&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;$ qemu-img create -f qcow2 -o preallocation=metadata winxp.qcow2 20G
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;i&gt;Virtio&lt;/i&gt; — це такі спеціальні драйвера, які безпосередньо прокидають фізичне залізо у віртуалку, без емуляції його. Власне це поввино зменшувати навантаження на хост-машину.&lt;br /&gt;
&lt;br /&gt;
У &lt;i&gt;Windows XP&lt;/i&gt;, як відомо, немає драйверів &lt;i&gt;Virtio&lt;/i&gt; і при установці виникає помилка через відсутність доступу до жорсткого диску.&lt;br /&gt;
&lt;br /&gt;
Для установки драйверів можете використати мій образ дискети &lt;a href=&quot;https://docs.google.com/open?id=0B4P_mkC26xqHSDk3XzI1eEJjWUU&quot;&gt;Virtio Disk Floppy&lt;/a&gt;.&lt;br /&gt;
Або створити його власноруч (чи оновити драйвери на дискеті) за допомогою найсвіжіших &lt;a href=&quot;https://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/&quot;&gt;Virtio Windows Drivers&lt;/a&gt;:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;$ dd bs=512 count=2880 if=/dev/zero of=viostor-0.1-49-floppy.img
$ mkfs.msdos viostor-0.1-49-floppy.img
$ mkdir /mnt/floppy
$ sudo mount -o loop viostor-0.1-49-floppy.img /mnt/floppy
$ mkdir /mnt/iso
$ sudo mount -o loop virtio-win-0.1-49.iso /mnt/iso
&lt;/code&gt;&lt;/pre&gt;
і скопіювати відповідні файли viostor з ISO на дискету, використовуючи мій образ в якості орієнтира.&lt;br /&gt;
Для довідки:&lt;br /&gt;
&lt;i&gt;wxp&lt;/i&gt; — Windows XP&lt;br /&gt;
&lt;i&gt;wnet&lt;/i&gt; — Windows Server 2003&lt;br /&gt;
&lt;br /&gt;
Далі переходимо до інсталяції віртуальної машини:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;$ sudo virt-install -n winxp -r 1024 --disk path=winxp.qcow2,format=qcow2,bus=virtio,cache=&#39;writeback&#39; --disk path=viostor-0.1-30-floppy.img,device=floppy -c winxp.iso --video=vmvga --accelerate --os-variant=winxp -v --vnc -w bridge:virbr0
&lt;/code&gt;&lt;/pre&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;i&gt;-n winxp&lt;/i&gt; — ім&#39;я віртуальної машини;&lt;br /&gt;
&lt;i&gt;-r 1024&lt;/i&gt; — обсяг оперативної пам&#39;яті(в мегабайтаз) для неї;&lt;br /&gt;
&lt;i&gt;--disk path=winxp.qcow2,format=qcow2,bus=virtio,cache=&#39;writeback&#39;&lt;/i&gt; — шлях до файлу, який буде використовуватися в якості віртуального жорсткого диску для гостьової ОС. Зверніть увагу на опції &lt;b&gt;bus=virtio,cache=&#39;writeback&#39;&lt;/b&gt;;&lt;br /&gt;
&lt;i&gt;--disk path=viostor-0.1-30-floppy.img,device=floppy&lt;/i&gt; — образ дискети з драйверами, що підключається як віртуальний floppy;&lt;br /&gt;
&lt;i&gt;-c winxp.iso&lt;/i&gt; — образ CD гостьової ОС, що підключається як віртуальний cdrom&lt;br /&gt;
&lt;i&gt;--video=vmvga&lt;/i&gt; — вказуємо модель відео-карти (&lt;a href=&quot;http://packages.vmware.com/tools/esx/latest/windows/index.html&quot;&gt;Vmware Windows Tools ISO&lt;/a&gt;);&lt;br /&gt;
&lt;i&gt;--accelerate --os-variant=winxp -v&lt;/i&gt; — прискорюємо, оптимізуємо ВМ для конкретної гостьової ОС і задіюємо апаратні можливості віртуалізації;&lt;br /&gt;
&lt;i&gt;--vnc&lt;/i&gt; — встановлюємо віртуальну консоль і експортуємо її як vnc-сервер;&lt;br /&gt;
&lt;i&gt;-w bridge:virbr0&lt;/i&gt; — вказуємо bridge-пристрій для приєднання до нього віртуальної мережевої карти.&lt;br /&gt;
&lt;br /&gt;
На початку інсталяції&lt;i&gt; Windows XP&lt;/i&gt; натисніть клавішу F6, коли буде запропоновано вказати додаткові драйвери SCSI і натисніть &quot;s&quot; при появі запиту на системному диску. У графічній частині установки XP ви також повинні дати згоду на установку непідписаних драйверів для установки.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDxTWzgXAj_ufJGkMrULFqlt_Cc-irGJLhG47qOlr3jcoL1PzY6W3LhRMo1zhmWL_zRYSO8C733PA4afwJp74cICAegaveVzvBn0sLLNXJrOHFuRGGO6AZZP5IA5GMaG49MehLgtVq-E0/s1600/winxpkvm.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDxTWzgXAj_ufJGkMrULFqlt_Cc-irGJLhG47qOlr3jcoL1PzY6W3LhRMo1zhmWL_zRYSO8C733PA4afwJp74cICAegaveVzvBn0sLLNXJrOHFuRGGO6AZZP5IA5GMaG49MehLgtVq-E0/s400/winxpkvm.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX11vpy2DdKZ38ElBkJJ_aml2craPhjBuniscTPKHiWc4wG18t8iWVYuckm_mxZIgjxVfcYpNRT0yF9MtG3vHHQ7qJ6Mn2idZHzL9AupWt-BXMsPeGqcGVpXJYpPt_zFBmDLRLCb9ZcUU/s1600/winxpkvm1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;299&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX11vpy2DdKZ38ElBkJJ_aml2craPhjBuniscTPKHiWc4wG18t8iWVYuckm_mxZIgjxVfcYpNRT0yF9MtG3vHHQ7qJ6Mn2idZHzL9AupWt-BXMsPeGqcGVpXJYpPt_zFBmDLRLCb9ZcUU/s400/winxpkvm1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCByTtllqYIUU4kZ1En0cce4iFc3NCqJ16OAKNxwgunZq9IdyOjtb1ONaVdYBgYhJEVVl9CWrwfKc0IjJU-Mchil073dpdz6-EZ-pxfygxI-2_R7zKb1dEiOh6VqKbT2n-e3kXkSy5VQc/s1600/winxpkvm2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCByTtllqYIUU4kZ1En0cce4iFc3NCqJ16OAKNxwgunZq9IdyOjtb1ONaVdYBgYhJEVVl9CWrwfKc0IjJU-Mchil073dpdz6-EZ-pxfygxI-2_R7zKb1dEiOh6VqKbT2n-e3kXkSy5VQc/s400/winxpkvm2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/8433238393641954983/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/8433238393641954983' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8433238393641954983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8433238393641954983'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2013/01/windows-xp-kvm.html' title='Встановлення Windows XP на віртуальну машину KVM'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDxTWzgXAj_ufJGkMrULFqlt_Cc-irGJLhG47qOlr3jcoL1PzY6W3LhRMo1zhmWL_zRYSO8C733PA4afwJp74cICAegaveVzvBn0sLLNXJrOHFuRGGO6AZZP5IA5GMaG49MehLgtVq-E0/s72-c/winxpkvm.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-4829059724279764259</id><published>2012-12-31T10:52:00.000+02:00</published><updated>2012-12-31T10:52:17.103+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="news"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Ретроспектива 2012</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSiwsE4EC9jKDIN1Tve-gBrkF-X7WqbJudhsxNgo38cuenkfIxT5FBzLjM1cDBtFYNZY6yY0x1iiPyNSyDIWaGBOty0nmy8nNVSBDKIXTPa6WRZxRkaATohsRu4dHJFyOWCcuP9hrhoDo/s1600/rubyxmas1.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSiwsE4EC9jKDIN1Tve-gBrkF-X7WqbJudhsxNgo38cuenkfIxT5FBzLjM1cDBtFYNZY6yY0x1iiPyNSyDIWaGBOty0nmy8nNVSBDKIXTPa6WRZxRkaATohsRu4dHJFyOWCcuP9hrhoDo/s1600/rubyxmas1.png&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
2012 рік добігає кінця. І за хорошою традицією в останньому записі я згадую найбільш значущі події в світі Ruby, що відбулися у цьому році.&lt;br /&gt;
&lt;br /&gt;
Цього року формат статті зазнав деяких змін. Події розбиті по місяцях.&lt;br /&gt;
&lt;br /&gt;
Січень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Випуск &lt;a href=&quot;http://kidsruby.com/&quot;&gt;KidsRuby&lt;/a&gt; 1.0, редактора &lt;i&gt;Ruby&lt;/i&gt; розробленого в освітніх цілях для  дітей дошкільного й молодшого шкільного віку (але не менш корисного для дорослих). Він включає в себе навчальні посібники та графічну систему в стилі мови програмування &lt;i&gt;Logo&lt;/i&gt; для більш наочного типу навчання.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Лютий&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.phusion.nl/2012/02/21/ruby-enterprise-edition-1-8-7-2012-02-released-end-of-life-imminent/&quot;&gt;Припинення розробки Ruby Enterprise Edition&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.jetbrains.com/ruby/2012/02/rubymine-4-is-here-to-make-you-feel-the-productivity/&quot;&gt;Випуск RubyMine 4.0&lt;/a&gt;, популярного середовища розробки для &lt;i&gt;Ruby&lt;/i&gt; і &lt;i&gt;Rails&lt;/i&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
Березень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/larskanis/fxruby&quot;&gt;FXRuby&lt;/a&gt; - Ruby bindings для FOX (крос-платформної бібліотеки з відкритим вихідним кодом для побудови графічного інтерфейсу) повернувся з довгого періоду застою.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Юкіхіро Мацумото (Yukihiro Matsumoto), автору мови програмування &lt;i&gt;Ruby&lt;/i&gt;, &lt;a href=&quot;https://www.fsf.org/news/2011-free-software-awards-announced&quot; target=&quot;_blank&quot;&gt;присуджена&lt;/a&gt; премія &quot;&lt;a href=&quot;http://www.fsf.org/awards&quot; target=&quot;_blank&quot;&gt;Free Software Awards 2011&lt;/a&gt;&quot; номінації, що вручається за просування і розвиток вільного ПЗ.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Ruby&lt;/i&gt; став стандартом &lt;i&gt;ISO&lt;/i&gt;.&lt;br /&gt;
Після чотирьох років розробки, 31 березня цього року за результатами голосування &lt;i&gt;Ruby&lt;/i&gt; версії 1.8 був прийнятий як стандарт &lt;i&gt;ISO/IEC 30170&lt;/i&gt;. Будемо сподіватися, що наступну версію стандарту підготують швидше.&lt;/li&gt;
&lt;/ul&gt;
Квітень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mruby/mruby&quot; target=&quot;_blank&quot;&gt;mruby&lt;/a&gt; - полегшена реалізації мови &lt;i&gt;Ruby&lt;/i&gt;, виконана за ISO стандартом для виконання різних середовищах. Може були як виконана інтерпретатором так і бути скомпільованою і виконаною віртуальною машиною,&amp;nbsp; відповідно до його модульної конструкції.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mobiruby.org/&quot; target=&quot;_blank&quot;&gt;MobiRuby&lt;/a&gt; - інструментарій для створеня &lt;i&gt;IOS&lt;/i&gt; додатків за допомогою мови &lt;i&gt;Ruby&lt;/i&gt;. В майбутньому планується підтримка &lt;i&gt;Android&lt;/i&gt;. &lt;/li&gt;
&lt;/ul&gt;
Травень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;i&gt;Компанія Red Hat&lt;/i&gt; запустила нову хмарну платформу &lt;a href=&quot;https://openshift.redhat.com/&quot; target=&quot;_blank&quot;&gt;OpenShift&lt;/a&gt; з підтримкою &lt;i&gt;Java&lt;/i&gt;, &lt;i&gt;Ruby&lt;/i&gt;, &lt;i&gt;Node&lt;/i&gt;, &lt;i&gt;Python&lt;/i&gt;, &lt;i&gt;PHP&lt;/i&gt; і &lt;i&gt;Perl&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;Два ключових розробника команди &lt;i&gt;JRuby&lt;/i&gt;(Thomas Enebo і Charles Nutter) &lt;a href=&quot;http://www.rubyinside.com/jruby-redhat-5856.html&quot; target=&quot;_blank&quot;&gt;переходять&lt;/a&gt; на роботу в &lt;i&gt;Red Hat&lt;/i&gt;.&lt;/li&gt;
&lt;li&gt;Перший попередній &lt;a href=&quot;http://jruby.org/2012/05/21/jruby-1-7-0-preview1&quot; target=&quot;_blank&quot;&gt;реліз&lt;/a&gt; &lt;i&gt;JRuby 1.7&lt;/i&gt;. Цікавий тим, що це перший реліз з підтримкою&amp;nbsp; &lt;i&gt;InvokeDynamic&lt;/i&gt; - рішення, що дозволяє взаємодіяти з динамічними мовами практично без втрати продуктивності.&lt;/li&gt;
&lt;li&gt;Реліз &lt;a href=&quot;http://www.rubymotion.com/&quot; target=&quot;_blank&quot;&gt;RubyMotion&lt;/a&gt; - набір інструментів для &lt;i&gt;IOS,&lt;/i&gt; який дозволяє швидко розробляти і тестувати власні програми для &lt;i&gt;iPhone&lt;/i&gt; або &lt;i&gt;iPad&lt;/i&gt;, за допомогою &lt;i&gt;Ruby&lt;/i&gt;.&lt;/li&gt;
&lt;/ul&gt;
Червень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;div&gt;
Вийшла ювілейна версія 1.0 бібліотеки &lt;a href=&quot;https://github.com/ai/r18n&quot; target=&quot;_blank&quot;&gt;R18n&lt;/a&gt;, яка дозволяє додати в додаток на Rails/Ruby підтримку декількох мов (i18n).&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sublimetext.com/blog/articles/sublime-text-2-0-released&quot; target=&quot;_blank&quot;&gt;Реліз Sublime Text 2.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
Вересень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://www.codecademy.com/ru/tracks/ruby&quot; target=&quot;_blank&quot;&gt;Курс по Ruby на Codecademy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Жовтень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://jruby.org/2012/10/22/jruby-1-7-0.html&quot; target=&quot;_blank&quot;&gt;Реліз&lt;/a&gt; JRuby 1.7&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46258&quot; target=&quot;_blank&quot;&gt;Оголошено&lt;/a&gt; &#39;Feature Freeze&#39; для Ruby 2.0&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.engineyard.com/2012/rvm-1-16/&quot; target=&quot;_blank&quot;&gt;Резіл&lt;/a&gt; RVM 1.16 з можливістю встановлення бінарних версій Ruby&lt;/li&gt;
&lt;/ul&gt;
Листопад&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;div&gt;
&lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46348&quot; target=&quot;_blank&quot;&gt;Анонсований&lt;/a&gt; Ruby 2.0.0 preview1&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.phusion.nl/2012/10/30/phusion-passenger-4-0-supports-jruby-rubinius/#.UJUjzrQX7UI&quot; target=&quot;_blank&quot;&gt;Реліз&lt;/a&gt; Phusion Passenger 4.0 з підтримкою JRuby і Rubinius&lt;/li&gt;
&lt;/ul&gt;
Грудень&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Heroku &lt;a href=&quot;http://blog.heroku.com/archives/2012/12/13/run_jruby_on_heroku_right_now/&quot; target=&quot;_blank&quot;&gt;додали&lt;/a&gt; офіційну підтримку для JRuby&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
2013 рік обіцяє також бути багатим на нові релізи. Зокрема Ruby 2.0 і Rails 4.0.&lt;br /&gt;
&lt;br /&gt;
Щиро вітаю Вас з наступаючим Новим Роком!&lt;br /&gt;
Нехай він принесе нам довгождане щастя, спокій, добробут, палке кохання, міцне здоров&#39;я та здійснення наших самих заповітних мрій!&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/4829059724279764259/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/4829059724279764259' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/4829059724279764259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/4829059724279764259'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/12/2012.html' title='Ретроспектива 2012'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSiwsE4EC9jKDIN1Tve-gBrkF-X7WqbJudhsxNgo38cuenkfIxT5FBzLjM1cDBtFYNZY6yY0x1iiPyNSyDIWaGBOty0nmy8nNVSBDKIXTPa6WRZxRkaATohsRu4dHJFyOWCcuP9hrhoDo/s72-c/rubyxmas1.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7038241751955918817</id><published>2012-12-28T13:54:00.001+02:00</published><updated>2013-01-27T12:23:18.955+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Історія одного тупняку, або як я конвертував DBF в SQLite3</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK1NUZDnZJP0PeAtjkbyl3Rbvup2QbWqHIQtpAP2FFzSJea4V4QNci5JWXxzz_iCoUWASwOq_xm3-t2P_YqlUnoTqq8Q8Ikw0F8hRHiC6YvmjYp-s4fyeF6q3Cr3NC1uYWCXkLBGj4IGA/s1600/10814.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK1NUZDnZJP0PeAtjkbyl3Rbvup2QbWqHIQtpAP2FFzSJea4V4QNci5JWXxzz_iCoUWASwOq_xm3-t2P_YqlUnoTqq8Q8Ikw0F8hRHiC6YvmjYp-s4fyeF6q3Cr3NC1uYWCXkLBGj4IGA/s320/10814.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Нещодавно до мене потрапив файл у форматі &lt;i&gt;dbf&lt;/i&gt; з досить цікавою інформацією. Але сьогодні не про це.&lt;br /&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
Для роботи з цією інформацією, я вирішив імпортувати таблицю &lt;i&gt;DBF&lt;/i&gt; у &lt;i&gt;SQLite3&lt;/i&gt;. Використовувати сторонній софт для такої тривіальної задачки — це не наш варіант. Ми не шукаємо легких шляхів. Напишемо скрипт самі. Писати, звичайно, будемо на &lt;i&gt;Ruby&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;DBF&lt;/i&gt; — застаріваючий формат зберігання даних, який (був?) широко розповсюджений на пострадянському просторі.&lt;/blockquote&gt;
&lt;br /&gt;
Недовгі пошуки навели на бібліотеку &lt;a href=&quot;https://github.com/infused/dbf&quot;&gt;dbf&lt;/a&gt;. Як описує її автор, це невелика швидка бібліотека для читання &lt;i&gt;DBase&lt;/i&gt;, &lt;i&gt;Xbase&lt;/i&gt;, &lt;i&gt;Clipper&lt;/i&gt; і &lt;i&gt;FoxPro&lt;/i&gt; файлів баз даних.&lt;br /&gt;
&lt;br /&gt;
Відкриваємо &lt;i&gt;DBF&lt;/i&gt; файл:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;require &#39;dbf&#39;
dbf_table = DBF::Table.new(dbf_file, nil)
dbf_columns = dbf_table.columns
&lt;/pre&gt;
І відразу отримуємо помилку:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;dbf-2.0.3/lib/dbf/column/base.rb:19:in `initialize&#39;: column name cannot be empty (DBF::Column::NameError)
&lt;/pre&gt;
&lt;br /&gt;
Проблема виникає через те, що при &lt;a href=&quot;https://github.com/infused/dbf/blob/master/lib/dbf/column/base.rb#L15&quot;&gt;ініціалізації&lt;/a&gt; поля, у його назві відсікаються всі не-ASCII символи. А такий порядок речей в моєму випадку недопустимий, оскільки&lt;br /&gt;
імена полів у &lt;i&gt;DBF&lt;/i&gt; таблиці записані кирилицею у кодуванні &lt;i&gt;cp1251&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Тут стане у нагоді &quot;monkey patching&quot;.&lt;br /&gt;
Ініціалізуємо таблицю у кодуванні cp1251 і конверуємо імена полів в utf-8:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;module DBF
  module Column
    class Base
      attr_reader :name, :type, :length, :decimal

      def initialize(name, type, length, decimal, version, encoding = nil)
        @name, @type, @length, @decimal, @version, @encoding = clean(name, encoding), type, length, decimal, version, encoding

        raise LengthError, &quot;field length must be greater than 0&quot; unless length &amp;gt; 0
        raise NameError, &quot;column name cannot be empty&quot; if @name.length == 0
      end

      def clean(value, encoding)
        value.force_encoding(encoding).encode(&#39;utf-8&#39;)
      end

    end
  end
end

dbf_table = DBF::Table.new(dbf_file, nil, &#39;cp1251&#39;)
dbf_columns = dbf_table.columns
&lt;/pre&gt;
&lt;br /&gt;
Не вдаючись в подробиці створення схеми &lt;i&gt;SQLite3&lt;/i&gt; (повний код скрипта Ви знайдете в кінці статті), перейдемо відразу до імпорту. Задачка звичайно зовсім тривіальна і написання рішення займає лічені хвилини.&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;dbf_table.each do |record|
  sqlite_db.execute(&quot;INSERT INTO the_table VALUES (?,?,?,?,?,?)&quot;, record.attributes.values)
end
&lt;/pre&gt;
Тут можна було б піти покурити, попити чаю або кави чи навіть подивитися фільм. Даний процес зайняв досить багато часу.&lt;br /&gt;
Час роботи такого рішення мене не вдовольняв зовсім.&lt;br /&gt;
Бувалі програмісти мабуть відразу зрозуміють де собака зарита. Але цей тупняк поглинув мене на кілька годин.&lt;br /&gt;
Спочатку я грішив на повільність бібліотеки &lt;i&gt;dbf&lt;/i&gt;. Але цей варіант був швидко відкинутий. Каменем спотикання була саме бібліотека &lt;i&gt;SQLite3&lt;/i&gt;.&lt;br /&gt;
Наступну годину я курив, пив пиво і дивився &quot;Ruby Sparks&quot;. Між іншим красивий і милий романтичний фільм, але настирливий продакт-плейсмент Apple вже бісить. Паралельно ґвалтува ґуґл в пошуках рішення. І ось воно зійшло:&lt;br /&gt;
&lt;pre class=&quot;brush:ruby&quot;&gt;sql_db.transaction do |db|
  dbf_table.each do |record|
    db.execute(&quot;INSERT INTO the_table VALUES (?,?,?,?,?,?)&quot;, record.attributes.values)
  end
end
&lt;/pre&gt;
&lt;br /&gt;
Несподівано скрипт, який виконувався годинами, виконався за 10 секунд. Підвищення продуктивності over 9000%. Я отетерів(!) від такого результату.&lt;br /&gt;
&lt;br /&gt;
Мораль цієї історії проста... Комусь здається, що це тривіально, але мені просто хотілось поділитися з кимось цими думками.&lt;br /&gt;
&lt;br /&gt;
Нище ви знайдете повну версію скрипта для конвертування &lt;i&gt;DBF&lt;/i&gt; у &lt;i&gt;SQLite3&lt;/i&gt;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/4397089.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7038241751955918817/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7038241751955918817' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7038241751955918817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7038241751955918817'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/12/dbf-sqlite3.html' title='Історія одного тупняку, або як я конвертував DBF в SQLite3'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK1NUZDnZJP0PeAtjkbyl3Rbvup2QbWqHIQtpAP2FFzSJea4V4QNci5JWXxzz_iCoUWASwOq_xm3-t2P_YqlUnoTqq8Q8Ikw0F8hRHiC6YvmjYp-s4fyeF6q3Cr3NC1uYWCXkLBGj4IGA/s72-c/10814.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-1820694543352948906</id><published>2012-12-27T17:31:00.002+02:00</published><updated>2013-01-27T12:22:30.468+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Робота з файлами eml в Ruby</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN3u6jFb48TUAVLNl48mfANhtutGzMGOnhoqfmVFKDgpcsVsX-7uTt8EwjwmSQeuq2L_QgdXSg238Spfq4la14Wdj5GJhOnOqSiTqggo00-NV4IFZAtGMJzvU3NA3U_R4x8CH4GMiB_ZM/s1600/10821.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN3u6jFb48TUAVLNl48mfANhtutGzMGOnhoqfmVFKDgpcsVsX-7uTt8EwjwmSQeuq2L_QgdXSg238Spfq4la14Wdj5GJhOnOqSiTqggo00-NV4IFZAtGMJzvU3NA3U_R4x8CH4GMiB_ZM/s320/10821.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Сьогодні зіткнувся з проблемою пошуку вкладень серед багатьох файлів з розширенням &lt;i&gt;eml&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Формат &lt;i&gt;eml&lt;/i&gt; використовується багатьма клієнтами електронної пошти, включаючи Microsoft Outlook Express, Windows Mail і Mozilla Thunderbird. Це звичайний текстовий файл у форматі MIME, що містять заголовки повідомлень електронної пошти, а також вміст повідомлення та вкладення.&lt;/blockquote&gt;
&lt;br /&gt;
Відкрити його під Linux не складає труднощів, наприклад, за допомогою поштового клієнта KMail, однак таке рішення мені здалося занадто складним.&lt;br /&gt;
&lt;br /&gt;
Трохи погугливши, виявилося, що бібліотека &lt;a href=&quot;https://github.com/mikel/mail&quot;&gt;email&lt;/a&gt; чудово вміє розбирати такі файли.&lt;br /&gt;
&lt;br /&gt;
В результаті вийшов невеликий скрипт, який вибирає всі файли з розширенням eml у поточній директорії, і відображає в консолі текстовий вміст листа, а прикріплені файли зберігає у відповідних директоріях.&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;require &#39;mail&#39;

Dir.glob(&#39;*.eml&#39;) do |filename|
  mail = Mail.read(filename)

  puts &amp;lt;&amp;lt;EOF
  From:    #{mail.from}
  To:      #{mail.to}
  Subject: #{mail.subject}
  Date:    #{mail.date}

EOF

  charset = mail.text_part.content_type_parameters[&#39;charset&#39;]
  puts mail.text_part.body.decoded.force_encoding(charset).encode(&#39;utf-8&#39;)

  if mail.multipart?
    dir = File.basename(filename, File.extname(filename))
    Dir.mkdir(dir) if !Dir.exists?(dir)

    mail.attachments.each do |attachment|
      file = File.open(dir + &#39;/&#39; + attachment.filename, &#39;wb&#39;) { |f| f.write attachment.body.decoded }
      puts &quot;Saving `#{attachment.filename}`&quot;
    end
  end

  puts &quot;===\n\n&quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/1820694543352948906/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/1820694543352948906' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/1820694543352948906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/1820694543352948906'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/12/eml-ruby.html' title='Робота з файлами eml в Ruby'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN3u6jFb48TUAVLNl48mfANhtutGzMGOnhoqfmVFKDgpcsVsX-7uTt8EwjwmSQeuq2L_QgdXSg238Spfq4la14Wdj5GJhOnOqSiTqggo00-NV4IFZAtGMJzvU3NA3U_R4x8CH4GMiB_ZM/s72-c/10821.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2735240313055639045</id><published>2012-10-29T15:55:00.000+02:00</published><updated>2012-10-29T15:55:31.186+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="link"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Opal — реалізація Ruby на JavaScript</title><content type='html'>&lt;a href=&quot;http://opalrb.org/&quot;&gt;Opal&lt;/a&gt; — реалізація Ruby, написана на мові JavaScript.&lt;br /&gt;
&lt;br /&gt;
Opal включає в себе компілятор (який можна запустити в будь-якому браузері), основну бібліотеку і середовища виконання. У стисненому вигляді основна бібліотека і середовище виконання займають всього-на-всього 10.8kb.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmv9eNEuphBSMEeGwal2NJFO66GzSFlTsqiWdnHog4RqqlyM2C2HOWtt8iwi3te-SMpOImJpwSUCCcxZvQcnCrhyFNDImwaRfM42NQ6q9pteuvaod9blsf5_9c-SVtmJhB95B5g7t2JIw/s1600/opalweb.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;268&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmv9eNEuphBSMEeGwal2NJFO66GzSFlTsqiWdnHog4RqqlyM2C2HOWtt8iwi3te-SMpOImJpwSUCCcxZvQcnCrhyFNDImwaRfM42NQ6q9pteuvaod9blsf5_9c-SVtmJhB95B5g7t2JIw/s400/opalweb.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2735240313055639045/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2735240313055639045' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2735240313055639045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2735240313055639045'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/opal-ruby-javascript.html' title='Opal — реалізація Ruby на JavaScript'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmv9eNEuphBSMEeGwal2NJFO66GzSFlTsqiWdnHog4RqqlyM2C2HOWtt8iwi3te-SMpOImJpwSUCCcxZvQcnCrhyFNDImwaRfM42NQ6q9pteuvaod9blsf5_9c-SVtmJhB95B5g7t2JIw/s72-c/opalweb.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2882693265933079237</id><published>2012-10-26T15:51:00.000+03:00</published><updated>2012-11-06T11:00:35.128+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="news"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby2"/><title type='text'>Оголошено &#39;Feature Freeze&#39; для Ruby 2.0</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgajkmOw6fNLqxSF0hYXBXPJD-b-dIJ3Kup0Gi3Unvs330ANE4BjOEtulpbMv-xkv-6zgMOpvNKIt1EX1romNtjQ0g1NPTxYdFjoHhFbH4pQPhbhTEXvBhAEK3v1kjWRoVATK8cxZyrwDQ/s1600/ruby_yula.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgajkmOw6fNLqxSF0hYXBXPJD-b-dIJ3Kup0Gi3Unvs330ANE4BjOEtulpbMv-xkv-6zgMOpvNKIt1EX1romNtjQ0g1NPTxYdFjoHhFbH4pQPhbhTEXvBhAEK3v1kjWRoVATK8cxZyrwDQ/s1600/ruby_yula.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Точно за розкладом, основна команда Ruby &lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46258&quot;&gt;оголосила&lt;/a&gt; про заморожування коду нових можливостей(&#39;feature freeze&#39;) майбутнього&lt;i&gt; Ruby 2.0&lt;/i&gt;. Це означає, що з цього моменту розробники лише будуть виправляти баги, не додаючи нових фіч в дану версію.&lt;br /&gt;
&lt;br /&gt;
Нижче я збираюся представити переклад статті &quot;&lt;i&gt;Things to Look Forward to in Ruby 2.0&lt;/i&gt;&quot; у якій автор перерахував декілька нових можливостей Ruby 2.0.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Комбінація методів map/select&lt;/h3&gt;
&lt;blockquote&gt;
Ця можливість не ввійшла до Ruby 2.0 (&lt;i&gt;прим. перекладача&lt;/i&gt;).&lt;/blockquote&gt;
Припустимо, ви хочете виконати метод &lt;i&gt;map&lt;/i&gt; для &lt;i&gt;Enumerable&lt;/i&gt; і отримати тільки ті елементи, які відповідають певним критеріям.&lt;br /&gt;
Ви можете зробити це одним із цих двох способів:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;[1,2,3,4].select(&amp;amp;:even?).map {|i| i + 1}
==&amp;gt; [3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;[1,2,3,4].map { |i| i + 1 if i.even? }.compact
==&amp;gt; [3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Ідея полягає в тому, щоб мати один метод, який поєднує в собі ці два. Його ім&#39;я до цих пір не визначене, але &lt;i&gt;filter_map&lt;/i&gt; здається можливим вибором.&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;[1,2,3,4].filter_map { |i| i + 1 if i.even? }
==&amp;gt; [3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Так як я не хочу чекати, я вирішив зробити версію для бідних, але дати їй інше ім&#39;я.&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;module Enumerable
  def map_selected(&amp;amp;block)
    map(&amp;amp;block).compact!
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;[1,2,3,4].map_selected { |i| i + 1 if i.even? }
==&amp;gt; [3, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;a href=&quot;http://bugs.ruby-lang.org/issues/5663&quot;&gt;Ruby feature #5663&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Іменовані аргументи функцій&lt;/h3&gt;
Мені їх не вистачає з тих пір, як я дізнався, що вони є в &lt;i&gt;Smalltalk&lt;/i&gt;. Потім, на мій жах я зрозумів, що вони є в &lt;i&gt;Lisp&lt;/i&gt;, &lt;i&gt;Clojure&lt;/i&gt; і навіть в &lt;i&gt;Python&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Звичайно, ви можете підробити іменовані аргументи за допомогою хешу, але приємніше мати &amp;nbsp;підтримку з коробки:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;def foo_bar(name: &#39;foo&#39;, last_name: &#39;bar&#39;)
  print &quot;#{name} #{last_name}&quot;
end

foo_bar ==&amp;gt; foo bar
foo_bar last_name: &#39;baruco&#39; ==&amp;gt; foo baruco
foo_bar last_name: &#39;baruco&#39;, name:&#39;hello&#39; ==&amp;gt; hello baruco
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;a href=&quot;http://bugs.ruby-lang.org/issues/5474&quot;&gt;Ruby feature #5474&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://ruby-dev.info/posts/44602&quot;&gt;Ruby feature #5454 translation&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Про іменовані аргументи функцій в &lt;i&gt;Ruby 2.0&lt;/i&gt; я раніше &lt;a href=&quot;http://ruby-ua.blogspot.com/2012/01/ruby-20.html&quot;&gt;писав&lt;/a&gt; у цьому блозі.&lt;/blockquote&gt;
&lt;br /&gt;
&lt;h3&gt;
Змінна екземпляру присвоюється об&#39;єкту під час створення&lt;/h3&gt;
Це частий випадок можна буде скоротити на два рядки:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;class FooBar
  def initialize(name, last_name)
    @name = name
    @last_name = last_name
  end

  def to_s
    &quot;#@name #@last_name&quot;
  end
end

print FooBar.new(&#39;foobar&#39;, &#39;rulez&#39;)
=&amp;gt; foobar rulez
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Ось так:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;class FooBar
  def initialize(@name, @last_name)
    #nice isn&#39;t it?
  end

  def to_s
    &quot;#@name #@last_name&quot;
  end
end

print FooBar.new(&#39;foobar&#39;, &#39;rulez&#39;)
=&amp;gt; foobar rulez
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
Я впевнений, що будуть ситуації, коли така поведінка стане в нагоді. Функція йде від &lt;i&gt;CoffeScript&lt;/i&gt;, наскільки я можу судити. Для &lt;i&gt;Ruby 1.8.7&lt;/i&gt; стане у нагоді наступний трюк:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;define_method(:intialize){|@name, @last_name|}
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;a href=&quot;http://bugs.ruby-lang.org/issues/5825&quot;&gt;Ruby feature #5825&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;a href=&quot;http://kresimirbojcic.com/2012/08/23/things-to-look-forward-to-in-ruby-2-dot-0.html&quot;&gt;Оригінал статті&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Не менш цікавою можливістю у новому &lt;i&gt;Ruby&lt;/i&gt; є метод &lt;i&gt;Enumerable#lazy&lt;/i&gt;, про який я &lt;a href=&quot;http://ruby-ua.blogspot.com/2012/03/ruby-20-enumeratorlazy.html&quot;&gt;писав&lt;/a&gt; у цьому блозі.&lt;br /&gt;
Докладніше про &lt;i&gt;Enumerable#lazy&lt;/i&gt;: &lt;a href=&quot;http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/&quot;&gt;англійською&lt;/a&gt; і &lt;a href=&quot;http://habrahabr.ru/post/140362/&quot;&gt;російською&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Про всі зміни які відбулися після &lt;i&gt;1.9.3&lt;/i&gt; ви можете почитати &lt;a href=&quot;http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/NEWS?revision=37126&amp;amp;view=markup&quot;&gt;тут&lt;/a&gt;. Їх небагато, і ваш код, написаний для &lt;i&gt;1.9.3&lt;/i&gt; буде справно працювати і на &lt;i&gt;2.0.0&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2882693265933079237/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2882693265933079237' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2882693265933079237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2882693265933079237'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/feature-freeze-ruby-20.html' title='Оголошено &#39;Feature Freeze&#39; для Ruby 2.0'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgajkmOw6fNLqxSF0hYXBXPJD-b-dIJ3Kup0Gi3Unvs330ANE4BjOEtulpbMv-xkv-6zgMOpvNKIt1EX1romNtjQ0g1NPTxYdFjoHhFbH4pQPhbhTEXvBhAEK3v1kjWRoVATK8cxZyrwDQ/s72-c/ruby_yula.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2092992822988986462</id><published>2012-10-23T22:00:00.004+03:00</published><updated>2012-10-23T22:00:48.447+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="link"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Ruby Bits.Частина 2</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW4x0Wz780gLQaHtBz77c4Op5hhQ6p7VgF8e-m4g52cm2uaT49gunVYIOjT7Eoztti5awySj36QtsWAh3iEruSNlpuWRCQzs6K41JalzJKew7VnOFk5AJcTlLhZUdn4sezAHhzGviV7LQ/s1600/Ruby_Bits_2_Banner.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW4x0Wz780gLQaHtBz77c4Op5hhQ6p7VgF8e-m4g52cm2uaT49gunVYIOjT7Eoztti5awySj36QtsWAh3iEruSNlpuWRCQzs6K41JalzJKew7VnOFk5AJcTlLhZUdn4sezAHhzGviV7LQ/s1600/Ruby_Bits_2_Banner.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Для багатьох не секрет, що Ruby — це потужна мова програмування. Але чи використовуєте ви її в повній мірі?&lt;br /&gt;
У другій частині курсу&amp;nbsp;від Code School ви зможете познайомитися з найбільш корисними можливостями метапрограмування у Ruby.&lt;br /&gt;
&lt;br /&gt;
У цьому курсі ви дізнаєтеся про:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Використання Procs і лямбда для зберігання і виконання блоків коду&lt;/li&gt;
&lt;li&gt;Різні способи для передачі блоків у методи&lt;/li&gt;
&lt;li&gt;Як використовувати необов&#39;язкові блоки&lt;/li&gt;
&lt;li&gt;Динамічне визначення та виклик методів&lt;/li&gt;
&lt;li&gt;Відповідь на неіснуючі методи&lt;/li&gt;
&lt;li&gt;Управління контекстом, в якому виконується код&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
В кінці курсу, ви зможете використовувати вивчені можливості для побудови Domain Specific Languages(DSL).&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &lt;a href=&quot;http://www.codeschool.com/courses/ruby-bits-part-2&quot; target=&quot;_blank&quot;&gt;Перейти до курсу&lt;/a&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2092992822988986462/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2092992822988986462' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2092992822988986462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2092992822988986462'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/ruby-bits-2.html' title='Ruby Bits.Частина 2'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW4x0Wz780gLQaHtBz77c4Op5hhQ6p7VgF8e-m4g52cm2uaT49gunVYIOjT7Eoztti5awySj36QtsWAh3iEruSNlpuWRCQzs6K41JalzJKew7VnOFk5AJcTlLhZUdn4sezAHhzGviV7LQ/s72-c/Ruby_Bits_2_Banner.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7528590996452199140</id><published>2012-10-23T12:26:00.000+03:00</published><updated>2012-10-23T12:26:19.900+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jruby"/><category scheme="http://www.blogger.com/atom/ns#" term="news"/><title type='text'>Реліз JRuby 1.7.0</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBaD6Jjaun6ik0QRi0EGg8xx38O6e2Ku4N-VBxL1FmadGEPy820HwAlULHFh-O56bTB0c6l6bsnDoh8V8geyrPXXfd5nb37jiBoNzw1wkV9ONPzlXoJcrq8HhxiAJNNP7YOB6pTDzcV_8/s1600/jruby-logo-sm.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBaD6Jjaun6ik0QRi0EGg8xx38O6e2Ku4N-VBxL1FmadGEPy820HwAlULHFh-O56bTB0c6l6bsnDoh8V8geyrPXXfd5nb37jiBoNzw1wkV9ONPzlXoJcrq8HhxiAJNNP7YOB6pTDzcV_8/s1600/jruby-logo-sm.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Спільноті JRuby рада &lt;a href=&quot;http://jruby.org/2012/10/22/jruby-1-7-0.html&quot; target=&quot;_blank&quot;&gt;оголосити&lt;/a&gt; про випуск JRuby 1.7.0, починаючи з якої заявлена офіційна підтримка Ruby 1.9.x.&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Домашня сторінка: &lt;a href=&quot;http://www.jruby.org/&quot;&gt;http://www.jruby.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Завантажити: &lt;a href=&quot;http://www.jruby.org/download&quot;&gt;http://www.jruby.org/download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Після півтора років розробки вийшов мажорний реліз відкритої багатоплатформної реалізації інтерпретатора мови програмування Ruby, написаної цілком на Java.&lt;br /&gt;
&lt;br /&gt;
В JRuby 1.7 &amp;nbsp;проведений величезний обсяг робіт, десятки учасників, і покращення у кожній підсистемі. І тепер за замовчуванням JRuby працює у режимі сумісності Ruby 1.9.3. Втім, не означає, що реалізація не буде більше вдосконалюватися. Це означає лише, що в майбутньому будуть вирішуватися проблеми з якими зіткнуться користувачі. На даний момент, розробники планують випускати нові версії 1.7.x кожні 2-3 тижні.&lt;br /&gt;
&lt;br /&gt;
1.7 є першим стабільним JRuby з підтримкою нової можливості JVM - &lt;em&gt;invokedynamic&lt;/em&gt;. Ви можете включити використання &lt;em&gt;invokedynamic&lt;/em&gt; для Java 7, але вона по замовчуванню відключена, через проблему в JVM. На Java 8 , вона включений за умовчанням: &lt;a href=&quot;http://wiki.jruby.org/PerformanceTuning&quot;&gt;http://wiki.jruby.org/PerformanceTuning&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Що нового:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Режим сумісності з 1.9.3 тепер використовується по замовчуванню(1.8 необхідний для підтримки 1.8.7)&lt;/li&gt;
&lt;li&gt;Стандартна бібліотека оновлена до 1.9.3p286&lt;/li&gt;
&lt;li&gt;Багато виправлень сумісності з 1.9.x&lt;/li&gt;
&lt;li&gt;Підтримка invokedynamic&lt;/li&gt;
&lt;li&gt;Численні покращення продуктивності&lt;/li&gt;
&lt;li&gt;Припинена підтримка Java 5(тепер обов&#39;язкова Java 6+).&lt;/li&gt;
&lt;li&gt;Вирішені всі відомі проблеми з кодуваннями у 1.9&lt;/li&gt;
&lt;li&gt;Покращення і виправлення для Java інтеграції&lt;/li&gt;
&lt;li&gt;Краща підтримка для Solaris, ARM Linux.&lt;/li&gt;
&lt;li&gt;Оновлення до Rubygems 1.8.24&lt;/li&gt;
&lt;li&gt;Оновлення до Rake 0.9.2.2&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7528590996452199140/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7528590996452199140' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7528590996452199140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7528590996452199140'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/jruby-170.html' title='Реліз JRuby 1.7.0'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBaD6Jjaun6ik0QRi0EGg8xx38O6e2Ku4N-VBxL1FmadGEPy820HwAlULHFh-O56bTB0c6l6bsnDoh8V8geyrPXXfd5nb37jiBoNzw1wkV9ONPzlXoJcrq8HhxiAJNNP7YOB6pTDzcV_8/s72-c/jruby-logo-sm.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7721519763040790473</id><published>2012-10-13T16:20:00.000+03:00</published><updated>2012-10-26T11:58:52.437+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby1.9"/><title type='text'>Ruby 1.9.3-p286</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;Новий реліз включає в себе виправлення кількох критичних помилок, і не містить нових можливостей.&lt;br /&gt;
Докладніше на &lt;a href=&quot;http://www.ruby-lang.org/en/news/2012/10/12/ruby-1-9-3-p286-is-released/&quot;&gt;офіційній сторінці&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Для Linux:&lt;br /&gt;
&lt;pre style=&quot;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%;&quot;&gt;&lt;code&gt;$ rvm get head

$ rvm upgrade ruby
Are you sure you wish to upgrade from ruby-1.9.3-p194 to ruby-1.9.3-p286? (Y/n):
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
Для Windows доступний для завантаження &lt;a href=&quot;http://rubyinstaller.org/downloads&quot;&gt;RubyInstaller 1.9.3-p286&lt;/a&gt;.&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7721519763040790473/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7721519763040790473' title='2 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7721519763040790473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7721519763040790473'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/ruby-193-p286.html' title='Ruby 1.9.3-p286'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-119856248488306328</id><published>2012-10-09T14:17:00.000+03:00</published><updated>2012-10-11T11:57:55.881+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="link"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Курс по Ruby на Codecademy</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ7hVGDwiryCzMSDPFquvFlOwvrofesF-Kmhi_WmNAPAwkRQETS4RXlqks1sWc2mhWot9Z6zWsFIn1Q1dXYO6mrIiYe5xzosMquYW6wzl6gbQdrNw2hjnGcUBZT1RNXdf3APOUPQnO7SA/s1600/F-DdQbpJKSM.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ7hVGDwiryCzMSDPFquvFlOwvrofesF-Kmhi_WmNAPAwkRQETS4RXlqks1sWc2mhWot9Z6zWsFIn1Q1dXYO6mrIiYe5xzosMquYW6wzl6gbQdrNw2hjnGcUBZT1RNXdf3APOUPQnO7SA/s1600/F-DdQbpJKSM.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
На навчальному порталі &lt;a href=&quot;http://www.codecademy.com/ru/tracks/ruby&quot;&gt;Codecademy&lt;/a&gt; з&#39;явився курс з мови програмування Ruby.&lt;br /&gt;
&lt;br /&gt;
Курс інтерактивний, інтерпретатор працює прямо в браузері. Складається з більше сотні вправ, розбитих на 5 блоків. Частина вправ кожного блоку ввідні, а частина - приклад реалізації найпростіших додатків.&lt;br /&gt;
&lt;br /&gt;
Курс можна рекомендувати, тим, хто тільки починає вивчення Ruby.&lt;br /&gt;
&lt;br /&gt;
Курс на англійській, але на простій і зрозумілій.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/119856248488306328/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/119856248488306328' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/119856248488306328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/119856248488306328'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/10/ruby-codecademy.html' title='Курс по Ruby на Codecademy'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ7hVGDwiryCzMSDPFquvFlOwvrofesF-Kmhi_WmNAPAwkRQETS4RXlqks1sWc2mhWot9Z6zWsFIn1Q1dXYO6mrIiYe5xzosMquYW6wzl6gbQdrNw2hjnGcUBZT1RNXdf3APOUPQnO7SA/s72-c/F-DdQbpJKSM.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7306972378934325048</id><published>2012-08-15T12:33:00.001+03:00</published><updated>2012-08-15T12:33:30.212+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bootstrap"/><category scheme="http://www.blogger.com/atom/ns#" term="sinatra"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Стилізація sinatra-flash для Bootstrap</title><content type='html'>Про гем &lt;a href=&quot;https://github.com/SFEley/sinatra-flash&quot;&gt;sinatra-flash&lt;/a&gt;, я писав у статті &lt;a href=&quot;http://ruby-ua.blogspot.com/2011/07/flash-sinatra.html&quot;&gt;Flash-повідомлення і Sinatra&lt;/a&gt; &lt;br /&gt;
Задачею є створити замість стандартного &lt;i&gt;styled_flash&lt;/i&gt;, методу-помінчника для Sinatra, який відображатиме &lt;a href=&quot;http://twitter.github.com/bootstrap/components.html#alerts&quot;&gt;попередження&lt;/a&gt; стилізовані під &lt;i&gt;Bootstrap&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaITC85XvEqUPQoUWlH4_W7XpRmnU_Y0CTVsge2Ny6PHrXb17iyq2z4XscaayNM2WJkCymRAsdGK4YY5zEpBYzoWFJZC4xp7VfFSX7w72YqayQOTJBFv-ogfcVp39hY-zThP_CdytpEEY/s1600/alert.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;60&quot; width=&quot;377&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaITC85XvEqUPQoUWlH4_W7XpRmnU_Y0CTVsge2Ny6PHrXb17iyq2z4XscaayNM2WJkCymRAsdGK4YY5zEpBYzoWFJZC4xp7VfFSX7w72YqayQOTJBFv-ogfcVp39hY-zThP_CdytpEEY/s400/alert.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3358074.js?file=style.rb&quot;&gt;&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7306972378934325048/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7306972378934325048' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7306972378934325048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7306972378934325048'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/08/sinatra-flash-bootstrap.html' title='Стилізація sinatra-flash для Bootstrap'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaITC85XvEqUPQoUWlH4_W7XpRmnU_Y0CTVsge2Ny6PHrXb17iyq2z4XscaayNM2WJkCymRAsdGK4YY5zEpBYzoWFJZC4xp7VfFSX7w72YqayQOTJBFv-ogfcVp39hY-zThP_CdytpEEY/s72-c/alert.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-6510024561894218587</id><published>2012-08-14T00:14:00.001+03:00</published><updated>2012-08-14T00:14:20.999+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Як зробити локальий веб-сервер загальнодоступним</title><content type='html'>Сьогодні відкрив для себе чудовий сервіс, який дозволяє швидко і просто зробити локальний веб-сервер загальнодоступним в Інтернеті.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Зустрічайте ProxyLocal&lt;/h3&gt;Це програмне забезпечення складається з клієнтської і серверної частин. Серверна частина працює на сервері &lt;a href=&quot;http://proxylocal.com/&quot;&gt;proxylocal.com&lt;/a&gt;, і ви можете використання його ресурси абсолютно безкоштовно. Клієнт написаний на мові &lt;i&gt;Ruby&lt;/i&gt; і поширюється як &lt;i&gt;gem&lt;/i&gt;, його вихідний код відкритий і доступний на &lt;a href=&quot;https://github.com/proxylocal/proxylocal-gem&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Інсталяція&lt;/h3&gt;&lt;i&gt;ProxyLocal&lt;/i&gt; - це утиліта командного рядка.&lt;br /&gt;
&lt;br /&gt;
Відкрийте термінал і наберіть:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;$ gem install proxylocal
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Використання&lt;/h3&gt;Припустимо, ваш локальний веб-сервер запущений на порту 9292. Щоб зробити його загальнодоступним виконайте в терміналі:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;$ proxylocal 9292
Local server on port 9292 is now publicly available via:
http://o18f.t.proxylocal.com/
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Тепер ваш локальний сервер на порту 9292 доступний через:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;http://o18f.t.proxylocal.com/
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Також ви можете вказати бажане ім&#39;я, яке ви хочете використовувати, наприклад:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;$ proxylocal 9292 --host testhost
Local server on port 9292 is now publicly available via:
http://testhost.t.proxylocal.com/
&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/6510024561894218587/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/6510024561894218587' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/6510024561894218587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/6510024561894218587'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/08/blog-post.html' title='Як зробити локальий веб-сервер загальнодоступним'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2798952473222144833</id><published>2012-07-03T17:19:00.000+03:00</published><updated>2012-07-03T17:19:09.862+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="vkontakte"/><title type='text'>ВКонтакте → Авторизація додатків з Ruby і Net::HTTP</title><content type='html'>На днях виникло бажання переписати код своєї &lt;a href=&quot;https://github.com/mamantoha/vkontakte&quot;&gt;бібліотеки&lt;/a&gt; для для авторизації ВКонтакте і здійснення запитів до API, використовуючи тільки стандартні модулі Ruby.&lt;br /&gt;
&lt;br /&gt;
Для того, щоб прикинутися справжнім браузером, просто завантажувати потрібні сторінки недостатньо. Як мінімум, потрібно коректно обробляти куки і редіректи. Для цього у &lt;a href=&quot;http://ruby-ua.blogspot.com/2011/06/standalone-oauth-20-ruby-mechanize.html&quot;&gt;попередній статі&lt;/a&gt; я використовував чудову бібліотеку &lt;i&gt;Mechanize&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Спочатку встановимо необхідні параметри.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=1_params.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
Детально про параметри звернення можна прочитати в &lt;a href=&quot;http://vk.com/developers.php?id=-1_37230422&amp;s=1&quot;&gt;документації&lt;/a&gt;.&lt;br /&gt;
&lt;i&gt;client_id&lt;/i&gt; - ідентифікатор вашого додатку.&lt;br /&gt;
Тут слід зазначити, що ми будемо використовувати параметр &lt;i&gt;display&lt;/i&gt; із значенням &lt;i&gt;wap&lt;/i&gt;, так в цьому варіанті сторінки практично відсутній JavaScript.&lt;br /&gt;
&lt;i&gt;scope&lt;/i&gt; являє собою &lt;a href=&quot;http://vk.com/developers.php?oid=-1&amp;p=%D0%9F%D1%80%D0%B0%D0%B2%D0%B0_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9&quot;&gt;список прав&lt;/a&gt;, до яких ми хочемо отримати доступ.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Звертаємося до сторінки авторизації&lt;/h3&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi38wQwvv6H9E6YDZ-dUTpzkluzZeYGe4Gu2XxCMZWf70hYDf-52GEHINZSTEo2zieNDzM-xI3se3xIac9EJh7Q_MXzu6jjB7iOzNuP8InyZHh87q6nnA5mT8Q2jhG1sVPH3Zg8dxSup0Y/s1600/1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;154&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi38wQwvv6H9E6YDZ-dUTpzkluzZeYGe4Gu2XxCMZWf70hYDf-52GEHINZSTEo2zieNDzM-xI3se3xIac9EJh7Q_MXzu6jjB7iOzNuP8InyZHh87q6nnA5mT8Q2jhG1sVPH3Zg8dxSup0Y/s400/1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/3039674.js?file=2_auth_page.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Парсимо відповідь&lt;/h3&gt;&lt;br /&gt;
Подивимося на код сторінки авторизації. Найбільше нас буде цікавити наступна частина:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=3_login_form.html&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Для подальшої відправки форми необхідно розпарсити всі input&#39;и (и тому числі і приховані), а також URL, на який сабмітиться форма.&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=4_parse_form.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Авторизуємось&lt;/h3&gt;&lt;br /&gt;
Підставляємо в параметри запиту електронну пошту та пароль користувача і відправляємо форму:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=5_authorization.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Отримуємо куку&lt;/h3&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=6_get_cookie.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Встановлюємо куку&lt;/h3&gt;&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/3039674.js?file=7_set_cookie.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Отримуємо код&lt;/h3&gt;&lt;br /&gt;
Наступним етапом, якщо користувач цього ще не робив, треба дати додатку ті права, які ми запитували в параметрі &lt;i&gt;scope&lt;/i&gt;. Для цього нам буде запропонована сторінка з формою.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl5KY84MnW1dRI4T1hrKRoXSDfVox3nk79Io-yujIWDFqCmT5lAUgug9Tp2RiqJl07DfpIH54BYGYEDXaAsku7ywULqFRu7x6zWLyyCYaTxjDXjYsBXRQ5Q0vbTSvc4WcPvof_6e7PaXw/s1600/2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;219&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl5KY84MnW1dRI4T1hrKRoXSDfVox3nk79Io-yujIWDFqCmT5lAUgug9Tp2RiqJl07DfpIH54BYGYEDXaAsku7ywULqFRu7x6zWLyyCYaTxjDXjYsBXRQ5Q0vbTSvc4WcPvof_6e7PaXw/s400/2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
В результаті отримуємо відповідь наступного вигляду:&lt;br /&gt;
&lt;i&gt;http://oauth.vk.com/blank.html#code=xxxxxxxxxxxxxxxxxx&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkXwTfD_x2eBI3evJqlgJQxIxvhnTY1YJcKqeXAjxoRdixjqajGSnQhHuS0koHTVRLS0m9aUXE5XncwSUVw2mJnKXCo676zYC0l_8wIBUVgv83z6WdYW1nGU0BSWULaUpIyISODt20m48/s1600/3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;71&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkXwTfD_x2eBI3evJqlgJQxIxvhnTY1YJcKqeXAjxoRdixjqajGSnQhHuS0koHTVRLS0m9aUXE5XncwSUVw2mJnKXCo676zYC0l_8wIBUVgv83z6WdYW1nGU0BSWULaUpIyISODt20m48/s400/3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/3039674.js?file=8_get_code.rb&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Даний метод авторизації не є офіційним і може змінитися.</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2798952473222144833/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2798952473222144833' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2798952473222144833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2798952473222144833'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/07/ruby-nethttp.html' title='ВКонтакте → Авторизація додатків з Ruby і Net::HTTP'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi38wQwvv6H9E6YDZ-dUTpzkluzZeYGe4Gu2XxCMZWf70hYDf-52GEHINZSTEo2zieNDzM-xI3se3xIac9EJh7Q_MXzu6jjB7iOzNuP8InyZHh87q6nnA5mT8Q2jhG1sVPH3Zg8dxSup0Y/s72-c/1.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-8403190251090557750</id><published>2012-05-22T23:21:00.001+03:00</published><updated>2012-05-22T23:26:51.467+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="carrierwave"/><category scheme="http://www.blogger.com/atom/ns#" term="datamapper"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="sinatra"/><title type='text'>CarrierWave з DataMapper у Sinatra</title><content type='html'>У вільний час займаюся розробкою веб-додатку на &lt;i&gt;Sinatra&lt;/i&gt; з використанням &lt;i&gt;DataMapper&lt;/i&gt;. І ось задався питанням завантаження аватарів на сервер та їх після-обробкою.&lt;br /&gt;
&lt;br /&gt;
Переглянувши доступні &lt;a href=&quot;https://www.ruby-toolbox.com/categories/rails_file_uploads&quot;&gt;інструменти&lt;/a&gt; для забезпечення цієї функціональності, вибір впав на бібліотеку &lt;a href=&quot;https://github.com/jnicklas/carrierwave&quot;&gt;CarrierWave&lt;/a&gt;, яка на відміну від більшості інших не зав&#39;язана на &lt;i&gt;Rails&lt;/i&gt;/&lt;i&gt;ActiveRecord&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;CarrierWave&lt;/i&gt; описує себе, як &quot;першокласне рішення для завантаження файлів для &lt;i&gt;Rails&lt;/i&gt;, &lt;i&gt;Sinatra&lt;/i&gt; та інших веб-додатків на основі &lt;i&gt;Rack&lt;/i&gt;&quot;. Проект був започаткований у серпні 2008 року, і перший випуск відбувся в березні 2009 року. Перша його назва була &lt;i&gt;Merb::Upload&lt;/i&gt; і він був без підтримки &lt;i&gt;Rails&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Той факт, що &lt;i&gt;CarrierWave&lt;/i&gt; почав своє життя в якості плагіна для &lt;i&gt;Merb&lt;/i&gt; може пояснити його модульність, гнучкість і розширюваність.&lt;br /&gt;
&lt;br /&gt;
Завдяки &lt;a href=&quot;https://github.com/fog/fog&quot;&gt;fog&lt;/a&gt;, він має підтримку &lt;i&gt;Amazon S3&lt;/i&gt;, &lt;i&gt;Rackspace Cloud Files&lt;/i&gt; і &lt;i&gt;Google Storage for Developers&lt;/i&gt;. Він також підтримує звичайне зберігання файлів і &lt;i&gt;GridFS&lt;/i&gt; в &lt;i&gt;MongoDB&lt;/i&gt;.&lt;br /&gt;
Має підтримку незліченної кількості ORM: &lt;i&gt;ActiveRecord&lt;/i&gt;, &lt;i&gt;Mongoid&lt;/i&gt;, &lt;i&gt;DataMapper&lt;/i&gt;, &lt;i&gt;Sequel&lt;/i&gt;, &lt;i&gt;MongoMapper&lt;/i&gt;, &lt;i&gt;CouchDB&lt;/i&gt;.&lt;br /&gt;
Обробка зображення доступна засобами &lt;i&gt;RMagick&lt;/i&gt;, &lt;i&gt;ImageScience&lt;/i&gt; або &lt;i&gt;MiniMagick&lt;/i&gt;.&lt;br /&gt;
Сама по собі ця бібліотека дуже добре документована, і якщо раптом когось цікавлять деталі, то читайте &lt;a href=&quot;https://github.com/jnicklas/carrierwave/wiki&quot;&gt;wiki&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
У цій статті для прикладу ми напишемо просту фотогалерею.&lt;br /&gt;
Наступні gem`и повинні бути встановлені:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;sinatra&lt;/li&gt;
&lt;li&gt;datamapper&lt;/li&gt;
&lt;li&gt;dm-sqlite-adapter&lt;/li&gt;
&lt;li&gt;slim&lt;/li&gt;
&lt;li&gt;&lt;i&gt;carrierwave&lt;/i&gt; - для завантаження зображень&lt;/li&gt;
&lt;li&gt;&lt;i&gt;carrierwave-datamapper&lt;/i&gt; - для зв&#39;язку &lt;i&gt;DataMapper&lt;/i&gt; і &lt;i&gt;CarrierWave&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;rmagick&lt;/i&gt; - для створення мініатюр зображень(в Ubuntu потрібно встановити пакет &lt;i&gt;libmagick++-dev&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Налаштування підключення до бази даних і створення таблиці для зберігання інформації про зображення у галереї.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;DataMapper.setup(:default, &amp;quot;sqlite3://#{Dir.pwd}/photogallery.sqlite3&amp;quot;)

class Image
  include DataMapper::Resource

  property :id, Serial
  property :title, Text
end

DataMapper.auto_upgrade!
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Налаштування &lt;i&gt;CarrierWave&lt;/i&gt;. Для того щоб він правильно працював потрібно також встановити gem &lt;i&gt;carrierwave-datamapper&lt;/i&gt; і &lt;i&gt;rmagick&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Клас завантажувача успадкований від &lt;i&gt;CarrierWave::Uploader::Base&lt;/i&gt;:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;class ImageUploader &amp;lt; CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  storage :file

  process :resize_to_fit =&amp;gt; [800, 800]

  version :thumb do
    process :resize_to_fill =&amp;gt; [200, 200]
  end

  def store_dir
    &#39;uploads&#39;
  end

  def extension_white_list
    %w(bmp gif jpg jpeg png)
  end
end
&lt;/code&gt;&lt;/pre&gt;Для того, щоб змінити розташування завантажених файлів необхідно просто перевизначити метод &lt;i&gt;store_dir&lt;/i&gt;. А також створити каталог &lt;i&gt;&#39;public/uploads&#39;&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Метод &lt;i&gt;extension_white_list&lt;/i&gt; визначає, які розширення файлів дозволені для завантаження.&lt;br /&gt;
&lt;br /&gt;
При завантаженні зображення буде масштабуватися не більше ніж 800 на 800 пікселів. А його мініатюрна версія &lt;i&gt;:thumb&lt;/i&gt; буде масштабована і обрізана рівно 200 на 200 пікселів.&lt;br /&gt;
&lt;br /&gt;
Завантажувач може бути використаний наступним чином:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;uploader = ImageUploader.new
uploader.store!(my_file)                              # розмір: 1024x768

uploader.url # =&amp;gt; &#39;/url/to/my_file.png&#39;               # розмір: 800x600
uploader.thumb.url # =&amp;gt; &#39;/url/to/thumb_my_file.png&#39;   # розмір: 200x200
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
З&#39;єднання моделі &lt;i&gt;DataMapper&lt;/i&gt; із завантажувачем &lt;i&gt;CarrierWave&lt;/i&gt; за допомогою методу &lt;i&gt;mount_uploader&lt;/i&gt;:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;class Image
  include DataMapper::Resource

  property :id, Serial
  property :title, Text

  mount_uploader :image, ImageUploader
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Маршрути:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;get &#39;/&#39; do
  @images = Image.all

  slim :index
end

post &#39;/&#39; do
  image = Image.new(:title =&amp;gt; params[:title])
  image.image = params[:image]
  image.save

  redirect &#39;/&#39;
end
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Шаблон &lt;i&gt;Slim&lt;/i&gt;. Мініатюри усіх завантажених зображень і форма для додавання нових:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;__END__

@@ index
- @images.each do &amp;#124;i&amp;#124;
  p
    = i.title
  a href=&amp;quot;#{i.image.url}&amp;quot;
    img src=&amp;quot;#{i.image.thumb.url}&amp;quot;

form action=&#39;/&#39; method=&#39;post&#39; enctype=&#39;multipart/form-data&#39;
  fieldset
    p
      label for=&#39;title&#39; Title:
      input name=&#39;title&#39; type=&#39;text&#39;
    p
      label for=&#39;image&#39; Image:
      input name=&#39;image&#39; type=&#39;file&#39;
    p
      input type=&#39;submit&#39; value=&#39;Save&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju9SUorMW7ud-mNToXC9Kx5I-Fnduq1DeW9yrkyyDw4GFnVbCu_SuJCOrpqm-ZO9H5rjfh4575XyeIbxw4zBRoCLD7saJoQDEZe6l4KW4QqmDmrebF_L1ai-DEVIeGKM7I37tBsGcIoDc/s1600/wave.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; width=&quot;365&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju9SUorMW7ud-mNToXC9Kx5I-Fnduq1DeW9yrkyyDw4GFnVbCu_SuJCOrpqm-ZO9H5rjfh4575XyeIbxw4zBRoCLD7saJoQDEZe6l4KW4QqmDmrebF_L1ai-DEVIeGKM7I37tBsGcIoDc/s400/wave.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Весь код можна подивитись на &lt;a href=&quot;https://gist.github.com/2771347&quot;&gt;GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/8403190251090557750/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/8403190251090557750' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8403190251090557750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8403190251090557750'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/05/carrierwave-datamapper-sinatra.html' title='CarrierWave з DataMapper у Sinatra'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju9SUorMW7ud-mNToXC9Kx5I-Fnduq1DeW9yrkyyDw4GFnVbCu_SuJCOrpqm-ZO9H5rjfh4575XyeIbxw4zBRoCLD7saJoQDEZe6l4KW4QqmDmrebF_L1ai-DEVIeGKM7I37tBsGcIoDc/s72-c/wave.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-9191403392171868963</id><published>2012-05-18T16:52:00.001+03:00</published><updated>2012-05-19T19:38:54.821+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bundler"/><category scheme="http://www.blogger.com/atom/ns#" term="openshift"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="sinatra"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><title type='text'>Розгортання додатку Sinatra на OpenShift</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlvNoIbbMz2Bp34Bv6UH5ItHBzV2tcBl3UyqvVHwj9zfVsWdT_KUd4VD3Mlza0wkkDev78pomC7ezZhlnJKiYrle-oBCtZ0zemY1wlydsM2ZobhnRVqbBfg-8A51quVu9aGyIesyoAYn4/s1600/OpenShift-Logo.png&quot; imageanchor=&quot;1&quot; style=&quot;clear:right; float:right; margin-left:1em; margin-bottom:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;288&quot; width=&quot;269&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlvNoIbbMz2Bp34Bv6UH5ItHBzV2tcBl3UyqvVHwj9zfVsWdT_KUd4VD3Mlza0wkkDev78pomC7ezZhlnJKiYrle-oBCtZ0zemY1wlydsM2ZobhnRVqbBfg-8A51quVu9aGyIesyoAYn4/s400/OpenShift-Logo.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;i&gt;Red Hat OpenShift&lt;/i&gt; - це нова, вільно-масштабована &quot;платформа як послуга(Platform as a service, PaaS) для розробки веб-додатків. На даний момент підтримує &lt;i&gt;Java&lt;/i&gt;, &lt;i&gt;Ruby&lt;/i&gt;, &lt;i&gt;Node&lt;/i&gt;, &lt;i&gt;Python&lt;/i&gt;, &lt;i&gt;PHP&lt;/i&gt; і &lt;i&gt;Perl&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Картриджі - це компоненти додатку &lt;i&gt;OpenShift&lt;/i&gt;, які включають в себе бази даних(&lt;i&gt;MySQL&lt;/i&gt;, &lt;i&gt;PostgreSQL&lt;/i&gt;, &lt;i&gt;MongoDB&lt;/i&gt;) та інші утиліти(&lt;i&gt;Cron&lt;/i&gt;, &lt;i&gt;phpMyAdmin&lt;/i&gt;, &lt;i&gt;RockMongo&lt;/i&gt;, &lt;i&gt;OpenShift Metrics&lt;/i&gt;). Додавання картриджа у додаток забезпечує бажану функціональність.&lt;br /&gt;
&lt;br /&gt;
Для початку необхідно зареєструватися на сайті &lt;a href=&quot;https://openshift.redhat.com&quot;&gt;https://openshift.redhat.com&lt;/a&gt; і створити новий додаток.&lt;br /&gt;
Вибрати тип додатку(в нашому випадку це &lt;i&gt;Ruby 1.8.7&lt;/i&gt;). Вказати ім&#39;я додатку і простір імен.&lt;br /&gt;
Вітання, тепер ви у хмарах!&lt;br /&gt;
Новий додаток буде доступний за &lt;i&gt;URL&lt;/i&gt; виду:&lt;br /&gt;
&lt;a href=&quot;#&quot;&gt;http://&lt;ім&#39;я додатку&gt;-&lt;простір імен&gt;.rhcloud.com&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;OpenShift&lt;/i&gt; використовує розподілену система керування версіями коду &lt;i&gt;Git&lt;/i&gt;. Коли ви внесете зміни у віддалений репозиторій, сервіс автоматично розгорне ваш код і перевантажить додаток якщо необхідно.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Перед тим, як ви зможете завантажувати код, ви повинні надати публічні ключі &lt;i&gt;ssh&lt;/i&gt; для ідентифікації вас на сервері.&lt;br /&gt;
&lt;i&gt;OpenShift&lt;/i&gt; використовує публічні ключі для шифрування з&#39;єднання між вашою локальною машиною і додатком. Ви повинні створити приватний і публічний ключі на вашій локальній машині, і завантажити публічний ключ перед тим як ви зможете приєднатися до вашого додатку&lt;br /&gt;
&lt;br /&gt;
Публічний ключ знаходиться у файлі&lt;i&gt;~/.ssh/id_rsa.pub&lt;/i&gt;&lt;br /&gt;
Його вміст потрібно вставити на сторінці &lt;a href=&quot;https://openshift.redhat.com/app/console/applications/test/get_started&quot;&gt;https://openshift.redhat.com/app/console/applications/test/get_started&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Згенерувати новий ключ можна командою:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;$ ssh-keygen -t rsa -C &amp;quot;your_email@youremail.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
У вашій системі повинен бути встановлений клієнт &lt;i&gt;Git&lt;/i&gt;.&lt;br /&gt;
Для створення свого клону проекту з git-репозиторію потрібно виконати команду типу такої:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;$ git clone ssh://ххх@test-mamantoha.rhcloud.com/~/git/test.git/
&lt;/code&gt;&lt;/pre&gt;Ця команда створить на локальній машині каталог з кодом вашого додатку. Після цього ви зможете правити і публікувати код у віддалений репозиторій. &lt;br /&gt;
&lt;br /&gt;
Давайте подивимось на структуру додатку по замовчуванню:&lt;br /&gt;
&lt;i&gt;config.ru&lt;/i&gt; - цей файл використовується для запуску веб-орієнтованих додатків на основі &lt;i&gt;Rack&lt;/i&gt;(наприклад, &lt;i&gt;Sinatra&lt;/i&gt;, &lt;i&gt;Padrino&lt;/i&gt;).&lt;br /&gt;
&lt;i&gt;tmp/&lt;/i&gt; - тимчасове сховище.&lt;br /&gt;
&lt;i&gt;public/&lt;/i&gt; - публічний каталог (для картинок, &lt;i&gt;css&lt;/i&gt;, &lt;i&gt;javascript&lt;/i&gt;).&lt;br /&gt;
&lt;i&gt;../data&lt;/i&gt; - для постійних даних.&lt;br /&gt;
&lt;i&gt;.openshift/action_hooks/pre_build&lt;/i&gt; - скрипт, який запускається перед кожним внесенням змін у віддалений репозиторій (&lt;i&gt;git push&lt;/i&gt;).&lt;br /&gt;
&lt;i&gt;.openshift/action_hooks/build&lt;/i&gt; - скрипт, який запускається після &lt;i&gt;git push&lt;/i&gt;, в процесі побудови.&lt;br /&gt;
&lt;i&gt;.openshift/action_hooks/deploy&lt;/i&gt; - скрипт, який запускається після &lt;i&gt;git push&lt;/i&gt;, але перед перезапуском додатку.&lt;br /&gt;
&lt;i&gt;.openshift/action_hooks/post_deploy&lt;/i&gt; - скрипт, який запускається після &lt;i&gt;git push&lt;/i&gt;, після перезапуску додатку.&lt;br /&gt;
&lt;br /&gt;
Прийшов час створити простий &lt;i&gt;Sinatra&lt;/i&gt; додаток.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;OpenShift&lt;/i&gt; має дзеркало &lt;a href=&quot;http://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; на &lt;a href=&quot;http://mirror1.prod.rhcloud.com/mirror/ruby/&quot;&gt;http://mirror1.prod.rhcloud.com/mirror/ruby/&lt;/a&gt;.&lt;br /&gt;
Це дзеркало знаходиться у тій самій мережі, що і ваш додаток. Тому &lt;i&gt;gem&lt;/i&gt;&#39;и будуть завантажуватися швидше.&lt;br /&gt;
Щоб використовувати дзеркало &lt;i&gt;OpenShift&lt;/i&gt;, відредагуйте файл &lt;i&gt;Gemfile&lt;/i&gt; і просто замініть:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;source &#39;http://rubygems.org&#39;
&lt;/code&gt;&lt;/pre&gt;на&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;source &#39;http://mirror1.prod.rhcloud.com/mirror/ruby/&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Нижче додайте &lt;i&gt;gem&lt;/i&gt;&#39;и, які будете використовуватися у додатку:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;gem &#39;sinatra&#39;
gem &#39;slim&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Далі відредагуйте файл &lt;i&gt;config.ru&lt;/i&gt;, який призначений для запуску додатку &lt;i&gt;Sinatra&lt;/i&gt;.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;require &#39;bundler&#39;

Bundler.require

require &#39;./app&#39;

run Sinatra::Application
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
І власне &lt;i&gt;app.rb&lt;/i&gt;:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;require &#39;sinatra&#39;
require &#39;slim&#39;

enable :inline_templates

get &#39;/&#39; do
  slim :hello
end

__END__

@@ hello
h1 Hello OpenShift!
p = RUBY_DESCRIPTION
p = Time.now
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Переконуємось, що всі залежності в Gemfile &lt;i&gt;доступні&lt;/i&gt; для нашого додатку.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;bundle install
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Коли ви внесете зміни у віддалений репозиторій, &lt;i&gt;OpenShift&lt;/i&gt; повідомить статус розгортання коду. Сервіс виконає усі необхідні дії і перезапустить додаток.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;git add .
git commit -a
git push
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Робочий приклад додатку зі статті: &lt;a href=&quot;http://test-mamantoha.rhcloud.com/&quot;&gt;http://test-mamantoha.rhcloud.com/&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/9191403392171868963/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/9191403392171868963' title='2 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/9191403392171868963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/9191403392171868963'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/05/sinatra-openshift.html' title='Розгортання додатку Sinatra на OpenShift'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlvNoIbbMz2Bp34Bv6UH5ItHBzV2tcBl3UyqvVHwj9zfVsWdT_KUd4VD3Mlza0wkkDev78pomC7ezZhlnJKiYrle-oBCtZ0zemY1wlydsM2ZobhnRVqbBfg-8A51quVu9aGyIesyoAYn4/s72-c/OpenShift-Logo.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-2492911090356827144</id><published>2012-05-17T14:11:00.001+03:00</published><updated>2012-05-17T15:25:24.774+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="mechanize"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Ведення логів у Mechanize</title><content type='html'>Для того, щоб проаналізувати, що пішло не так, коли &lt;i&gt;Mechanize&lt;/i&gt; викликає виключення, виникає необхідність ведення логів. &lt;i&gt;Mechanize&lt;/i&gt; може реєструвати практично будь-які події, включаючи заголовки запитів. Для цього потрібно передати екземпляр класу &lt;i&gt;Logger&lt;/i&gt; у метод &lt;i&gt;Mechanize#log&lt;/i&gt;.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;# -*- encoding: utf-8 -*-

require &#39;mechanize&#39;
require &#39;logger&#39;

log = Logger.new($stderr)
log.level = Logger::DEBUG

agent = Mechanize.new do &amp;#124;a&amp;#124;
  a.log = log
end

agent.get(&#39;http://google.com&#39;)
&lt;/code&gt;&lt;/pre&gt;Отриману інформацію надалі можна використати для аналізу подій, виявлення помилок та збоїв.&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/2718143#file_mechanize1.log&quot;&gt;https://gist.github.com/2718143#file_mechanize1.log&lt;/a&gt;&lt;br /&gt;
Офіційна документація по класу &lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html&quot;&gt;Logger&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Також існує менш відомий, але не менш корисний спосіб ведення логів за допомогою методу &lt;i&gt;Mechanize#agent.http.debug_output&lt;/i&gt;:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;# -*- encoding: utf-8 -*-

require &#39;mechanize&#39;

agent = Mechanize.new do &amp;#124;a&amp;#124;
  a.agent.http.debug_output = $stderr
end

agent.get(&#39;http://google.com&#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;a href=&quot;https://gist.github.com/2718143#file_mechanize2.log&quot;&gt;https://gist.github.com/2718143#file_mechanize2.log&lt;/a&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/2492911090356827144/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/2492911090356827144' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2492911090356827144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/2492911090356827144'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/05/mechanize.html' title='Ведення логів у Mechanize'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-7244099663132894381</id><published>2012-05-17T00:17:00.000+03:00</published><updated>2012-05-17T00:42:30.187+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="vkontakte"/><title type='text'>Оновлюємо статус ВКонтакте за допомогою Ruby</title><content type='html'>Сьогодні вечором виникло бажання, щоб на моїй сторінці &lt;i&gt;ВКонтакте&lt;/i&gt; відображався таймер зворотнього відліку до початку Євро-2012 прямо в статусі. Написати простенький скрипт на &lt;i&gt;Ruby&lt;/i&gt; для такого достатньо просто.&lt;br /&gt;
З інструментів я використовував свою &lt;a href=&quot;https://github.com/mamantoha/vkontakte&quot;&gt;бібліотеку&lt;/a&gt; для роботи з &lt;i&gt;API ВКонтакте&lt;/i&gt;. Якщо комусь цікаво, як вона працює, можете почитати статтю &lt;a href=&quot;http://ruby-ua.blogspot.com/2011/06/standalone-oauth-20-ruby-mechanize.html&quot;&gt;ВКонтакте → Авторизація Standalone-додатків використовуючи OAuth 2.0 на прикладі Ruby і Mechanize&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Не вдаючись в подробиці, ось &lt;a href=&quot;https://gist.github.com/2713756&quot;&gt;посилання на приклад скрипта&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Здавалось би залишилось додати скрипт у &lt;i&gt;cron&lt;/i&gt; і насолоджуватись результатом.&lt;br /&gt;
Наступний рядок у &lt;i&gt;/etc/crontab&lt;/i&gt; не приніс бажаних результатів.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;*/1 * * * * user ruby /home/user/days_to_euro.rb
&lt;/code&gt;&lt;/pre&gt;Скрипт всього-на-всього не виконувався.&lt;br /&gt;
Причиною проблеми виявився Ruby Version Manager(&lt;i&gt;RVM&lt;/i&gt;). Змінюємо на наступний рядок.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;*/1 * * * * user bash -c &#39;source /home/user/.rvm/scripts/rvm &amp;amp;&amp;amp; /usr/bin/env ruby /home/user/days_to_euro.rb&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
І вуаля: тепер скрипт успішно виконується і так же успішно завершує роботу з помилкою:&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;`default_gemfile&#39;: Could not locate Gemfile (Bundler::GemfileNotFound)
&lt;/code&gt;&lt;/pre&gt;Це відбувається тому, &lt;i&gt;Bundler&lt;/i&gt; шукає &lt;i&gt;Gemfile&lt;/i&gt; в каталозі в якому виконується, а &lt;i&gt;Gemfile&lt;/i&gt; там звісно ж немає.&lt;br /&gt;
Потрібно вказати де шукати Gemfile.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;ENV[&#39;BUNDLE_GEMFILE&#39;] = File.join(File.dirname(__FILE__) ,&#39;Gemfile&#39;)
&lt;/code&gt;&lt;/pre&gt;Вищевказаний рядок потрібно додати у шапку скрипта.&lt;br /&gt;
&lt;br /&gt;
Тепер все добре і скрипт працює.&lt;br /&gt;
&lt;br /&gt;
P.S. До Євро-2012 залишилось 21 день 23 години 43 хвилини</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/7244099663132894381/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/7244099663132894381' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7244099663132894381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/7244099663132894381'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/05/ruby.html' title='Оновлюємо статус ВКонтакте за допомогою Ruby'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4152168096498110483.post-8489227712383459220</id><published>2012-05-13T19:17:00.001+03:00</published><updated>2012-05-13T19:17:36.953+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gui"/><category scheme="http://www.blogger.com/atom/ns#" term="qtruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>QtRuby: позиціювання віджетів</title><content type='html'>У цій статті, ми познайомимося з основами розміщенням віджетів у вікні додатку &lt;i&gt;QtRuby&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Коли ми розробляємо графічний інтерфейс додатку, ми вирішуємо, які компоненти ми будемо використовувати і як ми будемо організовувати ці компоненти. Щоб організувати компоненти, ми використовуємо спеціальні невидимі ​​об&#39;єкти, так звані менеджери компонування(layout managers).&lt;br /&gt;
&lt;i&gt;Qt&lt;/i&gt; надає кілька варіантів. Ми можемо використовувати абсолютне позиціювання, вбудовані менеджери компонування або створити власний менеджер компонування. Також ми також можемо візуально будувати макети допомогою &lt;i&gt;Qt Designer&lt;/i&gt;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3&gt;Абсолютне позиціювання.&lt;/h3&gt;&lt;br /&gt;
Негарний і не рекомендований метод розміщення графічних об&#39;єктів - &quot;в ручну&quot; задавати положення і розмір кожного віджета у пікселях, використовуючи метод &lt;i&gt;setGeometry(x, y, width, height)&lt;/i&gt;.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;# -*- encoding: utf-8 -*-

require &#39;Qt&#39;

class QtApp &amp;lt; Qt::Widget
  def initialize
    super

    set_window_title &#39;Absolute&#39;

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new(&#39;Windows&#39;, self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new(&#39;Activate&#39;, self)
    close = Qt::PushButton.new(&#39;Close&#39;, self)
    ok = Qt::PushButton.new(&#39;OK&#39;, self)
    help = Qt::PushButton.new(&#39;Help&#39;, self)

    label.move(10, 10)
    edit.set_geometry(10, 30, 300, 200)
    activate.set_geometry(320, 30, 70, 30)
    close.set_geometry(320, 60, 70, 30)
    ok.set_geometry(320, 240, 70, 30)
    help.set_geometry(10, 240, 70, 30)
  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLjTZoFk5TMV4nin1SdaIEeCFYiscO5T3-zH8p-fB0wH8tCSqH3NXsW1poCfHDx3lpFKFy0aXNSy44eAsaIc9qbCldIwlSYJS_xyQX6qyFcKv7OccffctfJmiVTEJ0LqS3c0n6JoBEJGM/s1600/absolute.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLjTZoFk5TMV4nin1SdaIEeCFYiscO5T3-zH8p-fB0wH8tCSqH3NXsW1poCfHDx3lpFKFy0aXNSy44eAsaIc9qbCldIwlSYJS_xyQX6qyFcKv7OccffctfJmiVTEJ0LqS3c0n6JoBEJGM/s400/absolute.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Очевидний недолік такого підходу проявиться відразу ж, як тільки ви почнете змінювати розміри вікна. Всі віджети залишаються на своїх місцях.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ7X20iPAORs4WlfUD8J0MToLTjYB8jQYquT6reWSnV7RT8faVMfjo9eUbdBJPh-Y2rFzXLucKGyZdfKiwxDApL57qUwEzJYabqrP2djS3vFXXpi5-kGkhckqy1V26NUVNqlZXMG56zE4/s1600/absolute_resize1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;272&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ7X20iPAORs4WlfUD8J0MToLTjYB8jQYquT6reWSnV7RT8faVMfjo9eUbdBJPh-Y2rFzXLucKGyZdfKiwxDApL57qUwEzJYabqrP2djS3vFXXpi5-kGkhckqy1V26NUVNqlZXMG56zE4/s400/absolute_resize1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;h3&gt;Менеджери компонування&lt;/h3&gt;&lt;i&gt;Qt&lt;/i&gt; надає більш гнучкий і досконалий механізм розміщення графічних об&#39;єктів в контейнері. В &lt;i&gt;Qt&lt;/i&gt; для цих цілей існують менеджери компонування, успадковані від класу &lt;i&gt;Qt::Layout&lt;/i&gt;.&lt;br /&gt;
Розглянемо три основних менеджера компонування: &lt;i&gt;Qt::HBoxLayout&lt;/i&gt;, &lt;i&gt;Qt::VBoxLayout&lt;/i&gt; і &lt;i&gt;Qt::GridLayout&lt;/i&gt;.&lt;br /&gt;
Для розміщення об&#39;єктів в один ряд по горизонталі використовується &lt;i&gt;Qt::HBoxLayout&lt;/i&gt;, аналогічно &lt;i&gt;Qt::VBoxLayout&lt;/i&gt; - для розміщення об&#39;єктів по вертикалі.&lt;br /&gt;
Для більш складних розміщень використовують &lt;i&gt;Qt::GridLayout&lt;/i&gt;, а також комбінації з усіх трьох менеджерів.&lt;br /&gt;
&lt;i&gt;Qt::GridLayout&lt;/i&gt; розміщує елементи в комірках уявної таблиці, причому кожен елемент може займати кілька суміжних комірок по вертикалі і/або горизонталі. Про нього пізніше.&lt;br /&gt;
Для додавання підлеглого віджету використовується метод &lt;i&gt;addWidget()&lt;/i&gt;, для додавання підлеглого менеджера компонування - метод &lt;i&gt;addLayout()&lt;/i&gt;.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;
# -*- encoding: utf-8 -*-

require &#39;Qt&#39;

class QtApp &amp;lt; Qt::Widget
  def initialize
    super

    set_window_title &#39;Layouts&#39;

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new(&#39;Windows&#39;, self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new(&#39;Activate&#39;, self)
    close = Qt::PushButton.new(&#39;Close&#39;, self)
    ok = Qt::PushButton.new(&#39;OK&#39;, self)
    help = Qt::PushButton.new(&#39;Help&#39;, self)

    vbox = Qt::VBoxLayout.new(self)

    vbox1 = Qt::VBoxLayout.new
    hbox1 = Qt::HBoxLayout.new
    hbox2 = Qt::HBoxLayout.new

    vbox.add_widget(label)

    vbox1.add_widget(activate)
    vbox1.add_widget(close, 0, Qt::AlignTop)
    hbox1.add_widget(edit)
    hbox1.add_layout(vbox1)

    vbox.add_layout(hbox1)

    hbox2.add_widget(help)
    hbox2.add_stretch(1)
    hbox2.add_widget(ok)

    vbox.add_layout(hbox2, 1)

    set_layout(vbox)

  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8lfbMnmy1ijt9HmfdOuIRjMhtbmiwpkb89hBnMGndCcajYRzeLpKCujxPTTG-HB9kygPt_SZEnVanJYd_2p_nu1a9lIZSXB1ljJtaKiIBfIgf7DVj43nPRKQ9AttiD5LlBxbzcKTYT_o/s1600/boxlayout.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8lfbMnmy1ijt9HmfdOuIRjMhtbmiwpkb89hBnMGndCcajYRzeLpKCujxPTTG-HB9kygPt_SZEnVanJYd_2p_nu1a9lIZSXB1ljJtaKiIBfIgf7DVj43nPRKQ9AttiD5LlBxbzcKTYT_o/s400/boxlayout.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;vbox = Qt::VBoxLayout.new(self)
&lt;/code&gt;&lt;/pre&gt;Базовий блок нашого прикладу, у якому будуть розміщуватися всі інші віджети і блоки.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;vbox.add_widget(label)
&lt;/code&gt;&lt;/pre&gt;Першим йде віджет мітки(&lt;i&gt;label&lt;/i&gt;). Він буде просто знаходитися зверху у вертикальному блоці(&lt;i&gt;vbox&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;vbox1.add_widget(activate)
vbox1.add_widget(close, 0, Qt::AlignTop)

hbox1.add_widget(edit)
hbox1.add_layout(vbox1)

vbox.add_layout(hbox1)
&lt;/code&gt;&lt;/pre&gt;У центральній частині вікна у нас є віджет редагування тексту(&lt;i&gt;edit&lt;/i&gt;) і дві кнопки(&lt;i&gt;activate&lt;/i&gt; і &lt;i&gt;close&lt;/i&gt;). Вони розміщені у вертикальному блоці(&lt;i&gt;vbox1&lt;/i&gt;), і вирівняні по верхній його частині. Віджет редагування тексту(&lt;i&gt;edit&lt;/i&gt;) і вертикальний блок(&lt;i&gt;vbox1&lt;/i&gt;) розміщені у горизонтальному блоці(&lt;i&gt;hbox1&lt;/i&gt;), який в свою чергу розміщений у вертикальному блоці(&lt;i&gt;vbox&lt;/i&gt;) відразу під віджетом мітки(&lt;i&gt;label&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;hbox2.add_widget(help)
hbox2.add_stretch(1)
hbox2.add_widget(ok)

vbox.add_layout(hbox2, 1)
&lt;/code&gt;&lt;/pre&gt;Кнопки &lt;i&gt;help&lt;/i&gt; і &lt;i&gt;ok&lt;/i&gt; розміщені в іншому горизонтальному блоці(&lt;i&gt;hbox2&lt;/i&gt;). Між ними за допомогою методу &lt;i&gt;addStretch()&lt;/i&gt; встановлений розширювальний пробіл. Знову ж таки, горизонтальний блок(&lt;i&gt;hbox2&lt;/i&gt;) розміщений в головному вертикальному блоці(&lt;i&gt;vbox&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;set_layout(vbox)
&lt;/code&gt;&lt;/pre&gt;Головний вертикальний блок(&lt;i&gt;vbox&lt;/i&gt;) встановлений, як основний для вікна.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUZQZf_yXf-S4YbHPjpjEbC3N1VsJMlqU3VmALOq6Kqih_xA3SUiGkqWRqCf0n8bQ1WgGbtn44zCGPdfXNpWvmjraN4X7mvDEOLDfxuocVuW4_TnfNQbHrBLGqITLWBYtCEfHtlRoiCog/s1600/boxlayout_resize1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;273&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUZQZf_yXf-S4YbHPjpjEbC3N1VsJMlqU3VmALOq6Kqih_xA3SUiGkqWRqCf0n8bQ1WgGbtn44zCGPdfXNpWvmjraN4X7mvDEOLDfxuocVuW4_TnfNQbHrBLGqITLWBYtCEfHtlRoiCog/s400/boxlayout_resize1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Можете переконатися, що віджети позиціонуються відносно розмірів вікна.&lt;br /&gt;
&lt;br /&gt;
В останньому прикладі ми будемо використовувати менеджер &lt;i&gt;Qt::GridLayout&lt;/i&gt;.&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;# -*- encoding: utf-8 -*-

require &#39;Qt&#39;

class QtApp &amp;lt; Qt::Widget
  def initialize
    super

    set_window_title &#39;GridLayout&#39;

    init_ui

    resize 400, 280
    move 300, 300

    show
  end

  def init_ui
    label = Qt::Label.new(&#39;Windows&#39;, self)
    edit = Qt::TextEdit.new(self)
    activate = Qt::PushButton.new(&#39;Activate&#39;, self)
    close = Qt::PushButton.new(&#39;Close&#39;, self)
    ok = Qt::PushButton.new(&#39;OK&#39;, self)
    help = Qt::PushButton.new(&#39;Help&#39;, self)

    grid = Qt::GridLayout.new(self)

    grid.add_widget(label, 0, 0)
    grid.add_widget(edit, 1, 0, 3, 2)
    grid.add_widget(activate, 1, 2)
    grid.add_widget(close, 2, 2)
    grid.add_widget(ok, 4, 2)
    grid.add_widget(help, 4, 0)

    grid.set_column_stretch(1, 1)
    grid.set_row_stretch(3, 1)

    set_layout(grid)
  end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlofe-c8Tgf0AlK__10euNBVzNqYCLLHOE6Z-DAtIFGyPl4ea_UdnjAkT30zdtManWD3JGU5zOxc4QyZun6pekxsCu4ayo6FCh4llkZnJov9FA2V3ibEGLTV1SqQk4RV74vcYeRSm5fHg/s1600/gridlayout.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlofe-c8Tgf0AlK__10euNBVzNqYCLLHOE6Z-DAtIFGyPl4ea_UdnjAkT30zdtManWD3JGU5zOxc4QyZun6pekxsCu4ayo6FCh4llkZnJov9FA2V3ibEGLTV1SqQk4RV74vcYeRSm5fHg/s400/gridlayout.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;grid.add_widget(label, 0, 0)
&lt;/code&gt;&lt;/pre&gt;Ми розміщуємо мітку(&lt;i&gt;label&lt;/i&gt;) в першу клітинку сітки. Клітинки рахуються від 0. Останні два параметри є номерами рядка і стовпця.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;grid.add_widget(edit, 1, 0, 3, 2)
&lt;/code&gt;&lt;/pre&gt;Віджет редагування тексту(&lt;i&gt;edit&lt;/i&gt;) поміщається в першому рядку і нульовому стовпці. Останні два параметри є діапазоном рядків і стовпців. Вертикально, віджет буде охоплювати три рядка, а горизонтально - дві колонки.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;grid.set_column_stretch(1, 1)
&lt;/code&gt;&lt;/pre&gt;Параметрами методу &lt;i&gt;setColumnStretch()&lt;/i&gt; є номер колонки і коефіцієнт розтягування. Тут ми встановлюємо коефіцієнт розтягування 1 для першої колонки. Це означає, що ця колонка буде займати все вільне місце по горизонталі. Це зроблено для, щоб кнопки зберігали свій оригінальний розмір.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;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%&quot;&gt;&lt;code&gt;grid.set_row_stretch(3, 1)
&lt;/code&gt;&lt;/pre&gt;Аналогічно тут встановлюємо коефіцієнт розтягування 1 для третього рядка, щоб мітка(&lt;i&gt;label&lt;/i&gt;) зберігала свій мінімальний розмір.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgubBaCkbxpJg4Py7iftllJ0A2WsWemL1iMAbmZxe_CMBtdoQA1rPa7upMGvKD_F2H8AtIQfAxQeFb8dv1t_dFGpWbsp63PLAVoIwx3Ykpec22W1WqWgN3VkPT0cQ9FRkbS6QeAf2NRCZw/s1600/gridlayout_resize1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;271&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgubBaCkbxpJg4Py7iftllJ0A2WsWemL1iMAbmZxe_CMBtdoQA1rPa7upMGvKD_F2H8AtIQfAxQeFb8dv1t_dFGpWbsp63PLAVoIwx3Ykpec22W1WqWgN3VkPT0cQ9FRkbS6QeAf2NRCZw/s400/gridlayout_resize1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-ua.blogspot.com/feeds/8489227712383459220/comments/default' title='Дописати коментарі'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/4152168096498110483/8489227712383459220' title='0 коментарі(в)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8489227712383459220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4152168096498110483/posts/default/8489227712383459220'/><link rel='alternate' type='text/html' href='http://ruby-ua.blogspot.com/2012/05/qtruby_13.html' title='QtRuby: позиціювання віджетів'/><author><name>Anton Maminov</name><uri>http://www.blogger.com/profile/08026234658348754340</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLjTZoFk5TMV4nin1SdaIEeCFYiscO5T3-zH8p-fB0wH8tCSqH3NXsW1poCfHDx3lpFKFy0aXNSy44eAsaIc9qbCldIwlSYJS_xyQX6qyFcKv7OccffctfJmiVTEJ0LqS3c0n6JoBEJGM/s72-c/absolute.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>