tag:blogger.com,1999:blog-41521680964981104832024-03-13T18:25:58.782+02:00Записки про Ruby5.times { print "We *love* Ruby -- it's outrageous!" }Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.comBlogger200125tag:blogger.com,1999:blog-4152168096498110483.post-70411872204793400262013-10-29T14:27:00.002+02:002013-10-29T14:33:22.744+02:00Magento XML-RPC API і RubyПісля написання першої статті <a href="http://ruby-ua.blogspot.com/2013/10/magento-rest-api-oauth-ruby.html">Magento REST API і OAuth в Ruby</a>, захотілося продовжити вивчення можливостей <i>Magento API</i>.<br />
Весь сир-бор через те, що можливості <i>REST</i> в <i>Magento</i> просто жалюгідні.<br />
На сьогодні <i>Magento</i> підтримує всі найбільш поширені способи доступу до API сайтів: <i>REST</i>, <i>XML-RPC</i>, <i>SOAP</i>.<br />
<br />
<i>Magento SOAP/XML-RPC API</i> дає вам можливість керувати своїми магазинами електронної комерції, забезпечуючи методи для роботи з ресурсами, такими як клієнти, категорій, продукти і замовлення.<br />
<br />
Про <i>SOAP</i> можна говорити багато і довго.<br />
Для мене основними мінусами стали складність протоколу і відсутність вбудованої підтримки в <i>Ruby</i>.<br />
Натомість стандарт <i>XML-RPC</i> зачарував мене своєю надзвичайною простотою.<br />
В базову поставку <i>Ruby</i> вже входить бібліотека для роботи з <i>XML-RPC</i>, відповідно вам не доведеться замислюватися про структуру запитів і обробку відповідей в XML.<br />
<br />
Тому саме <i>XML-RPC</i> в основному і буде присвячена ця стаття.<br />
Не буду зупинятися на питанні, що таке <i>XML-RPC</i> і навіщо він потрібен. У мережі багато статей на цю тему.<br />
<br />
Просто постараюся коротко показати, яким простим способом можливе створення клієнта до <i>XML-RPC</i> веб-сервісу на <i>Ruby</i>.<br />
<pre class="brush:ruby">require 'xmlrpc/client'
config = {
api_user: 'user',
api_key: 'secret',
host: 'example.com',
path: '/api/xmlrpc',
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('login', config[:api_user], config[:api_key])
parent_id = 1
store_view = 1
client.call('call', session, 'catalog_category.tree', [parent_id , store_view])
# If you don't need the session anymore
client.call('endSession', session)
</pre><br />
Все просто: ми підключаємося до сервера, отримуємо ключ сесії і виконуємо запити.<br />
<br />
Документацію по всіх запитах <i>Magento API</i> можна знайти на <a href="http://www.magentocommerce.com/api/soap/introduction.html">офіційному сайті</a>.<br />
<i>XML-RPC</i> підтримується тільки першою версією <i>Magento API</i>.<br />
<a name='more'></a><br />
<br />
А тепер найцікавіше! Цей код не працюватиме або працюватиме з перемінних успіхом по різному в усіх трьох основних реалізація мови: <i>MRI Ruby</i>, <i>Rubinius</i> і <i>JRuby</i><br />
<br />
<i>MRI Ruby</i> і <i>Rubinius</i> викликають наступну помилку:<br />
<pre class="brush:ruby">Wrong size. Was 0, should be 147 (RuntimeError)
</pre><br />
Недовге гуглення приводить до <a href="http://bugs.ruby-lang.org/issues/8182">баги</a>.<br />
Додамо наступний рядок після ініціалізації клієнта:<br />
<pre class="brush:ruby">client.http_header_extra = {"accept-encoding" => "identity"}
</pre><br />
Але і це ще не все. Для деяких запитів <i>XML-RPC</i> в усіх трьох реалізаціях інколи з'являється помилка:<br />
<pre class="brush:ruby">wrong/unknown XML-RPC type 'nil' (RuntimeError)
</pre><br />
Рішення проблеми було знайдене <a href="https://github.com/timmatheson/Magento#issues-">тут</a>.<br />
<pre class="brush:ruby">XMLRPC::Config.module_eval {
remove_const(:ENABLE_NIL_PARSER) # so that we're not warned about reassigning to a constant
const_set(:ENABLE_NIL_PARSER, true) # so that we don't get "RuntimeError: wrong/unknown XML-RPC type 'nil'"
}
</pre><br />
На цьому все.Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com2tag:blogger.com,1999:blog-4152168096498110483.post-31017233306972022282013-10-20T14:43:00.000+03:002013-10-20T14:52:19.697+03:00Magento REST API і OAuth в RubyУ цій статті я хочу поділитися прикладом роботи з <i>Magento REST API</i> використовуючи <i>Ruby</i> і <i>oauth</i> gem. У свій час пошуки подібного ні до чого не привели.<br />
<br />
Докладна документація по <i>Magento REST API</i> <a href="http://www.magentocommerce.com/api/rest/introduction.html">тут</a>.<br />
<br />
<h3>Реєстрація та уповноваженому додатку</h3><br />
Отже, приступимо. Першим ділом, потрібно отримати всі потрібні параметри для авторизації. Зокрема ключі <i>consumer_key</i> і <i>consumer_secret</i>. І, власне хост(<i>magentohost</i>), на якому встановлене Magento.<br />
<br />
<b>Скажу відразу</b>, налаштування платформи <i>Magento</i> для <i>REST API</i> не розглядається в рамках цієї статті.<br />
<a name='more'></a><br />
<pre class="brush:ruby">require 'json'
require 'oauth'
auth = {
consumer_key: '***',
consumer_secret: '***',
}
magentohost = 'http://example.com'
@consumer = OAuth::Consumer.new(auth[:consumer_key], auth[:consumer_secret], {
:site => magentohost,
:request_token_path => '/oauth/initiate',
:access_token_path => '/oauth/token',
:authorize_path => '/admin/oauth_authorize',
})
</pre><br />
<h3>Отримання токена</h3><br />
Для отримання <i>access_token</i> потрібно перейти за наступним посиланням, увійти(якщо потрібно) і уповноважити додаток.<br />
Якщо автентифікація пройдена успішно, потрібно ввести отриманий код верифікації. Після цього будуть отримані <i>token</i> і <i>token_secret</i>, які використовуватимуться для здійснення HTTP запитів.<br />
<br />
<pre class="brush:ruby">request_token = @consumer.get_request_token
puts request_token.authorize_url
print 'Код перевірки: '
verifier = gets.strip
access_token = request_token.get_access_token(:oauth_verifier => verifier)
auth[:token] = access_token.token
auth[:token_secret] = access_token.secret
</pre><br />
<h3>Запити до API</h3><br />
Ми вже отримали <i>access_token</i> і можемо виконувати HTTP запити.<br />
<pre class="brush:ruby">response = access_token.request(:get, '/api/rest/products')
rsp = JSON.load(response.body)
</pre><br />
Раніше отримані <i>token</i> і <i>token_secret</i> можна зберегти для того, щоб виконувати запити без попередньої автентифікації.<br />
<pre class="brush:ruby">auth[:token] = "***"
auth[:token_secret] = "***"
access_token = OAuth::AccessToken.new(@consumer, auth[:token], auth[:token_secret])
response = access_token.request(:get, '/api/rest/products')
rsp = JSON.load(response.body)
</pre><br />
На цьому все.Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-28912064211212773252013-09-13T11:44:00.000+03:002013-09-13T11:44:01.578+03:00Зі святом, програмісти!П'ятниця 13-го. День програміста. Програмістів з відьмами об'єднує не тільки бубен для магічної тряски, а і святкова п'ятницю для шабашу.<br />
Зі Святом, товариші!<br />
<br />
Наскільки часто буває такий збіг?<br />
Відповідь під катом.<br />
<br />
<a name='more'></a><br />
<br />
Вивести наступних 13 Днів Програміста у п'ятницю 13-го.<br />
<pre class="brush:ruby">require 'date'
puts (Date.new(2013)..Date.new(9999)).lazy.select{|d| d.yday == 256 && d.day == 13 && d.friday?}.first(13)
</pre><br />
<pre class="brush">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
</pre><br />
Не лінивий читач помітив, що в коді використовується лінивий <i>Enumerator</i>, який з'явився в <i>Ruby 2.0</i>.<br />
Провів простий бенчмарк для визначення порівняльних характеристик продуктивності.<br />
<pre class="brush:ruby">require 'date'
require 'benchmark'
iterations = 100
Benchmark.bm(20) do |bm|
bm.report('Enumerator#lazy') do
iterations.times do
(Date.new(2013)..Date.new(9999)).lazy.select{|d| d.yday == 256 && d.day == 13 && d.friday?}.first(13)
end
end
bm.report('Enumerator') do
iterations.times do
(Date.new(2013)..Date.new(9999)).select{|d| d.yday == 256 && d.day == 13 && d.friday?}.first(13)
end
end
end
</pre><br />
Висновки робіть самі.<br />
<pre class="brush"> user system total real
Enumerator#lazy 2.240000 0.000000 2.240000 ( 2.256149)
Enumerator 163.970000 0.000000 163.970000 (164.479462)
</pre>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-32275167355796566882013-07-15T22:59:00.002+03:002013-07-15T22:59:49.186+03:00Книга по Ruby 2.0<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="https://github.com/Krugloff" target="_blank">Алекcандр Круглов</a> виклав у вільний доступ книгу "Ruby" по мові програмування Ruby 2.0.<br />
<br />
Якщо я не помиляюся, це перша опенсорс книга про Ruby російською мовою.<br />
<br />
Текст книги у форматі PDF доступний за <a href="http://dl.dropbox.com/u/75172405/Ruby.pdf">наступним посиланням</a>. Зі змістом можна ознайомитися <a href="http://bpaste.net/show/114445/" target="_blank">тут</a>.<br />
<br />
Книгу можна зібрати з вихідних кодів:<br />
<ol style="text-align: left;">
<li>Встановити Ruby.</li>
<li>Встановити необхідні пакети: <em>gem install redcarpet</em>.</li>
<li>Завантажити <a href="http://gist.github.com/Krugloff/5491182" target="_blank">скрипт</a> для перетворення Markdown в LaTeX.</li>
<li>Встановити XeLaTeX.</li>
<li>Завантажити <a href="http://gist.github.com/Krugloff/5491168" target="_blank">стиль</a>.</li>
<li>Зібрати pdf: <em>xelatex book.tex</em> (за замовчуванням використовуються шрифти сімейства Liberation).</li>
</ol>
<br />
>>> Новина взята з <a href="http://www.linux.org.ru/news/doc/9364033" target="_blank">LOR</a>.</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-37152727402112233782013-04-30T16:37:00.001+03:002013-04-30T16:37:51.461+03:00Отримання улюблених аудіозаписів з Last.fmПочитав тут статтю <a href="http://habrahabr.ru/post/178215/">Получение любимых аудиозаписей с pandora.com</a>, подумав і придумав subj.<br />
Отже, з <i>Last.fm</i> будемо отримувати список назв пісень і виконавців, потім за допомогою <i>API ВКонтакте</i> будемо їх скачувати.<br />
<br />
Крок 1. Йдем на <i>Last.fm</i>, і витягуємо список улюблених пісень користувача.<br />
<br />
Для тих хто не знає, <i>Last.fm</i> має <i>API</i>, що дозволяє будь-якому користувачеві створювати свої власні програми з використанням даних Last.fm. Для роботи з API потрібно отримати <i>API Key</i> і <i>Secret</i>. Йдемо на <a href="http://www.last.fm/api">http://www.last.fm/api</a> і створюємо новий аккаунт для некомерційного використання.<br />
<br />
<a href="https://github.com/youpy/ruby-lastfm">ruby-lastfm</a> - інтерфейс для Web-сервісів Last.fm v2.0.<br />
Тепер нам потрібно отримати token:<br />
<pre class="brush:ruby">lastfm = Lastfm.new(lastfm_api_key, lastfm_api_secret)
lastfm_token = lastfm.auth.get_token
</pre><br />
Далі нам пропонують відкрити <i>'http://www.last.fm/api/auth/?api_key=xxxxxxxxxxx&token=xxxxxxxx'</i> і надати права додатку.<br />
<br />
Спробуємо змоделювати цей запит. Але спочатку потрібно авторизуватися на сайті <i>Last.fm</i> за допомогою імені і паролю. Використовуємо бібліотеку <a href="https://github.com/sparklemotion/mechanize">Mechanize</a>:<br />
<pre class="brush:ruby">mech = Mechanize.new do |a|
a.user_agent_alias = 'Linux Firefox'
a.verify_mode = OpenSSL::SSL::VERIFY_NONE
a.follow_meta_refresh = true
end
login_page = mech.get('https://last.fm/login')
login_form = login_page.form_with(action: '/login')
login_form.username = lastfm_username
login_form.password = lastfm_password
page = login_form.submit
if page.uri.to_s == 'http://www.last.fm/home'
puts "Login successful!"
else
puts page.uri.to_s
exit
end
</pre><br />
Якщо авторизація пройшла успішно, надаємо права додатку:<br />
<pre class="brush:ruby">grantaccess_url = "http://www.last.fm/api/auth/?api_key=#{lastfm_api_key}&token=#{lastfm_token}"
grantaccess_page = mech.get(grantaccess_url)
grantaccess_form = grantaccess_page.form_with(action: '/api/grantaccess')
grantaccess_form.submit
</pre><br />
Отже, тепер ми можемо витягнути всю цікаву для нас інформацію:<br />
<pre class="brush:ruby">lastfm.session = lastfm.auth.get_session(:token => lastfm_token)['key']
tracks = lastfm.user.get_loved_tracks(user: lastfm_username)
</pre><br />
Перший крок пройдений! :)<br />
<br />
Крок другий. Пошук і скачування записів з <i>vk.com</i>.<br />
Авторизуємося ВКонаткте:<br />
<pre class="brush:ruby">vk = Vkontakte::Client.new(vk_client_id)
vk.login!(vk_email, vk_password, scope = 'audio')
</pre><br />
Використовуємо API функцію пошуку аудіо:<br />
<pre class="brush:ruby">str = "#{track['artist']['name']} - #{track['name']}"
audio = vk.api.audio_search(q: str, sort: 2)[1]
</pre><br />
Вона повертає найпопулярніший результат пошуку рядка <i>str</i> (серед аудіозаписів).<br />
<br />
Тепер ми знаємо <i>url</i> для скачування. Завантажити можна за допомогою стандартної функції.<br />
<pre class="brush:ruby">path = "#{downloaded_folder}/" + "#{audio['artist']} - #{audio['title']}.mp3"
File.open(path, 'wb') do |saved_file|
open(audio['url'], 'rb') do |read_file|
saved_file.write(read_file.read)
end
end
</pre><br />
В результаті вийшов ось такий скрипт:<br />
<a href="https://gist.github.com/mamantoha/5488722">https://gist.github.com/mamantoha/5488722</a><br />
<br />
Як з ним працювати:<br />
<ul><li>Скрипт вимагає встановленого Ruby і гемів <a href="https://github.com/sparklemotion/mechanize">mechanize</a>, <a href="https://github.com/youpy/ruby-lastfm">ruby-lastfm</a>, <a href="https://github.com/mamantoha/vkontakte">vkontakte</a></li>
<li>Потрібно отримати ключі для <i>Last.fm</i>(<i>lastfm_api_key</i>, <i>lastfm_secret</i>) і <i>ВКонтакте</i>(<i>vk_client_id</i>)</li>
<li><i>downloaded_folder</i> - директорія, куди буде зберігатися скачана музика</li>
<li><i>lastfm_username</i> і <i>lastfm_password</i> - ваш логін і пароль на <i>Last.fm</i></li>
<li><i>vk_email</i> і <i>vk_password</i> - ваш логін і пароль на <i>Vk.com</i></li>
</ul><br />
Відповідні параметри прописати в тілі скрипта.Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-2886713206784025882013-02-24T11:27:00.000+02:002013-02-24T11:27:59.924+02:00Реліз Ruby 2.0.0-p0<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-wMSqo8ySH4g/UJjV-rtgvvI/AAAAAAAALnM/UMPIwYuvp-k/s1600/ruby.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://4.bp.blogspot.com/-wMSqo8ySH4g/UJjV-rtgvvI/AAAAAAAALnM/UMPIwYuvp-k/s200/ruby.jpg" width="199" /></a></div>
<br />
У нас свято!<br />
Точно за оперативним планом 24 лютого <a href="http://www.ruby-lang.org/en/news/2013/02/24/ruby-2-0-0-p0-is-released/" target="_blank">анонсовано</a> реліз Ruby 2.0.0-p0. Були включені нові можливості, які роблять розробку на Ruby ще приємнішою.<br />
<br />
Анонсовані можливості:<br />
<ul>
<li>Уточнення (Refinements) <sup>[1]</sup></li>
<li>Іменовані аргументи в методах <sup>[2]</sup></li>
<li><i>Enumerator#lazy</i> <sup>[3]</sup></li>
<li><i>Module#prepend</i> <sup>[4]</sup></li>
<li><i>#to_h</i></li>
<li><i>%i</i> для масивів символів</li>
<li>Двигун регулярних виразів змінений на Onigmo <sup>[5]</sup></li>
<li>Підтримка DTrace <sup>[6]</sup></li>
</ul>
<br />
Всі програми, які написані на ruby 1.9 будуть працювати на ruby 2.0, якщо в них не буде особливої магії.<br />
<br />
Несумісності:<br />
<div>
<ul style="text-align: left;">
<li>Кодування за замовчуванням для скриптів Ruby стало UTF-8.</li>
<li><i>String#lines</i>, <i>#chars</i>, <i>#codepoints</i> і <i>#bytes</i> тепер повертають <i>Array</i> замість <i>Enumerator</i>.</li>
<li>Iconv був остаточно видалений. Він був оголошений застарілим ще для Ruby 1.9.x. Тепер Ви повинні використовувати можливості M17N, такі як <i>String#encode.</i></li>
</ul>
</div>
<br />
<br />
<ul>
<li>[1] <a href="http://timelessrepo.com/refinements-in-ruby">Refinements</a></li>
<li>[2] <a href="http://bugs.ruby-lang.org/issues/5474">Keyword arguments</a></li>
<li>[3] <a href="http://railsware.com/blog/2012/03/13/ruby-2-0-enumerablelazy/">Enumerator#lazy</a></li>
<li>[4] <a href="http://bugs.ruby-lang.org/issues/1102">Module#prepend</a></li>
<li>[5] <a href="https://github.com/k-takata/Onigmo">Onigmo</a></li>
<li>[6] <a href="http://tenderlovemaking.com/2011/06/29/i-want-dtrace-probes-in-ruby.html">DTrace</a></li>
</ul>
<br />
В 2.0.0 preview1 був включений <a href="http://bugs.ruby-lang.org/issues/7158">чарівних патч</a>, який прискорює роботу Rails в 2.2 рази<br />
<a name='more'></a><br /></div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-87108306988499142692013-01-19T18:10:00.000+02:002013-01-20T23:22:45.792+02:00Використовуємо life:) API за допомогою Ruby<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-NpJ63iLk_QY/UPq1DTcFYpI/AAAAAAAAL1s/32RDNUiPSRc/s1600/rubyloveslife.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="132" width="400" src="http://3.bp.blogspot.com/-NpJ63iLk_QY/UPq1DTcFYpI/AAAAAAAAL1s/32RDNUiPSRc/s400/rubyloveslife.png" /></a></div><br />
У цій статті я хочу розповісти Вам, як на мові Ruby налагодити взаємодію з life:) API. Для тих хто не в курсі, life:) — український GSM-оператор мобільного зв'язку.<br />
<br />
Все почалося тоді, що коли у офіційному твітері life:) з'явилося <a href="https://twitter.com/lifeua/status/278785580941324288">повідомлення</a> про додаток "Мій life:)" для Android. Мені відразу стало цікаво — а як вони отримують інформацію, якщо не через свій сайт системи самообслуговування для індивідуальних абонентів <a href="https://my.life.com.ua">Мій life:)</a>.<br />
<br />
Добрі люди підказали мені, як декомпілювати файл apk. Але це не тема цієї статті.<br />
<br />
Трохи покопавшись в горах Java-коду, мені вдалося зрозуміти за яким принципом здійснюється робота з сервісом life:). Варто зауважити, що офіційно нікого API у life:) немає. Тому все нижче написане використовуйте <i>на свій страх і ризик</i>.<br />
<br />
Результатом цієї роботи стала бібліотека для Ruby - <i>life-api</i>, яка реалізує деякі методи API. Ви можете знайти її на <a href="https://github.com/mamantoha/life-api">Github</a>.<br />
<br />
Отже, що нам знадобиться щоб виконувати запити?<br />
Розглянемо все по порядку.<br />
<br />
Всі запити, включаючи авторизацію виконується до адреси <a href="https://api.life.com.ua/mobile">https://api.life.com.ua/mobile</a>.<br />
З кожним запитом передається постійний ключ API <i>accessKeyCode</i>. А <i>applicationKey</i> використовується, як секретний ключ для підписання запиту. Про це трохи пізніше.<br />
<a name='more'></a><br />
А зараз просто визначимо ці три змінні:<br />
<pre class="brush:ruby">@access_key_code = '7'
@application_key = 'E6j_$4UnR_)0b'
@api_url = 'https://api.life.com.ua/mobile/'
</pre><br />
Для отримання токена потрібно передати методу <i>signIn</i> наступні параметри:<br />
<ul><li><i>msisdn</i> - номер телефону, що почитається з "380"</li>
<li><i>superPassword</i> - ваш суперпароль</li>
</ul>Пам'ятаєте, параметр <i>accessKeyCode</i> є обов'язковим для всіх методів.<br />
<br />
Також обов'язково необхідно підписати запит. Значення параметра <b>signature</b> рівне криптографічній хеш-функції HMAC(SHA1) від конкатенації наступних рядків:<br />
<ul><li>назва методу</li>
<li>пар <i>"parameter_name=parameter_value"</i></li>
<li>рядок "&signature="</li>
</ul><br />
Наступний метод повертатиме валідний url для запиту. У якості параметрів він отримує назву функції і хеш параметрів з парами <i>"ключ => значення"</i>.<br />
<pre class="brush:ruby">require 'openssl'
require 'base64'
def create_signed_url(method, params)
query = create_param(params)
str = method + '?' + query + '&signature='
digest = OpenSSL::Digest::Digest.new('sha1')
hash = OpenSSL::HMAC.digest(digest, @application_key, str)
hash = Base64.encode64(hash).chomp
str += hash
return @api_url + str
end
</pre><br />
Зверніть увагу на метод <i>create_param</i>, який перетворює хеш параметрів у текстовий рядок, придатний для використання в рядку запиту url.<br />
<pre class="brush:ruby">def create_param(params)
params.map do |key, value|
"#{key}=#{value}"
end.sort * '&'
end
</pre><br />
Наступний метод власне і виконує запит за допомогою вбудованої у Ruby бібліотеки 'net/https':<br />
<pre class="brush:ruby">require 'net/https'
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 => true) do |http|
http.request(request)
end
end
</pre><br />
Виконуємо запит для отримання токена:<br />
<pre class="brush:ruby">request('signId', { msisdn: '380631234567', superPassword: '1234'})
</pre><br />
Приклад запиту:<br />
<a href="https://api.life.com.ua/mobile/signIn?accessKeyCode=7&msisdn=380631234567&superPassword=1234&signature=KmLILbck40UJbCvlZMDOTtC2Z6o%3D">https://api.life.com.ua/mobile/signIn?accessKeyCode=7&msisdn=380631234567&superPassword=1234&signature=KmLILbck40UJbCvlZMDOTtC2Z6o%3D</a><br />
<br />
Приклад успішної відповіді від сервера у форматі XML:<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<response method="signIn"><responsecode>0</responseCode><token>ghkIU9j</token><subid>u4i7Qlh</subId></response>
</pre><br />
Після отримання токена взаємодія з іншими методами life:) API проводиться шляхом створення HTTP-запиту (GET) до адреси API-сервісу <a href="https://api.life.com.ua/mobile">https://api.life.com.ua/mobile</a>.<br />
<br />
На цьому все. Сподіваюся, я досить докладно описав кожний свій крок. Буду радий відповісти на Ваші запитання, якщо такі виникнуть.<br />
<br />
Дякую за увагу.Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com2tag:blogger.com,1999:blog-4152168096498110483.post-84332383936419549832013-01-08T11:41:00.001+02:002013-01-08T11:48:14.144+02:00Встановлення Windows XP на віртуальну машину KVM<div dir="ltr" style="text-align: left;" trbidi="on">
Процедури установки і налаштування хост-сервера не розглядається в рамках у цієї статті.<br />
<br />
Що дано:<br />
<ul style="text-align: left;">
<li>Хост-система Ubuntu Server 12.04 LTS</li>
<li>KVM</li>
<li>Гостьова система Windows XP</li>
</ul>
Під час інсталяції <i>Windows XP</i> на віртуальну машину <i>KVM</i> стикнувся з дуже низьким дисковим I/O. Метод спроб і помилок бажаний результат був досягнутий.<br />
<br />
Створення образу гостьової машини розміром 20 гігабайт у форматі <i>qcow2</i>. Серед підтримуваних форматів <i>QEMU</i>, цей — найбільш універсальний.<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>$ qemu-img create -f qcow2 -o preallocation=metadata winxp.qcow2 20G
</code></pre>
<br />
<i>Virtio</i> — це такі спеціальні драйвера, які безпосередньо прокидають фізичне залізо у віртуалку, без емуляції його. Власне це поввино зменшувати навантаження на хост-машину.<br />
<br />
У <i>Windows XP</i>, як відомо, немає драйверів <i>Virtio</i> і при установці виникає помилка через відсутність доступу до жорсткого диску.<br />
<br />
Для установки драйверів можете використати мій образ дискети <a href="https://docs.google.com/open?id=0B4P_mkC26xqHSDk3XzI1eEJjWUU">Virtio Disk Floppy</a>.<br />
Або створити його власноруч (чи оновити драйвери на дискеті) за допомогою найсвіжіших <a href="https://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/">Virtio Windows Drivers</a>:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>$ 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
</code></pre>
і скопіювати відповідні файли viostor з ISO на дискету, використовуючи мій образ в якості орієнтира.<br />
Для довідки:<br />
<i>wxp</i> — Windows XP<br />
<i>wnet</i> — Windows Server 2003<br />
<br />
Далі переходимо до інсталяції віртуальної машини:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>$ sudo virt-install -n winxp -r 1024 --disk path=winxp.qcow2,format=qcow2,bus=virtio,cache='writeback' --disk path=viostor-0.1-30-floppy.img,device=floppy -c winxp.iso --video=vmvga --accelerate --os-variant=winxp -v --vnc -w bridge:virbr0
</code></pre>
<a name='more'></a><i>-n winxp</i> — ім'я віртуальної машини;<br />
<i>-r 1024</i> — обсяг оперативної пам'яті(в мегабайтаз) для неї;<br />
<i>--disk path=winxp.qcow2,format=qcow2,bus=virtio,cache='writeback'</i> — шлях до файлу, який буде використовуватися в якості віртуального жорсткого диску для гостьової ОС. Зверніть увагу на опції <b>bus=virtio,cache='writeback'</b>;<br />
<i>--disk path=viostor-0.1-30-floppy.img,device=floppy</i> — образ дискети з драйверами, що підключається як віртуальний floppy;<br />
<i>-c winxp.iso</i> — образ CD гостьової ОС, що підключається як віртуальний cdrom<br />
<i>--video=vmvga</i> — вказуємо модель відео-карти (<a href="http://packages.vmware.com/tools/esx/latest/windows/index.html">Vmware Windows Tools ISO</a>);<br />
<i>--accelerate --os-variant=winxp -v</i> — прискорюємо, оптимізуємо ВМ для конкретної гостьової ОС і задіюємо апаратні можливості віртуалізації;<br />
<i>--vnc</i> — встановлюємо віртуальну консоль і експортуємо її як vnc-сервер;<br />
<i>-w bridge:virbr0</i> — вказуємо bridge-пристрій для приєднання до нього віртуальної мережевої карти.<br />
<br />
На початку інсталяції<i> Windows XP</i> натисніть клавішу F6, коли буде запропоновано вказати додаткові драйвери SCSI і натисніть "s" при появі запиту на системному диску. У графічній частині установки XP ви також повинні дати згоду на установку непідписаних драйверів для установки.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-q_3CWgDnMr8/UOb9BiDUoMI/AAAAAAAALno/BG3XjZFUjD4/s1600/winxpkvm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="http://3.bp.blogspot.com/-q_3CWgDnMr8/UOb9BiDUoMI/AAAAAAAALno/BG3XjZFUjD4/s400/winxpkvm.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-NOXWQQxLYL4/UOb9G17KkNI/AAAAAAAALn0/pLHOvuRIydA/s1600/winxpkvm1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="299" src="http://2.bp.blogspot.com/-NOXWQQxLYL4/UOb9G17KkNI/AAAAAAAALn0/pLHOvuRIydA/s400/winxpkvm1.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-ThToPt1bIiw/UOb9HfwbplI/AAAAAAAALoA/Ixw9rdyPfuU/s1600/winxpkvm2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="http://1.bp.blogspot.com/-ThToPt1bIiw/UOb9HfwbplI/AAAAAAAALoA/Ixw9rdyPfuU/s400/winxpkvm2.png" width="400" /></a></div>
</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-48290597242797642592012-12-31T10:52:00.000+02:002012-12-31T10:52:17.103+02:00Ретроспектива 2012<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://2.bp.blogspot.com/-iZzib4r8SDM/TvsoBY1UUAI/AAAAAAAAIG8/fksyZlCJ1Go/s1600/rubyxmas1.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="http://2.bp.blogspot.com/-iZzib4r8SDM/TvsoBY1UUAI/AAAAAAAAIG8/fksyZlCJ1Go/s1600/rubyxmas1.png" /></a><br />
<br />
2012 рік добігає кінця. І за хорошою традицією в останньому записі я згадую найбільш значущі події в світі Ruby, що відбулися у цьому році.<br />
<br />
Цього року формат статті зазнав деяких змін. Події розбиті по місяцях.<br />
<br />
Січень<br />
<ul style="text-align: left;">
<li>Випуск <a href="http://kidsruby.com/">KidsRuby</a> 1.0, редактора <i>Ruby</i> розробленого в освітніх цілях для дітей дошкільного й молодшого шкільного віку (але не менш корисного для дорослих). Він включає в себе навчальні посібники та графічну систему в стилі мови програмування <i>Logo</i> для більш наочного типу навчання.</li>
</ul>
<br />
Лютий<br />
<ul style="text-align: left;">
<li><a href="http://blog.phusion.nl/2012/02/21/ruby-enterprise-edition-1-8-7-2012-02-released-end-of-life-imminent/">Припинення розробки Ruby Enterprise Edition</a>.</li>
<li><a href="http://blog.jetbrains.com/ruby/2012/02/rubymine-4-is-here-to-make-you-feel-the-productivity/">Випуск RubyMine 4.0</a>, популярного середовища розробки для <i>Ruby</i> і <i>Rails</i>.</li>
</ul>
</div>
<br />
Березень<br />
<ul style="text-align: left;">
<li><a href="https://github.com/larskanis/fxruby">FXRuby</a> - Ruby bindings для FOX (крос-платформної бібліотеки з відкритим вихідним кодом для побудови графічного інтерфейсу) повернувся з довгого періоду застою.</li>
<li> Юкіхіро Мацумото (Yukihiro Matsumoto), автору мови програмування <i>Ruby</i>, <a href="https://www.fsf.org/news/2011-free-software-awards-announced" target="_blank">присуджена</a> премія "<a href="http://www.fsf.org/awards" target="_blank">Free Software Awards 2011</a>" номінації, що вручається за просування і розвиток вільного ПЗ.</li>
<li><i>Ruby</i> став стандартом <i>ISO</i>.<br />
Після чотирьох років розробки, 31 березня цього року за результатами голосування <i>Ruby</i> версії 1.8 був прийнятий як стандарт <i>ISO/IEC 30170</i>. Будемо сподіватися, що наступну версію стандарту підготують швидше.</li>
</ul>
Квітень<br />
<ul style="text-align: left;">
<li><a href="https://github.com/mruby/mruby" target="_blank">mruby</a> - полегшена реалізації мови <i>Ruby</i>, виконана за ISO стандартом для виконання різних середовищах. Може були як виконана інтерпретатором так і бути скомпільованою і виконаною віртуальною машиною, відповідно до його модульної конструкції.</li>
<li><a href="http://mobiruby.org/" target="_blank">MobiRuby</a> - інструментарій для створеня <i>IOS</i> додатків за допомогою мови <i>Ruby</i>. В майбутньому планується підтримка <i>Android</i>. </li>
</ul>
Травень<br />
<ul style="text-align: left;">
<li><i>Компанія Red Hat</i> запустила нову хмарну платформу <a href="https://openshift.redhat.com/" target="_blank">OpenShift</a> з підтримкою <i>Java</i>, <i>Ruby</i>, <i>Node</i>, <i>Python</i>, <i>PHP</i> і <i>Perl</i>.</li>
<li>Два ключових розробника команди <i>JRuby</i>(Thomas Enebo і Charles Nutter) <a href="http://www.rubyinside.com/jruby-redhat-5856.html" target="_blank">переходять</a> на роботу в <i>Red Hat</i>.</li>
<li>Перший попередній <a href="http://jruby.org/2012/05/21/jruby-1-7-0-preview1" target="_blank">реліз</a> <i>JRuby 1.7</i>. Цікавий тим, що це перший реліз з підтримкою <i>InvokeDynamic</i> - рішення, що дозволяє взаємодіяти з динамічними мовами практично без втрати продуктивності.</li>
<li>Реліз <a href="http://www.rubymotion.com/" target="_blank">RubyMotion</a> - набір інструментів для <i>IOS,</i> який дозволяє швидко розробляти і тестувати власні програми для <i>iPhone</i> або <i>iPad</i>, за допомогою <i>Ruby</i>.</li>
</ul>
Червень<br />
<ul style="text-align: left;">
<li><div>
Вийшла ювілейна версія 1.0 бібліотеки <a href="https://github.com/ai/r18n" target="_blank">R18n</a>, яка дозволяє додати в додаток на Rails/Ruby підтримку декількох мов (i18n).</div>
</li>
<li><a href="http://www.sublimetext.com/blog/articles/sublime-text-2-0-released" target="_blank">Реліз Sublime Text 2.0</a></li>
</ul>
Вересень<br />
<ul style="text-align: left;">
<li><a href="http://www.codecademy.com/ru/tracks/ruby" target="_blank">Курс по Ruby на Codecademy</a></li>
</ul>
<br />
Жовтень<br />
<ul style="text-align: left;">
<li><a href="http://jruby.org/2012/10/22/jruby-1-7-0.html" target="_blank">Реліз</a> JRuby 1.7</li>
<li><a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46258" target="_blank">Оголошено</a> 'Feature Freeze' для Ruby 2.0</li>
<li><a href="https://blog.engineyard.com/2012/rvm-1-16/" target="_blank">Резіл</a> RVM 1.16 з можливістю встановлення бінарних версій Ruby</li>
</ul>
Листопад<br />
<ul style="text-align: left;">
<li><div>
<a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46348" target="_blank">Анонсований</a> Ruby 2.0.0 preview1</div>
</li>
<li><a href="http://blog.phusion.nl/2012/10/30/phusion-passenger-4-0-supports-jruby-rubinius/#.UJUjzrQX7UI" target="_blank">Реліз</a> Phusion Passenger 4.0 з підтримкою JRuby і Rubinius</li>
</ul>
Грудень<br />
<ul style="text-align: left;">
<li>Heroku <a href="http://blog.heroku.com/archives/2012/12/13/run_jruby_on_heroku_right_now/" target="_blank">додали</a> офіційну підтримку для JRuby</li>
</ul>
<br />
2013 рік обіцяє також бути багатим на нові релізи. Зокрема Ruby 2.0 і Rails 4.0.<br />
<br />
Щиро вітаю Вас з наступаючим Новим Роком!<br />
Нехай він принесе нам довгождане щастя, спокій, добробут, палке кохання, міцне здоров'я та здійснення наших самих заповітних мрій!<br />
<ul style="text-align: left;"></ul>
</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-70382417519559188172012-12-28T13:54:00.001+02:002013-01-27T12:23:18.955+02:00Історія одного тупняку, або як я конвертував DBF в SQLite3<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-GWZdCTWWBfU/UQT-cad3CaI/AAAAAAAAL2A/p0h4ZIBHnTI/s1600/10814.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-GWZdCTWWBfU/UQT-cad3CaI/AAAAAAAAL2A/p0h4ZIBHnTI/s320/10814.png" width="320" /></a></div>
Нещодавно до мене потрапив файл у форматі <i>dbf</i> з досить цікавою інформацією. Але сьогодні не про це.<br />
<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
Для роботи з цією інформацією, я вирішив імпортувати таблицю <i>DBF</i> у <i>SQLite3</i>. Використовувати сторонній софт для такої тривіальної задачки — це не наш варіант. Ми не шукаємо легких шляхів. Напишемо скрипт самі. Писати, звичайно, будемо на <i>Ruby</i>.<br />
<br />
<blockquote>
<i>DBF</i> — застаріваючий формат зберігання даних, який (був?) широко розповсюджений на пострадянському просторі.</blockquote>
<br />
Недовгі пошуки навели на бібліотеку <a href="https://github.com/infused/dbf">dbf</a>. Як описує її автор, це невелика швидка бібліотека для читання <i>DBase</i>, <i>Xbase</i>, <i>Clipper</i> і <i>FoxPro</i> файлів баз даних.<br />
<br />
Відкриваємо <i>DBF</i> файл:<br />
<pre class="brush:ruby">require 'dbf'
dbf_table = DBF::Table.new(dbf_file, nil)
dbf_columns = dbf_table.columns
</pre>
І відразу отримуємо помилку:<br />
<pre class="brush:ruby">dbf-2.0.3/lib/dbf/column/base.rb:19:in `initialize': column name cannot be empty (DBF::Column::NameError)
</pre>
<br />
Проблема виникає через те, що при <a href="https://github.com/infused/dbf/blob/master/lib/dbf/column/base.rb#L15">ініціалізації</a> поля, у його назві відсікаються всі не-ASCII символи. А такий порядок речей в моєму випадку недопустимий, оскільки<br />
імена полів у <i>DBF</i> таблиці записані кирилицею у кодуванні <i>cp1251</i>.<br />
<br />
Тут стане у нагоді "monkey patching".<br />
Ініціалізуємо таблицю у кодуванні cp1251 і конверуємо імена полів в utf-8:<br />
<br />
<pre class="brush:ruby">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, "field length must be greater than 0" unless length > 0
raise NameError, "column name cannot be empty" if @name.length == 0
end
def clean(value, encoding)
value.force_encoding(encoding).encode('utf-8')
end
end
end
end
dbf_table = DBF::Table.new(dbf_file, nil, 'cp1251')
dbf_columns = dbf_table.columns
</pre>
<br />
Не вдаючись в подробиці створення схеми <i>SQLite3</i> (повний код скрипта Ви знайдете в кінці статті), перейдемо відразу до імпорту. Задачка звичайно зовсім тривіальна і написання рішення займає лічені хвилини.<br />
<pre class="brush:ruby">dbf_table.each do |record|
sqlite_db.execute("INSERT INTO the_table VALUES (?,?,?,?,?,?)", record.attributes.values)
end
</pre>
Тут можна було б піти покурити, попити чаю або кави чи навіть подивитися фільм. Даний процес зайняв досить багато часу.<br />
Час роботи такого рішення мене не вдовольняв зовсім.<br />
Бувалі програмісти мабуть відразу зрозуміють де собака зарита. Але цей тупняк поглинув мене на кілька годин.<br />
Спочатку я грішив на повільність бібліотеки <i>dbf</i>. Але цей варіант був швидко відкинутий. Каменем спотикання була саме бібліотека <i>SQLite3</i>.<br />
Наступну годину я курив, пив пиво і дивився "Ruby Sparks". Між іншим красивий і милий романтичний фільм, але настирливий продакт-плейсмент Apple вже бісить. Паралельно ґвалтува ґуґл в пошуках рішення. І ось воно зійшло:<br />
<pre class="brush:ruby">sql_db.transaction do |db|
dbf_table.each do |record|
db.execute("INSERT INTO the_table VALUES (?,?,?,?,?,?)", record.attributes.values)
end
end
</pre>
<br />
Несподівано скрипт, який виконувався годинами, виконався за 10 секунд. Підвищення продуктивності over 9000%. Я отетерів(!) від такого результату.<br />
<br />
Мораль цієї історії проста... Комусь здається, що це тривіально, але мені просто хотілось поділитися з кимось цими думками.<br />
<br />
Нище ви знайдете повну версію скрипта для конвертування <i>DBF</i> у <i>SQLite3</i>.<br />
<a name='more'></a><br />
<script src="https://gist.github.com/4397089.js"></script></div>
</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-18206945433529489062012-12-27T17:31:00.002+02:002013-01-27T12:22:30.468+02:00Робота з файлами eml в Ruby<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-YvP-vi2ClZU/UQT_lWitIiI/AAAAAAAAL2U/ZPRTBFhHjdk/s1600/10821.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="http://1.bp.blogspot.com/-YvP-vi2ClZU/UQT_lWitIiI/AAAAAAAAL2U/ZPRTBFhHjdk/s320/10821.png" width="320" /></a></div>
Сьогодні зіткнувся з проблемою пошуку вкладень серед багатьох файлів з розширенням <i>eml</i>.<br />
<br />
<blockquote>
Формат <i>eml</i> використовується багатьма клієнтами електронної пошти, включаючи Microsoft Outlook Express, Windows Mail і Mozilla Thunderbird. Це звичайний текстовий файл у форматі MIME, що містять заголовки повідомлень електронної пошти, а також вміст повідомлення та вкладення.</blockquote>
<br />
Відкрити його під Linux не складає труднощів, наприклад, за допомогою поштового клієнта KMail, однак таке рішення мені здалося занадто складним.<br />
<br />
Трохи погугливши, виявилося, що бібліотека <a href="https://github.com/mikel/mail">email</a> чудово вміє розбирати такі файли.<br />
<br />
В результаті вийшов невеликий скрипт, який вибирає всі файли з розширенням eml у поточній директорії, і відображає в консолі текстовий вміст листа, а прикріплені файли зберігає у відповідних директоріях.<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>require 'mail'
Dir.glob('*.eml') do |filename|
mail = Mail.read(filename)
puts <<EOF
From: #{mail.from}
To: #{mail.to}
Subject: #{mail.subject}
Date: #{mail.date}
EOF
charset = mail.text_part.content_type_parameters['charset']
puts mail.text_part.body.decoded.force_encoding(charset).encode('utf-8')
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 + '/' + attachment.filename, 'wb') { |f| f.write attachment.body.decoded }
puts "Saving `#{attachment.filename}`"
end
end
puts "===\n\n"
end
</code></pre>
</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-27352403130556390452012-10-29T15:55:00.000+02:002012-10-29T15:55:31.186+02:00Opal — реалізація Ruby на JavaScript<a href="http://opalrb.org/">Opal</a> — реалізація Ruby, написана на мові JavaScript.<br />
<br />
Opal включає в себе компілятор (який можна запустити в будь-якому браузері), основну бібліотеку і середовища виконання. У стисненому вигляді основна бібліотека і середовище виконання займають всього-на-всього 10.8kb.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-_M6qmxBfNpw/UI6JX5CPkbI/AAAAAAAALl0/0aCZmHdJkLQ/s1600/opalweb.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="268" width="400" src="http://3.bp.blogspot.com/-_M6qmxBfNpw/UI6JX5CPkbI/AAAAAAAALl0/0aCZmHdJkLQ/s400/opalweb.png" /></a></div>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-28826932659330792372012-10-26T15:51:00.000+03:002012-11-06T11:00:35.128+02:00Оголошено 'Feature Freeze' для Ruby 2.0<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-TruO9uDr-1Y/UJjRg6Dll-I/AAAAAAAALm8/WZxXmYiR9hQ/s1600/ruby_yula.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="http://1.bp.blogspot.com/-TruO9uDr-1Y/UJjRg6Dll-I/AAAAAAAALm8/WZxXmYiR9hQ/s1600/ruby_yula.png" /></a></div>
Точно за розкладом, основна команда Ruby <a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/46258">оголосила</a> про заморожування коду нових можливостей('feature freeze') майбутнього<i> Ruby 2.0</i>. Це означає, що з цього моменту розробники лише будуть виправляти баги, не додаючи нових фіч в дану версію.<br />
<br />
Нижче я збираюся представити переклад статті "<i>Things to Look Forward to in Ruby 2.0</i>" у якій автор перерахував декілька нових можливостей Ruby 2.0.<br />
<a name='more'></a><br />
<br />
<h3>
Комбінація методів map/select</h3>
<blockquote>
Ця можливість не ввійшла до Ruby 2.0 (<i>прим. перекладача</i>).</blockquote>
Припустимо, ви хочете виконати метод <i>map</i> для <i>Enumerable</i> і отримати тільки ті елементи, які відповідають певним критеріям.<br />
Ви можете зробити це одним із цих двох способів:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>[1,2,3,4].select(&:even?).map {|i| i + 1}
==> [3, 5]
</code></pre>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>[1,2,3,4].map { |i| i + 1 if i.even? }.compact
==> [3, 5]
</code></pre>
<br />
Ідея полягає в тому, щоб мати один метод, який поєднує в собі ці два. Його ім'я до цих пір не визначене, але <i>filter_map</i> здається можливим вибором.<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>[1,2,3,4].filter_map { |i| i + 1 if i.even? }
==> [3, 5]
</code></pre>
<br />
Так як я не хочу чекати, я вирішив зробити версію для бідних, але дати їй інше ім'я.<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>module Enumerable
def map_selected(&block)
map(&block).compact!
end
end
</code></pre>
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>[1,2,3,4].map_selected { |i| i + 1 if i.even? }
==> [3, 5]
</code></pre>
<br />
<a href="http://bugs.ruby-lang.org/issues/5663">Ruby feature #5663</a><br />
<br />
<h3>
Іменовані аргументи функцій</h3>
Мені їх не вистачає з тих пір, як я дізнався, що вони є в <i>Smalltalk</i>. Потім, на мій жах я зрозумів, що вони є в <i>Lisp</i>, <i>Clojure</i> і навіть в <i>Python</i>.<br />
<br />
Звичайно, ви можете підробити іменовані аргументи за допомогою хешу, але приємніше мати підтримку з коробки:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>def foo_bar(name: 'foo', last_name: 'bar')
print "#{name} #{last_name}"
end
foo_bar ==> foo bar
foo_bar last_name: 'baruco' ==> foo baruco
foo_bar last_name: 'baruco', name:'hello' ==> hello baruco
</code></pre>
<br />
<a href="http://bugs.ruby-lang.org/issues/5474">Ruby feature #5474</a><br />
<a href="http://ruby-dev.info/posts/44602">Ruby feature #5454 translation</a><br />
<br />
<blockquote>
Про іменовані аргументи функцій в <i>Ruby 2.0</i> я раніше <a href="http://ruby-ua.blogspot.com/2012/01/ruby-20.html">писав</a> у цьому блозі.</blockquote>
<br />
<h3>
Змінна екземпляру присвоюється об'єкту під час створення</h3>
Це частий випадок можна буде скоротити на два рядки:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>class FooBar
def initialize(name, last_name)
@name = name
@last_name = last_name
end
def to_s
"#@name #@last_name"
end
end
print FooBar.new('foobar', 'rulez')
=> foobar rulez
</code></pre>
<br />
Ось так:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>class FooBar
def initialize(@name, @last_name)
#nice isn't it?
end
def to_s
"#@name #@last_name"
end
end
print FooBar.new('foobar', 'rulez')
=> foobar rulez
</code></pre>
<br />
Я впевнений, що будуть ситуації, коли така поведінка стане в нагоді. Функція йде від <i>CoffeScript</i>, наскільки я можу судити. Для <i>Ruby 1.8.7</i> стане у нагоді наступний трюк:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>define_method(:intialize){|@name, @last_name|}
</code></pre>
<br />
<a href="http://bugs.ruby-lang.org/issues/5825">Ruby feature #5825</a><br />
<br />
>>> <a href="http://kresimirbojcic.com/2012/08/23/things-to-look-forward-to-in-ruby-2-dot-0.html">Оригінал статті</a><br />
<br />
Не менш цікавою можливістю у новому <i>Ruby</i> є метод <i>Enumerable#lazy</i>, про який я <a href="http://ruby-ua.blogspot.com/2012/03/ruby-20-enumeratorlazy.html">писав</a> у цьому блозі.<br />
Докладніше про <i>Enumerable#lazy</i>: <a href="http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/">англійською</a> і <a href="http://habrahabr.ru/post/140362/">російською</a>.<br />
<br />
Про всі зміни які відбулися після <i>1.9.3</i> ви можете почитати <a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/NEWS?revision=37126&view=markup">тут</a>. Їх небагато, і ваш код, написаний для <i>1.9.3</i> буде справно працювати і на <i>2.0.0</i>.<br />
<br /></div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-20929928229889864622012-10-23T22:00:00.004+03:002012-10-23T22:00:48.447+03:00Ruby Bits.Частина 2<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-cRTCyaI2heg/UIbhcUPRmkI/AAAAAAAALlY/QD737bJfFVY/s1600/Ruby_Bits_2_Banner.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-cRTCyaI2heg/UIbhcUPRmkI/AAAAAAAALlY/QD737bJfFVY/s1600/Ruby_Bits_2_Banner.png" /></a></div>
<br />
Для багатьох не секрет, що Ruby — це потужна мова програмування. Але чи використовуєте ви її в повній мірі?<br />
У другій частині курсу від Code School ви зможете познайомитися з найбільш корисними можливостями метапрограмування у Ruby.<br />
<br />
У цьому курсі ви дізнаєтеся про:<br />
<ul style="text-align: left;">
<li>Використання Procs і лямбда для зберігання і виконання блоків коду</li>
<li>Різні способи для передачі блоків у методи</li>
<li>Як використовувати необов'язкові блоки</li>
<li>Динамічне визначення та виклик методів</li>
<li>Відповідь на неіснуючі методи</li>
<li>Управління контекстом, в якому виконується код</li>
</ul>
<br />
В кінці курсу, ви зможете використовувати вивчені можливості для побудови Domain Specific Languages(DSL).<br />
<br />
>>> <a href="http://www.codeschool.com/courses/ruby-bits-part-2" target="_blank">Перейти до курсу</a></div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-75285909964521991402012-10-23T12:26:00.000+03:002012-10-23T12:26:19.900+03:00Реліз JRuby 1.7.0<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-lTlLiR36eZc/UIZUcM5UdWI/AAAAAAAALlE/gRYkJlN52gU/s1600/jruby-logo-sm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-lTlLiR36eZc/UIZUcM5UdWI/AAAAAAAALlE/gRYkJlN52gU/s1600/jruby-logo-sm.png" /></a></div>
<br />
Спільноті JRuby рада <a href="http://jruby.org/2012/10/22/jruby-1-7-0.html" target="_blank">оголосити</a> про випуск JRuby 1.7.0, починаючи з якої заявлена офіційна підтримка Ruby 1.9.x.<br />
<ul style="text-align: left;">
<li>Домашня сторінка: <a href="http://www.jruby.org/">http://www.jruby.org/</a></li>
<li>Завантажити: <a href="http://www.jruby.org/download">http://www.jruby.org/download</a></li>
</ul>
<br />
Після півтора років розробки вийшов мажорний реліз відкритої багатоплатформної реалізації інтерпретатора мови програмування Ruby, написаної цілком на Java.<br />
<br />
В JRuby 1.7 проведений величезний обсяг робіт, десятки учасників, і покращення у кожній підсистемі. І тепер за замовчуванням JRuby працює у режимі сумісності Ruby 1.9.3. Втім, не означає, що реалізація не буде більше вдосконалюватися. Це означає лише, що в майбутньому будуть вирішуватися проблеми з якими зіткнуться користувачі. На даний момент, розробники планують випускати нові версії 1.7.x кожні 2-3 тижні.<br />
<br />
1.7 є першим стабільним JRuby з підтримкою нової можливості JVM - <em>invokedynamic</em>. Ви можете включити використання <em>invokedynamic</em> для Java 7, але вона по замовчуванню відключена, через проблему в JVM. На Java 8 , вона включений за умовчанням: <a href="http://wiki.jruby.org/PerformanceTuning">http://wiki.jruby.org/PerformanceTuning</a>.<br />
<br />
Що нового:<br />
<ul style="text-align: left;">
<li>Режим сумісності з 1.9.3 тепер використовується по замовчуванню(1.8 необхідний для підтримки 1.8.7)</li>
<li>Стандартна бібліотека оновлена до 1.9.3p286</li>
<li>Багато виправлень сумісності з 1.9.x</li>
<li>Підтримка invokedynamic</li>
<li>Численні покращення продуктивності</li>
<li>Припинена підтримка Java 5(тепер обов'язкова Java 6+).</li>
<li>Вирішені всі відомі проблеми з кодуваннями у 1.9</li>
<li>Покращення і виправлення для Java інтеграції</li>
<li>Краща підтримка для Solaris, ARM Linux.</li>
<li>Оновлення до Rubygems 1.8.24</li>
<li>Оновлення до Rake 0.9.2.2</li>
</ul>
</div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-77215197630407904732012-10-13T16:20:00.000+03:002012-10-26T11:58:52.437+03:00Ruby 1.9.3-p286<div dir="ltr" style="text-align: left;" trbidi="on">Новий реліз включає в себе виправлення кількох критичних помилок, і не містить нових можливостей.<br />
Докладніше на <a href="http://www.ruby-lang.org/en/news/2012/10/12/ruby-1-9-3-p286-is-released/">офіційній сторінці</a>.<br />
<br />
Для Linux:<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>$ 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):
</code></pre></div><br />
Для Windows доступний для завантаження <a href="http://rubyinstaller.org/downloads">RubyInstaller 1.9.3-p286</a>.<br />
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com2tag:blogger.com,1999:blog-4152168096498110483.post-1198562484883063282012-10-09T14:17:00.000+03:002012-10-11T11:57:55.881+03:00Курс по Ruby на Codecademy<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-A-QZxvlukoc/UHaJue3UD0I/AAAAAAAALcs/ayQliP1_LDA/s1600/F-DdQbpJKSM.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="http://2.bp.blogspot.com/-A-QZxvlukoc/UHaJue3UD0I/AAAAAAAALcs/ayQliP1_LDA/s1600/F-DdQbpJKSM.jpg" /></a></div>
На навчальному порталі <a href="http://www.codecademy.com/ru/tracks/ruby">Codecademy</a> з'явився курс з мови програмування Ruby.<br />
<br />
Курс інтерактивний, інтерпретатор працює прямо в браузері. Складається з більше сотні вправ, розбитих на 5 блоків. Частина вправ кожного блоку ввідні, а частина - приклад реалізації найпростіших додатків.<br />
<br />
Курс можна рекомендувати, тим, хто тільки починає вивчення Ruby.<br />
<br />
Курс на англійській, але на простій і зрозумілій.<br />
<br />
<br /></div>
Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-73069723789343250482012-08-15T12:33:00.001+03:002012-08-15T12:33:30.212+03:00Стилізація sinatra-flash для BootstrapПро гем <a href="https://github.com/SFEley/sinatra-flash">sinatra-flash</a>, я писав у статті <a href="http://ruby-ua.blogspot.com/2011/07/flash-sinatra.html">Flash-повідомлення і Sinatra</a> <br />
Задачею є створити замість стандартного <i>styled_flash</i>, методу-помінчника для Sinatra, який відображатиме <a href="http://twitter.github.com/bootstrap/components.html#alerts">попередження</a> стилізовані під <i>Bootstrap</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-TbyAuxVdRig/UCtsd20s0oI/AAAAAAAALGI/qhJTQ2YuIhA/s1600/alert.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="60" width="377" src="http://1.bp.blogspot.com/-TbyAuxVdRig/UCtsd20s0oI/AAAAAAAALGI/qhJTQ2YuIhA/s400/alert.png" /></a></div><br />
<script src="https://gist.github.com/3358074.js?file=style.rb"></script>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-65100245618942185872012-08-14T00:14:00.001+03:002012-08-14T00:14:20.999+03:00Як зробити локальий веб-сервер загальнодоступнимСьогодні відкрив для себе чудовий сервіс, який дозволяє швидко і просто зробити локальний веб-сервер загальнодоступним в Інтернеті.<br />
<br />
<h3>Зустрічайте ProxyLocal</h3>Це програмне забезпечення складається з клієнтської і серверної частин. Серверна частина працює на сервері <a href="http://proxylocal.com/">proxylocal.com</a>, і ви можете використання його ресурси абсолютно безкоштовно. Клієнт написаний на мові <i>Ruby</i> і поширюється як <i>gem</i>, його вихідний код відкритий і доступний на <a href="https://github.com/proxylocal/proxylocal-gem">GitHub</a>.<br />
<br />
<h3>Інсталяція</h3><i>ProxyLocal</i> - це утиліта командного рядка.<br />
<br />
Відкрийте термінал і наберіть:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>$ gem install proxylocal
</code></pre><br />
<h3>Використання</h3>Припустимо, ваш локальний веб-сервер запущений на порту 9292. Щоб зробити його загальнодоступним виконайте в терміналі:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>$ proxylocal 9292
Local server on port 9292 is now publicly available via:
http://o18f.t.proxylocal.com/
</code></pre><br />
Тепер ваш локальний сервер на порту 9292 доступний через:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>http://o18f.t.proxylocal.com/
</code></pre><br />
Також ви можете вказати бажане ім'я, яке ви хочете використовувати, наприклад:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>$ proxylocal 9292 --host testhost
Local server on port 9292 is now publicly available via:
http://testhost.t.proxylocal.com/
</code></pre>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-27989524732221448332012-07-03T17:19:00.000+03:002012-07-03T17:19:09.862+03:00ВКонтакте → Авторизація додатків з Ruby і Net::HTTPНа днях виникло бажання переписати код своєї <a href="https://github.com/mamantoha/vkontakte">бібліотеки</a> для для авторизації ВКонтакте і здійснення запитів до API, використовуючи тільки стандартні модулі Ruby.<br />
<br />
Для того, щоб прикинутися справжнім браузером, просто завантажувати потрібні сторінки недостатньо. Як мінімум, потрібно коректно обробляти куки і редіректи. Для цього у <a href="http://ruby-ua.blogspot.com/2011/06/standalone-oauth-20-ruby-mechanize.html">попередній статі</a> я використовував чудову бібліотеку <i>Mechanize</i>.<br />
<br />
Спочатку встановимо необхідні параметри.<br />
<script src="https://gist.github.com/3039674.js?file=1_params.rb"></script><br />
Детально про параметри звернення можна прочитати в <a href="http://vk.com/developers.php?id=-1_37230422&s=1">документації</a>.<br />
<i>client_id</i> - ідентифікатор вашого додатку.<br />
Тут слід зазначити, що ми будемо використовувати параметр <i>display</i> із значенням <i>wap</i>, так в цьому варіанті сторінки практично відсутній JavaScript.<br />
<i>scope</i> являє собою <a href="http://vk.com/developers.php?oid=-1&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">список прав</a>, до яких ми хочемо отримати доступ.<br />
<br />
<h3>Звертаємося до сторінки авторизації</h3><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-RurwOBWRKD0/T_LskjyxZJI/AAAAAAAAK3Q/3V_26fStfsw/s1600/1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="154" width="400" src="http://4.bp.blogspot.com/-RurwOBWRKD0/T_LskjyxZJI/AAAAAAAAK3Q/3V_26fStfsw/s400/1.png" /></a></div><script src="https://gist.github.com/3039674.js?file=2_auth_page.rb"></script><br />
<br />
<h3>Парсимо відповідь</h3><br />
Подивимося на код сторінки авторизації. Найбільше нас буде цікавити наступна частина:<br />
<script src="https://gist.github.com/3039674.js?file=3_login_form.html"></script><br />
<br />
Для подальшої відправки форми необхідно розпарсити всі input'и (и тому числі і приховані), а також URL, на який сабмітиться форма.<br />
<script src="https://gist.github.com/3039674.js?file=4_parse_form.rb"></script><br />
<br />
<h3>Авторизуємось</h3><br />
Підставляємо в параметри запиту електронну пошту та пароль користувача і відправляємо форму:<br />
<script src="https://gist.github.com/3039674.js?file=5_authorization.rb"></script><br />
<br />
<h3>Отримуємо куку</h3><br />
<script src="https://gist.github.com/3039674.js?file=6_get_cookie.rb"></script><br />
<br />
<h3>Встановлюємо куку</h3><br />
<script src="https://gist.github.com/3039674.js?file=7_set_cookie.rb"></script><br />
<br />
<h3>Отримуємо код</h3><br />
Наступним етапом, якщо користувач цього ще не робив, треба дати додатку ті права, які ми запитували в параметрі <i>scope</i>. Для цього нам буде запропонована сторінка з формою.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-zQITX2mXoh8/T_Lsv6PePtI/AAAAAAAAK3c/edVGL26kbFQ/s1600/2.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="219" width="400" src="http://2.bp.blogspot.com/-zQITX2mXoh8/T_Lsv6PePtI/AAAAAAAAK3c/edVGL26kbFQ/s400/2.png" /></a></div><br />
В результаті отримуємо відповідь наступного вигляду:<br />
<i>http://oauth.vk.com/blank.html#code=xxxxxxxxxxxxxxxxxx</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-PjcxkxJ2uKQ/T_LszQGVm8I/AAAAAAAAK3o/udy1s10m9SM/s1600/3.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="71" width="400" src="http://3.bp.blogspot.com/-PjcxkxJ2uKQ/T_LszQGVm8I/AAAAAAAAK3o/udy1s10m9SM/s400/3.png" /></a></div><script src="https://gist.github.com/3039674.js?file=8_get_code.rb"></script><br />
<br />
Даний метод авторизації не є офіційним і може змінитися.Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-84031902510905577502012-05-22T23:21:00.001+03:002012-05-22T23:26:51.467+03:00CarrierWave з DataMapper у SinatraУ вільний час займаюся розробкою веб-додатку на <i>Sinatra</i> з використанням <i>DataMapper</i>. І ось задався питанням завантаження аватарів на сервер та їх після-обробкою.<br />
<br />
Переглянувши доступні <a href="https://www.ruby-toolbox.com/categories/rails_file_uploads">інструменти</a> для забезпечення цієї функціональності, вибір впав на бібліотеку <a href="https://github.com/jnicklas/carrierwave">CarrierWave</a>, яка на відміну від більшості інших не зав'язана на <i>Rails</i>/<i>ActiveRecord</i>.<br />
<br />
<i>CarrierWave</i> описує себе, як "першокласне рішення для завантаження файлів для <i>Rails</i>, <i>Sinatra</i> та інших веб-додатків на основі <i>Rack</i>". Проект був започаткований у серпні 2008 року, і перший випуск відбувся в березні 2009 року. Перша його назва була <i>Merb::Upload</i> і він був без підтримки <i>Rails</i>.<br />
<br />
Той факт, що <i>CarrierWave</i> почав своє життя в якості плагіна для <i>Merb</i> може пояснити його модульність, гнучкість і розширюваність.<br />
<br />
Завдяки <a href="https://github.com/fog/fog">fog</a>, він має підтримку <i>Amazon S3</i>, <i>Rackspace Cloud Files</i> і <i>Google Storage for Developers</i>. Він також підтримує звичайне зберігання файлів і <i>GridFS</i> в <i>MongoDB</i>.<br />
Має підтримку незліченної кількості ORM: <i>ActiveRecord</i>, <i>Mongoid</i>, <i>DataMapper</i>, <i>Sequel</i>, <i>MongoMapper</i>, <i>CouchDB</i>.<br />
Обробка зображення доступна засобами <i>RMagick</i>, <i>ImageScience</i> або <i>MiniMagick</i>.<br />
Сама по собі ця бібліотека дуже добре документована, і якщо раптом когось цікавлять деталі, то читайте <a href="https://github.com/jnicklas/carrierwave/wiki">wiki</a>.<br />
<br />
У цій статті для прикладу ми напишемо просту фотогалерею.<br />
Наступні gem`и повинні бути встановлені:<br />
<ul><li>sinatra</li>
<li>datamapper</li>
<li>dm-sqlite-adapter</li>
<li>slim</li>
<li><i>carrierwave</i> - для завантаження зображень</li>
<li><i>carrierwave-datamapper</i> - для зв'язку <i>DataMapper</i> і <i>CarrierWave</i></li>
<li><i>rmagick</i> - для створення мініатюр зображень(в Ubuntu потрібно встановити пакет <i>libmagick++-dev</i>)</li>
</ul><br />
<a name='more'></a><br />
Налаштування підключення до бази даних і створення таблиці для зберігання інформації про зображення у галереї.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/photogallery.sqlite3")
class Image
include DataMapper::Resource
property :id, Serial
property :title, Text
end
DataMapper.auto_upgrade!
</code></pre><br />
Налаштування <i>CarrierWave</i>. Для того щоб він правильно працював потрібно також встановити gem <i>carrierwave-datamapper</i> і <i>rmagick</i>.<br />
<br />
Клас завантажувача успадкований від <i>CarrierWave::Uploader::Base</i>:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :file
process :resize_to_fit => [800, 800]
version :thumb do
process :resize_to_fill => [200, 200]
end
def store_dir
'uploads'
end
def extension_white_list
%w(bmp gif jpg jpeg png)
end
end
</code></pre>Для того, щоб змінити розташування завантажених файлів необхідно просто перевизначити метод <i>store_dir</i>. А також створити каталог <i>'public/uploads'</i>.<br />
<br />
Метод <i>extension_white_list</i> визначає, які розширення файлів дозволені для завантаження.<br />
<br />
При завантаженні зображення буде масштабуватися не більше ніж 800 на 800 пікселів. А його мініатюрна версія <i>:thumb</i> буде масштабована і обрізана рівно 200 на 200 пікселів.<br />
<br />
Завантажувач може бути використаний наступним чином:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>uploader = ImageUploader.new
uploader.store!(my_file) # розмір: 1024x768
uploader.url # => '/url/to/my_file.png' # розмір: 800x600
uploader.thumb.url # => '/url/to/thumb_my_file.png' # розмір: 200x200
</code></pre><br />
З'єднання моделі <i>DataMapper</i> із завантажувачем <i>CarrierWave</i> за допомогою методу <i>mount_uploader</i>:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>class Image
include DataMapper::Resource
property :id, Serial
property :title, Text
mount_uploader :image, ImageUploader
end
</code></pre><br />
Маршрути:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>get '/' do
@images = Image.all
slim :index
end
post '/' do
image = Image.new(:title => params[:title])
image.image = params[:image]
image.save
redirect '/'
end
</code></pre><br />
Шаблон <i>Slim</i>. Мініатюри усіх завантажених зображень і форма для додавання нових:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>__END__
@@ index
- @images.each do |i|
p
= i.title
a href="#{i.image.url}"
img src="#{i.image.thumb.url}"
form action='/' method='post' enctype='multipart/form-data'
fieldset
p
label for='title' Title:
input name='title' type='text'
p
label for='image' Image:
input name='image' type='file'
p
input type='submit' value='Save'
</code></pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/--9NUVa02awE/T7vxRsyV1XI/AAAAAAAAKt4/-AIac4d-yjY/s1600/wave.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="365" src="http://1.bp.blogspot.com/--9NUVa02awE/T7vxRsyV1XI/AAAAAAAAKt4/-AIac4d-yjY/s400/wave.png" /></a></div><br />
Весь код можна подивитись на <a href="https://gist.github.com/2771347">GitHub</a>.<br />
<br />Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-91914033921718689632012-05-18T16:52:00.001+03:002012-05-19T19:38:54.821+03:00Розгортання додатку Sinatra на OpenShift<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-Chi_Bv8jUXs/T7ZIuBnMpsI/AAAAAAAAKqY/qJKxIXkh4YM/s1600/OpenShift-Logo.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"><img border="0" height="288" width="269" src="http://1.bp.blogspot.com/-Chi_Bv8jUXs/T7ZIuBnMpsI/AAAAAAAAKqY/qJKxIXkh4YM/s400/OpenShift-Logo.png" /></a></div><i>Red Hat OpenShift</i> - це нова, вільно-масштабована "платформа як послуга(Platform as a service, PaaS) для розробки веб-додатків. На даний момент підтримує <i>Java</i>, <i>Ruby</i>, <i>Node</i>, <i>Python</i>, <i>PHP</i> і <i>Perl</i>.<br />
<br />
Картриджі - це компоненти додатку <i>OpenShift</i>, які включають в себе бази даних(<i>MySQL</i>, <i>PostgreSQL</i>, <i>MongoDB</i>) та інші утиліти(<i>Cron</i>, <i>phpMyAdmin</i>, <i>RockMongo</i>, <i>OpenShift Metrics</i>). Додавання картриджа у додаток забезпечує бажану функціональність.<br />
<br />
Для початку необхідно зареєструватися на сайті <a href="https://openshift.redhat.com">https://openshift.redhat.com</a> і створити новий додаток.<br />
Вибрати тип додатку(в нашому випадку це <i>Ruby 1.8.7</i>). Вказати ім'я додатку і простір імен.<br />
Вітання, тепер ви у хмарах!<br />
Новий додаток буде доступний за <i>URL</i> виду:<br />
<a href="#">http://<ім'я додатку>-<простір імен>.rhcloud.com</a><br />
<br />
<i>OpenShift</i> використовує розподілену система керування версіями коду <i>Git</i>. Коли ви внесете зміни у віддалений репозиторій, сервіс автоматично розгорне ваш код і перевантажить додаток якщо необхідно.<br />
<a name='more'></a><br />
Перед тим, як ви зможете завантажувати код, ви повинні надати публічні ключі <i>ssh</i> для ідентифікації вас на сервері.<br />
<i>OpenShift</i> використовує публічні ключі для шифрування з'єднання між вашою локальною машиною і додатком. Ви повинні створити приватний і публічний ключі на вашій локальній машині, і завантажити публічний ключ перед тим як ви зможете приєднатися до вашого додатку<br />
<br />
Публічний ключ знаходиться у файлі<i>~/.ssh/id_rsa.pub</i><br />
Його вміст потрібно вставити на сторінці <a href="https://openshift.redhat.com/app/console/applications/test/get_started">https://openshift.redhat.com/app/console/applications/test/get_started</a>.<br />
<br />
Згенерувати новий ключ можна командою:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>$ ssh-keygen -t rsa -C "your_email@youremail.com"
</code></pre><br />
У вашій системі повинен бути встановлений клієнт <i>Git</i>.<br />
Для створення свого клону проекту з git-репозиторію потрібно виконати команду типу такої:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>$ git clone ssh://ххх@test-mamantoha.rhcloud.com/~/git/test.git/
</code></pre>Ця команда створить на локальній машині каталог з кодом вашого додатку. Після цього ви зможете правити і публікувати код у віддалений репозиторій. <br />
<br />
Давайте подивимось на структуру додатку по замовчуванню:<br />
<i>config.ru</i> - цей файл використовується для запуску веб-орієнтованих додатків на основі <i>Rack</i>(наприклад, <i>Sinatra</i>, <i>Padrino</i>).<br />
<i>tmp/</i> - тимчасове сховище.<br />
<i>public/</i> - публічний каталог (для картинок, <i>css</i>, <i>javascript</i>).<br />
<i>../data</i> - для постійних даних.<br />
<i>.openshift/action_hooks/pre_build</i> - скрипт, який запускається перед кожним внесенням змін у віддалений репозиторій (<i>git push</i>).<br />
<i>.openshift/action_hooks/build</i> - скрипт, який запускається після <i>git push</i>, в процесі побудови.<br />
<i>.openshift/action_hooks/deploy</i> - скрипт, який запускається після <i>git push</i>, але перед перезапуском додатку.<br />
<i>.openshift/action_hooks/post_deploy</i> - скрипт, який запускається після <i>git push</i>, після перезапуску додатку.<br />
<br />
Прийшов час створити простий <i>Sinatra</i> додаток.<br />
<br />
<i>OpenShift</i> має дзеркало <a href="http://rubygems.org">rubygems.org</a> на <a href="http://mirror1.prod.rhcloud.com/mirror/ruby/">http://mirror1.prod.rhcloud.com/mirror/ruby/</a>.<br />
Це дзеркало знаходиться у тій самій мережі, що і ваш додаток. Тому <i>gem</i>'и будуть завантажуватися швидше.<br />
Щоб використовувати дзеркало <i>OpenShift</i>, відредагуйте файл <i>Gemfile</i> і просто замініть:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>source 'http://rubygems.org'
</code></pre>на<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>source 'http://mirror1.prod.rhcloud.com/mirror/ruby/'
</code></pre><br />
Нижче додайте <i>gem</i>'и, які будете використовуватися у додатку:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>gem 'sinatra'
gem 'slim'
</code></pre><br />
Далі відредагуйте файл <i>config.ru</i>, який призначений для запуску додатку <i>Sinatra</i>.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>require 'bundler'
Bundler.require
require './app'
run Sinatra::Application
</code></pre><br />
І власне <i>app.rb</i>:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>require 'sinatra'
require 'slim'
enable :inline_templates
get '/' do
slim :hello
end
__END__
@@ hello
h1 Hello OpenShift!
p = RUBY_DESCRIPTION
p = Time.now
</code></pre><br />
Переконуємось, що всі залежності в Gemfile <i>доступні</i> для нашого додатку.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>bundle install
</code></pre><br />
Коли ви внесете зміни у віддалений репозиторій, <i>OpenShift</i> повідомить статус розгортання коду. Сервіс виконає усі необхідні дії і перезапустить додаток.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>git add .
git commit -a
git push
</code></pre><br />
Робочий приклад додатку зі статті: <a href="http://test-mamantoha.rhcloud.com/">http://test-mamantoha.rhcloud.com/</a>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com2tag:blogger.com,1999:blog-4152168096498110483.post-24929110903568271442012-05-17T14:11:00.001+03:002012-05-17T15:25:24.774+03:00Ведення логів у MechanizeДля того, щоб проаналізувати, що пішло не так, коли <i>Mechanize</i> викликає виключення, виникає необхідність ведення логів. <i>Mechanize</i> може реєструвати практично будь-які події, включаючи заголовки запитів. Для цього потрібно передати екземпляр класу <i>Logger</i> у метод <i>Mechanize#log</i>.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code># -*- encoding: utf-8 -*-
require 'mechanize'
require 'logger'
log = Logger.new($stderr)
log.level = Logger::DEBUG
agent = Mechanize.new do |a|
a.log = log
end
agent.get('http://google.com')
</code></pre>Отриману інформацію надалі можна використати для аналізу подій, виявлення помилок та збоїв.<br />
<a href="https://gist.github.com/2718143#file_mechanize1.log">https://gist.github.com/2718143#file_mechanize1.log</a><br />
Офіційна документація по класу <a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html">Logger</a><br />
<br />
Також існує менш відомий, але не менш корисний спосіб ведення логів за допомогою методу <i>Mechanize#agent.http.debug_output</i>:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code># -*- encoding: utf-8 -*-
require 'mechanize'
agent = Mechanize.new do |a|
a.agent.http.debug_output = $stderr
end
agent.get('http://google.com')
</code></pre><a href="https://gist.github.com/2718143#file_mechanize2.log">https://gist.github.com/2718143#file_mechanize2.log</a><br />Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-72440996631328943812012-05-17T00:17:00.000+03:002012-05-17T00:42:30.187+03:00Оновлюємо статус ВКонтакте за допомогою RubyСьогодні вечором виникло бажання, щоб на моїй сторінці <i>ВКонтакте</i> відображався таймер зворотнього відліку до початку Євро-2012 прямо в статусі. Написати простенький скрипт на <i>Ruby</i> для такого достатньо просто.<br />
З інструментів я використовував свою <a href="https://github.com/mamantoha/vkontakte">бібліотеку</a> для роботи з <i>API ВКонтакте</i>. Якщо комусь цікаво, як вона працює, можете почитати статтю <a href="http://ruby-ua.blogspot.com/2011/06/standalone-oauth-20-ruby-mechanize.html">ВКонтакте → Авторизація Standalone-додатків використовуючи OAuth 2.0 на прикладі Ruby і Mechanize</a>.<br />
<br />
Не вдаючись в подробиці, ось <a href="https://gist.github.com/2713756">посилання на приклад скрипта</a>.<br />
<br />
Здавалось би залишилось додати скрипт у <i>cron</i> і насолоджуватись результатом.<br />
Наступний рядок у <i>/etc/crontab</i> не приніс бажаних результатів.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>*/1 * * * * user ruby /home/user/days_to_euro.rb
</code></pre>Скрипт всього-на-всього не виконувався.<br />
Причиною проблеми виявився Ruby Version Manager(<i>RVM</i>). Змінюємо на наступний рядок.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>*/1 * * * * user bash -c 'source /home/user/.rvm/scripts/rvm && /usr/bin/env ruby /home/user/days_to_euro.rb'
</code></pre><br />
І вуаля: тепер скрипт успішно виконується і так же успішно завершує роботу з помилкою:<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>`default_gemfile': Could not locate Gemfile (Bundler::GemfileNotFound)
</code></pre>Це відбувається тому, <i>Bundler</i> шукає <i>Gemfile</i> в каталозі в якому виконується, а <i>Gemfile</i> там звісно ж немає.<br />
Потрібно вказати де шукати Gemfile.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>ENV['BUNDLE_GEMFILE'] = File.join(File.dirname(__FILE__) ,'Gemfile')
</code></pre>Вищевказаний рядок потрібно додати у шапку скрипта.<br />
<br />
Тепер все добре і скрипт працює.<br />
<br />
P.S. До Євро-2012 залишилось 21 день 23 години 43 хвилиниAnton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0tag:blogger.com,1999:blog-4152168096498110483.post-84892277123834592202012-05-13T19:17:00.001+03:002012-05-13T19:17:36.953+03:00QtRuby: позиціювання віджетівУ цій статті, ми познайомимося з основами розміщенням віджетів у вікні додатку <i>QtRuby</i>.<br />
<br />
Коли ми розробляємо графічний інтерфейс додатку, ми вирішуємо, які компоненти ми будемо використовувати і як ми будемо організовувати ці компоненти. Щоб організувати компоненти, ми використовуємо спеціальні невидимі об'єкти, так звані менеджери компонування(layout managers).<br />
<i>Qt</i> надає кілька варіантів. Ми можемо використовувати абсолютне позиціювання, вбудовані менеджери компонування або створити власний менеджер компонування. Також ми також можемо візуально будувати макети допомогою <i>Qt Designer</i>.<br />
<a name='more'></a><br />
<h3>Абсолютне позиціювання.</h3><br />
Негарний і не рекомендований метод розміщення графічних об'єктів - "в ручну" задавати положення і розмір кожного віджета у пікселях, використовуючи метод <i>setGeometry(x, y, width, height)</i>.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code># -*- encoding: utf-8 -*-
require 'Qt'
class QtApp < Qt::Widget
def initialize
super
set_window_title 'Absolute'
init_ui
resize 400, 280
move 300, 300
show
end
def init_ui
label = Qt::Label.new('Windows', self)
edit = Qt::TextEdit.new(self)
activate = Qt::PushButton.new('Activate', self)
close = Qt::PushButton.new('Close', self)
ok = Qt::PushButton.new('OK', self)
help = Qt::PushButton.new('Help', 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
</code></pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-lOatwCCy8RY/T6_WqXBbW8I/AAAAAAAAKjY/R_ZPouVOnUs/s1600/absolute.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="320" width="400" src="http://2.bp.blogspot.com/-lOatwCCy8RY/T6_WqXBbW8I/AAAAAAAAKjY/R_ZPouVOnUs/s400/absolute.png" /></a></div><br />
Очевидний недолік такого підходу проявиться відразу ж, як тільки ви почнете змінювати розміри вікна. Всі віджети залишаються на своїх місцях.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-U2rKBokpRkk/T6_WzqoTZFI/AAAAAAAAKjk/zg_AQ9ceCKw/s1600/absolute_resize1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="272" width="400" src="http://3.bp.blogspot.com/-U2rKBokpRkk/T6_WzqoTZFI/AAAAAAAAKjk/zg_AQ9ceCKw/s400/absolute_resize1.png" /></a></div><br />
<h3>Менеджери компонування</h3><i>Qt</i> надає більш гнучкий і досконалий механізм розміщення графічних об'єктів в контейнері. В <i>Qt</i> для цих цілей існують менеджери компонування, успадковані від класу <i>Qt::Layout</i>.<br />
Розглянемо три основних менеджера компонування: <i>Qt::HBoxLayout</i>, <i>Qt::VBoxLayout</i> і <i>Qt::GridLayout</i>.<br />
Для розміщення об'єктів в один ряд по горизонталі використовується <i>Qt::HBoxLayout</i>, аналогічно <i>Qt::VBoxLayout</i> - для розміщення об'єктів по вертикалі.<br />
Для більш складних розміщень використовують <i>Qt::GridLayout</i>, а також комбінації з усіх трьох менеджерів.<br />
<i>Qt::GridLayout</i> розміщує елементи в комірках уявної таблиці, причому кожен елемент може займати кілька суміжних комірок по вертикалі і/або горизонталі. Про нього пізніше.<br />
Для додавання підлеглого віджету використовується метод <i>addWidget()</i>, для додавання підлеглого менеджера компонування - метод <i>addLayout()</i>.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>
# -*- encoding: utf-8 -*-
require 'Qt'
class QtApp < Qt::Widget
def initialize
super
set_window_title 'Layouts'
init_ui
resize 400, 280
move 300, 300
show
end
def init_ui
label = Qt::Label.new('Windows', self)
edit = Qt::TextEdit.new(self)
activate = Qt::PushButton.new('Activate', self)
close = Qt::PushButton.new('Close', self)
ok = Qt::PushButton.new('OK', self)
help = Qt::PushButton.new('Help', 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
</code></pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-d5wdSnvNtwI/T6_YZlJhFpI/AAAAAAAAKjw/JOJHF6UALRY/s1600/boxlayout.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="320" width="400" src="http://1.bp.blogspot.com/-d5wdSnvNtwI/T6_YZlJhFpI/AAAAAAAAKjw/JOJHF6UALRY/s400/boxlayout.png" /></a></div><br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>vbox = Qt::VBoxLayout.new(self)
</code></pre>Базовий блок нашого прикладу, у якому будуть розміщуватися всі інші віджети і блоки.<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>vbox.add_widget(label)
</code></pre>Першим йде віджет мітки(<i>label</i>). Він буде просто знаходитися зверху у вертикальному блоці(<i>vbox</i>).<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>vbox1.add_widget(activate)
vbox1.add_widget(close, 0, Qt::AlignTop)
hbox1.add_widget(edit)
hbox1.add_layout(vbox1)
vbox.add_layout(hbox1)
</code></pre>У центральній частині вікна у нас є віджет редагування тексту(<i>edit</i>) і дві кнопки(<i>activate</i> і <i>close</i>). Вони розміщені у вертикальному блоці(<i>vbox1</i>), і вирівняні по верхній його частині. Віджет редагування тексту(<i>edit</i>) і вертикальний блок(<i>vbox1</i>) розміщені у горизонтальному блоці(<i>hbox1</i>), який в свою чергу розміщений у вертикальному блоці(<i>vbox</i>) відразу під віджетом мітки(<i>label</i>).<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>hbox2.add_widget(help)
hbox2.add_stretch(1)
hbox2.add_widget(ok)
vbox.add_layout(hbox2, 1)
</code></pre>Кнопки <i>help</i> і <i>ok</i> розміщені в іншому горизонтальному блоці(<i>hbox2</i>). Між ними за допомогою методу <i>addStretch()</i> встановлений розширювальний пробіл. Знову ж таки, горизонтальний блок(<i>hbox2</i>) розміщений в головному вертикальному блоці(<i>vbox</i>).<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>set_layout(vbox)
</code></pre>Головний вертикальний блок(<i>vbox</i>) встановлений, як основний для вікна.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/-yxzWqXEdUfI/T6_az_mG36I/AAAAAAAAKj8/Q8mRWd1tTMA/s1600/boxlayout_resize1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="273" width="400" src="http://3.bp.blogspot.com/-yxzWqXEdUfI/T6_az_mG36I/AAAAAAAAKj8/Q8mRWd1tTMA/s400/boxlayout_resize1.png" /></a></div>Можете переконатися, що віджети позиціонуються відносно розмірів вікна.<br />
<br />
В останньому прикладі ми будемо використовувати менеджер <i>Qt::GridLayout</i>.<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code># -*- encoding: utf-8 -*-
require 'Qt'
class QtApp < Qt::Widget
def initialize
super
set_window_title 'GridLayout'
init_ui
resize 400, 280
move 300, 300
show
end
def init_ui
label = Qt::Label.new('Windows', self)
edit = Qt::TextEdit.new(self)
activate = Qt::PushButton.new('Activate', self)
close = Qt::PushButton.new('Close', self)
ok = Qt::PushButton.new('OK', self)
help = Qt::PushButton.new('Help', 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
</code></pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-kqNzNm86suk/T6_bw6vL-wI/AAAAAAAAKkI/Dd0Cs44_gJ8/s1600/gridlayout.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="320" width="400" src="http://4.bp.blogspot.com/-kqNzNm86suk/T6_bw6vL-wI/AAAAAAAAKkI/Dd0Cs44_gJ8/s400/gridlayout.png" /></a></div><br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>grid.add_widget(label, 0, 0)
</code></pre>Ми розміщуємо мітку(<i>label</i>) в першу клітинку сітки. Клітинки рахуються від 0. Останні два параметри є номерами рядка і стовпця.<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>grid.add_widget(edit, 1, 0, 3, 2)
</code></pre>Віджет редагування тексту(<i>edit</i>) поміщається в першому рядку і нульовому стовпці. Останні два параметри є діапазоном рядків і стовпців. Вертикально, віджет буде охоплювати три рядка, а горизонтально - дві колонки.<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>grid.set_column_stretch(1, 1)
</code></pre>Параметрами методу <i>setColumnStretch()</i> є номер колонки і коефіцієнт розтягування. Тут ми встановлюємо коефіцієнт розтягування 1 для першої колонки. Це означає, що ця колонка буде займати все вільне місце по горизонталі. Це зроблено для, щоб кнопки зберігали свій оригінальний розмір.<br />
<br />
<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>grid.set_row_stretch(3, 1)
</code></pre>Аналогічно тут встановлюємо коефіцієнт розтягування 1 для третього рядка, щоб мітка(<i>label</i>) зберігала свій мінімальний розмір.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-k6iTSwIBqEs/T6_cW4CEHWI/AAAAAAAAKkU/rbkC5bfuOM8/s1600/gridlayout_resize1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="271" width="400" src="http://1.bp.blogspot.com/-k6iTSwIBqEs/T6_cW4CEHWI/AAAAAAAAKkU/rbkC5bfuOM8/s400/gridlayout_resize1.png" /></a></div>Anton Maminovhttp://www.blogger.com/profile/08026234658348754340noreply@blogger.com0