суботу, 4 грудня 2010 р.

Робота з неіснуючими ключами в Hash

Веду цей блог для написання безґлуздих думок (в основному шматків коду), щоб потім не гуглити їх заново.

Досить поширена задача:
Підрахувати кількість входжень кожного елементу (наприклад, IP-адрес з лог-файлу Apache). Очевидно, для цього потрібно використовувати Hash, щоб зберігати число лічильників для ключів. Можна просто виконувати операцію += 1 для членів хешу.

Варіант 1
> languages = {}
 => {}
> languages['ukrainian'] = 0
 => 0 
> languages['ukrainian'] += 1
 => 1 
> languages
 => {"ukrainian"=>1}
> languages['russian'] += 1
NoMethodError: undefined method `+' for nil:NilClass
В Ruby, ви повинні ініціалізувати змінні. Іншими словами, ви не можете використовувати зміст змінної, якщо її не існує.

Друге, що потрібно зробити - автоматично створювати пару ключ-значення, якщо ключа не існує.
> languages['russian'] = languages.fetch('russian', 0) + 1
 => 1 
> languages
 => {"ukrainian"=>1, "russian"=>1}

Всю магію тут виконує метод Hash#fetch(key [, default] ), який повертає значення з хешу для ключа key, а якщо його не знайдено, повертає значення default.

Варіант 2
Існує простіший спосіб. Встановити значення для ключа, якого не існує в хеші (по замовчуванняю це nil).
> languages = {}
 => {} 
> languages.default
 => nil 
> languages.default = 0
 => 0 
> languages['ukrainian'] += 1
 => 1 
> languages['russian'] += 1
 => 1 
> languages
 => {"ukrainian"=>1, "russian"=>1}
> languages['english']
 => 0
Зверніть увагу, якщо запитати ключ, якого не існує в хеші, то поверне значення по замовчуванню. Тут потрібно бути обережним.

Використовуйте в залежності від ваших задач. І не забувайте читати офіційну документацію.
Успіхів!

пʼятницю, 3 грудня 2010 р.

Вирішення проблем з Rack і Sinatra на Ruby 1.9.2

Оновив на веб-сервері Ruby до версії 1.9.2 і додаток на Sinatra валиться при спробі запуску.
Справа в тому, що $LOAD_PATH (він же $:) у Ruby 1.9.2 не містить шлях до поточного каталогу і require не бачить файл /.
Рішень є кілька:
  • замінити require на require_relative
  • прописати повний шлях до файлу
  • додати поточний каталог "./" до $LOAD_PATH
В моєму випадку допомогло прописати повний шлях у файлі config.ru:
require './hello'
run Sinatra::Application
І використання require_relative в hello.rb:
require 'sinatra'
require 'haml'

require_relative 'lib/api'

пʼятницю, 19 листопада 2010 р.

Rails for Zombies

А я, між іншим, хворію. Соплі у мене і кашель, так. Температури немає і горло не болить. Дозволив собі трішечки відпочити від роботи, і щоб час не пройшов даремно почитати щось користе. Випадково натрапив на скрінкасти Rails for Zombies від Envy Labs. Це інтригуюча спроба навчити людей тому, як використовувати Ruby On Rails безпосередньо у веб-браузері. Мета Rails for Zombies зробити цей процес безпосередньо доступним і веселим.

Ось вам для затравки:


Схожі записи:

середу, 3 листопада 2010 р.

RVM - диспетчер версій Ruby на стероїдах


Після затяжної відсутності хочу представити корисний інструмент під назвою RVM - Ruby Version Manager, який забезпечує просте управління кількома інтерпретаторами (MRI, Ruby Enterprise Edition, JRuby, Rubinius, ...) і версіями Ruby (1.8.6, 1.8.7, 1.9.2, ...) без головного болю. Цей інструмент буде корисний, якщо ви бажаєте одночасно використовувати в системі декілька різних версій Ruby.

Про інсталяція можна прочитати на офіційній сторінці проекту.
Я ж опишу процес інсталяції для своєї системи - Ubuntu 10.10 для звичайного користувача у його домашній теці.

Спочатку встановлюємо необхідні пакунки:
$ sudo apt-get install build-essential libreadline5-dev libssl-dev git-core curl

Установка/оновлення з репозиторію GitHub:
$ wget http://rvm.beginrescueend.com/releases/rvm-install-head
$ chmod +x rvm-install-head
$ ./rvm-install-head

Додаємо наступний рядок в кінець файлу ~/.bashrc:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"

Щоб перевірити чи rvm коректно встановився, відкриваємо новий термінал і вводимо команду. Якщо все було виконано правильно ви повинні побачити:
$ type rvm|head -n1
rvm є функцією

Тепер власне встановлюємо сам інтерпретатор Ruby версії 1.9.2:
$ rvm install ruby-1.9.2

Встановлюємо 1.9.2, як версію Ruby по замовчуванню:
$ rvm ruby-1.9.2 --default

Насолоджуємось!
$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]

вівторок, 13 липня 2010 р.

Робота з форматом CSV в Ruby 1.9

Сьогодні мова піде про роботу з форматом CSV в Ruby 1.9.x.
Wikipedia каже:
CSV (від англ. Comma Separated Values - значення, розділені комами) - це текстовий формат, призначений для представлення табличних даних. Кожен рядок файлу - це один рядок таблиці. Значення окремих колонок розділяються розділовим символом (delimiter) - кома (,) або крапку з комою (;). Використовуваний символ роздільника залежить від встановленої в системі локалі. У США це кома, а в Росії - крапка з комою, так як кома використовується для дробових чисел (на відміну від США, де це крапка). Значення, що містять зарезервовані символи, такі як: кома, крапка з комою або новий рядок обрамляються символом подвійні лапки ("); якщо у значенні зустрічаються лапки - вони представляються в файлі у вигляді двох лапок поспіль. Рядки розділяються парою символів CR LF (0x0D 0x0A) (в DOS і Windows ця пара генерується натисканням клавіші Enter).

У Ruby 1.9 стандартна бібліотеки CSV була замінена на FasterCSV.

У прикладі я буду використовувати екпортовану у CSV адресну книгу з Nokia PC Suite. Цей скрипт буде виводити доступну інформацію про контакти.
# -*- encoding: utf-8

require 'csv'
filename = 'contacts.csv'
CSV.foreach(filename, :col_sep => ';', :headers => :first_row, :encoding => 'UTF-8') do |row|
  puts "==="
  row.to_hash.each_pair{|k, v| puts "#{k} => #{v}" if !v.empty?}
end


Опції:
  • row_sep - розлілювач полів (по замовчуванню кома)
  • col_sep - розділювач рядків (по замовчуванню перехід на новий рядок)
  • headers(:first_row означає, що перший рядок трактується, як заголовок)
  • encoding - кодування файлу

Щоб подивитись всі доступні опції виконайте в терміналі:
ri CSV::new

середу, 7 липня 2010 р.

Онлайн тест по Ruby

На сервісі Quizful є тест з основ Ruby - http://www.quizful.net/category/ruby.

Наразі є тільки тест початкового рівня. Але в майбутньому планується додати тести з Ruby середнього та експертного рівнів. Ще одним поліпшенням буде розширення списку питань з усіх тестів розділу, а також розбиття всіх питань на тематики (синтаксис, оператори, класи і т.д.).

Крім того на Quizful ви знайдете більше 100 тестів по адмініструванню, програмуванню, базам даних, веб-технологіях

Нові методи для роботи з масивами у Ruby 1.9.2

Робота з масивами та аналогічними об’єктами у Ruby є дуже простою. З Ruby 1.9.2 ми отримали більше цікавих можливостей :)

У файлі NEWS написано:
* Array
    * new method:
      * Array#keep_if
      * Array#repeated_combination
      * Array#repeated_permutation
      * Array#rotate
      * Array#rotate!
      * Array#select!
      * Array#sort_by!

    * extended methods:
      * Array#{uniq,uniq!,product} can take a block.
...
  * Enumerable
    * New methods:
      * Enumerable#chunk
      * Enumerable#collect_concat
      * Enumerable#each_entry
      * Enumerable#flat_map
      * Enumerable#slice_before

У цій статті коротко розглянемо ці методи.

пʼятницю, 2 липня 2010 р.

Ruby 1.9.2 RC

Майже за планом вийшов реліз-кандидат Ruby 1.9.2.
Було виправлено близько 130 багів. Версія 1.9.2 в більшості випадків сумісна з 1.9.1. Проте додано багато нових методів.

Все йде за планом і Ruby 1.9.2 буде випущена на початку серпня.

>>> Подробиці

суботу, 19 червня 2010 р.

Аналог PHP функції strtr() на Ruby

В ході написання одного скрипта на Ruby, знадобився аналог PHP функції strtr().
Власне, функція повинна повертати рядок, у якому кожне входження будь-якого рядків із перелічених у from, замінюється на відповідний рядок з to. Функція приймає один аргумент, який повинен бути масивом, індекси якого трактуються як рядки пошуку, а відповідні значення - як рядки заміни. В першу чергу замінює більш довші підрядки.

class String
  def strtr(tr)
    sorted_tr = tr.sort{|a, b| b[0] <=> a[0]}
    keys = sorted_tr.map{|k, v| k}
    values = sorted_tr.map{|k, v| v}
    r = /(#{keys.map{|i| Regexp.escape(i)}.join( ')|(' )})/
    self.gsub(r){|match| values[keys.index(match)]}
  end
end

Приклад роботи:
tr1 = {'A' => '1', 'AA' => '2', 'AAA' => '3'}
tr2 = [['A', '1'],['AA', '2'],['AAA', '3']]
s = 'ABAACAAADAAAA'

puts s.strtr(tr1)
puts s.strtr(tr2)

1B2C3D31
1B2C3D31


UPD
Ще один варіант цієї функції. Коротший і зрозуміліший:
class String
  def strtr(tr)
    tr.sort{|a, b| b[0] <=> a[0]}.map.inject(self){|str, pair| str.gsub(pair[0], pair[1])}
  end
end


Але він не відповідає умові, що один і той же рядок пошуку використовується тільки один раз.

При вхідних даних:
s = "ABAACAAADAAAA"
tr = {"A"=>"AA", "AA"=>"AAAA", "AAA"=>"AAAAAA"}
s.strtr(tr)

Для першого варіанту отримаємо:
=> "AABAAAACAAAAAADAAAAAAAA"
а для другого:
=> "AABAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAA"

середу, 5 травня 2010 р.

Meet Padrino! Part 2

У попередній статті ми познайомитись з веб-фреймворком Padrino. Створили проект і розглянули його структуру. Також навчились генерувати інтерфейс адміністратора, контролери і моделі. Сьогодні ми продовжимо наше знайомство з цим чудовим фреймворком.
Минулого разу ми додали можливість керувати(створювати, редагувати і видаляти) повідомленнями блогу і відображати їх на головній сторінці. Але ми пропустили одну важливу властивість у моделі Post - дату створення/редагування повідомлення.

понеділок, 3 травня 2010 р.

Запуск web-додатку на Sinatra з Phusion Passenger

На сьогоднішній день одним з найпростіших способів запуску Rails і Rack web-додатків є Phusion Passenger, що представляє собою модуль для Apache і Nginx. Фреймворк Sinatra базується на Rack, отже, додатки на його основі Passenger здатний легко запускати.

Для програми необхідна базова структура директорій:
APP_DIRECTORY/
  |-- app.rb       <-- безпосередньо додаток
  |-- config.ru    <-- Rackup файл для запуску
  |-- public/      <-- директорія для статичних файлів (зображення, css, javascript)
  |-- tmp/         <-- тимчасова директорія

Встановлюємо Apache2:
$ sudo apt-get install apache2-mpm-prefork apache2-prefork-dev libapr1-dev libaprutil1-dev

Встановлюємо Phusion Passenger:
$ sudo gem1.9.1 install passenger

Налаштування модуля для Apache:
$ sudo /opt/ruby191/bin/passenger-install-apache2-module

Далі слідуємо інструкції.
Створюємо файл /etc/apache2/mods-available/passenger.load і додаємо наступні рядки:
LoadModule passenger_module /opt/ruby191/lib/ruby/gems/1.9.1/gems/passenger-2.2.11/ext/apache2/mod_passenger.so
PassengerRoot /opt/ruby191/lib/ruby/gems/1.9.1/gems/passenger-2.2.11
PassengerRuby /opt/ruby191/bin/ruby

Застосовуємо зміни і перезапускаємо сервіс:
$ sudo a2enmod passenger
$ sudo service apache2 restart

Припустимо наш додаток Sinatra знаходиться у /somewhere. Додамо віртуальний хост до конфігурації Apache і встановимо DocumentRoot у /somewhere/public
# /etc/apache2/sites-enabled/000-default
<VirtualHost *:80>
  ServerName www.yourhost.com
  DocumentRoot /somewhere/public
  <Directory /somewhere/public>
    AllowOverride all
    Options -MultiViews
  </Directory>
</VirtualHost>

Для запуску додатку із статті Привіт, Sinatra! створимо Rackup файл config.ru:
require 'sinatra'
require 'app.rb'

run Sinatra::Application

# app.rb
require 'rubygems'
require 'sinatra'

get '/' do
 "Привіт, Sinatra!"
end

середу, 28 квітня 2010 р.

ВКонтакте → Авторизація Desktop-додатків на прикладі Ruby і Mechanize

Увага! Дана версія документації є застарілою. Замість неї я рекомендую прочитати статтю ВКонтакте → Авторизація Standalone-додатків використовуючи OAuth 2.0 на прикладі Ruby і Mechanize

Нещодавно розробники соціальної мережі ВКонтакте повідомити про запуск можливості використання VK API для standalone-додатків. Я ж вирішив експериментально перевірити цю нову можливість у зв'язці з мовою Ruby.

Використані джерела:

Авторизація Desktop-додатків
Desktop-додатки на відміну від звичайних програм ВКонтакте запускаються у вигляді звичайних програм на пристрої користувача, яким може бути комп'ютер, комунікатор або смартфон. Наприклад, це може бути додаток на платформі Adobe AIR або додаток для iPhone, написане на Objective-C.

Почав писати обгортку до цього на Ruby. І відразу ж засмутився - авторизація на даний момент через одне місце. Потрібен компонент браузера з підтримкою JavaScript. Насправді я уявлення не маю як таке реалізувати на Ruby. Доведеться вручну вивчати що і куди посилати. Але чому б не зробити метод у який висилається логін-пароль? І просто отримувати ID сесії.
Маємо те, що маємо. Обійдемося поки цим. А в майбутньому, надіюся виправлять.
Для початку необхідно створити новий або взяти вже існуючий додаток.

пʼятницю, 23 квітня 2010 р.

Meet Padrino! Part 1

Днями по гарячих слідах Sinatra 1.0 вийшов офіційний реліз Padrino. Цю статтю я почав писати відразу після виходу версії 0.9.9 (2 квітня), але з технічних причин зумів довести її до кінця тільки після виходу 0.9.10 (22 квітня).

Padrino - це ще один веб-фреймворк, написаний на мові Ruby. Padrino намагається зробити розробку додатків більш простою і елегантною настільки наскільки це можливо, шляхом розширенням функціональності Sinatra (додаючи помічники, генератори, інтерфейс адміністратора, інтернаціоналізацію), зберігаючи його дух.
Я вже писав декілька статей про Sinatra, думаю їх буде корисно почитати.

Отже, зустрічайте – Padrino!

пʼятницю, 26 березня 2010 р.

Sinatra 1.0 is OUT!

Днями світ побачила версія 1.0 чудового DSL для створення веб-застосунків на Ruby - Sinatra.
Список змін в порівнянні з попередньою стабільною версією можна подивитися тут.
Зі слів Blake Mizerany - одного із авторів, найбільші зміни у цій версія - це чистка і стабілізація коду.

Також, починаючи з версії 1.0 Sinatra використовує бібліотеку Tilt для рéндерингу шаблонів. Це додає підтримку кешування шаблонів, послідовного трасування шаблонів, а також підтримку нових систем шаблонів, як Mustache і Liquid.

$ gem update sinatra
Updating sinatra
Successfully installed sinatra-1.0
Gems updated: sinatra

Long live Sinatra!

четвер, 25 березня 2010 р.

Новий реліз-план для Ruby 1.9.2

Згідно з попереднім планом фінальна версія Ruby 1.9.2 планувалась на кінець 2009 року.
Нещодавно було оголошено переглянутий графік релізів Ruby 1.9.2, згідно з яким, реліз відбудеться приблизно в середині серпня.
  • 31 березня буде заморожено список нових можливостей Ruby 1.9.2
  • 30 квітня буде заморожений код, всі можливості не реалізовані до цього часу не увійдуть в реліз
  • 31 травня - вихід 1.9.2-preview2: можливості, які не будуть завершені і стабільні до цього моменту, не ввійдуть в реліз
  • 30 червня - вихід 1.9.2-rc: всі знайдені на попередніх етапах помилки повинні бути виправлені
  • 31 липня - вихід 1.9.2-p0: протягом двох тижнів будуть збиратися багрепорти і завершувати реліз, перш ніж випустити його

Що ж будемо сподіватися, що цього разу розробники впораються з наміченими термінами і ми отримаємо стабільний реліз гілки 1.9.x до осені.

Відкритим залишається питання, коли ж вийде Ruby 2.0? В twitter-і Yuki Sonoda одного з розробників Ruby є інформація про те, що це може відбутися раніше, ніж очікувалося, Ruby 1.9.3 вже може бути 2.0.

четвер, 18 березня 2010 р.

Ruby Best Practices


Напевно, багато хто вже чули про цей проект. Останні кілька місяців виходили окремі розділи книги.

Тепер повністю готову книгу Ruby Best Practices можна завантажити безкоштовно.

Посилання:

четвер, 11 березня 2010 р.

Yahoo! Weather і Ruby

Yahoo! Weather RSS-канал дозволяє отримувати останню інформацію про погоду для вашої місцевості. Ви можете зберігати цю інформаію у вашому улюбленому RSS-агрегаторі, або включити ці дані до вашого сайту або додатку. RSS динамічно генерується на основі WOEID.

Короткий опис формату запиту URL та RSS відповіді.
Запит RSS слідує наступному простому синтакстису HTTP GET: починається з простого базого URL за яким слідують додаткові параметри і значення після знаку питання (?). Кілька параметрів розділяються амперсандом (&).
Базовий URL для каналу погоди є
http://weather.yahooapis.com/forecastrss
Два можливі параметри:
  • w - для WOID (обов'язковий параметр, що вказує на місце розташування для прогнозу погоди). Наприклад w=935810
  • u - для одиниць вимірювання(c: за Цельсієм, f: за Фаренгейтом). Наприклад u=c. Вибір 'c' покаже всі дані в метричних одиницях(наприклад швидкість вітру буде відображатися в кілометрах за годину).
http://weather.yahooapis.com/forecastrss?w=location

Наприклад, щоб отримати погоду для Тернополя, використовується код 935810.
http://weather.yahooapis.com/forecastrss?w=935810

Щоб знайти значення WOID для вашого міста, здійсність пошук на головній сторінці.
Наприклад для Тернополя, URL сайту буде мати наступний вигляд:
http://weather.yahoo.com/ukraine/ternopil-oblast/tarnopol'-935810/
Де WOID це 935810.

RSS відповідь я не буду докладно описувати.
Знизу приведений приклад коду для роботи з Yahoo! Weather з Ruby.

середу, 10 березня 2010 р.

Mechanize 1.0.0

Тихо і непомітно 6.02.2010 вийшов реліз моєї улюбленої бібліотеки для Ruby Mechanize версії 1.0.0. Хоч новина вже встигла припасти пилом, але краще пізно ніж ніколи. Змін не так вже й багато. Розробники в основному зосередилися на виправленні помилок.

Особливості релізу:
  • Константа WWW вважається застарілою, натомість слід використовувати константу верхного рівня Mechanize
  • Нові методи SelectList#option_with і SelectList#options_with для пошуку параметрів у випадаючому списку
  • Необов’язкові параметри можуть передавалися методу Mechanize#get

Виправлені помилки
  • Краща обробка помилок пов’язаних з некоректним кодуваннями сторінки
  • Підтримка 7-бітного кодування
  • Виправлений баґ із перетвореннями за допомогою бібліотеки Iconv
  • Відсилання форми з нульовим(nil) кодуванням сторінки
  • Прапорці(чекбокси) і поля впорядковуються за зовнішнім виглядом сторінки перед відправленням форми
  • Виправлення значень за замовчуванням з серіалізованим кукісом(cookies)
  • Перенаправлення за межами HEAD не дотримуються

Для демонстрації я переписав скрипт для Google Translate, для сумісності з новою версією Mechanize.

четвер, 4 лютого 2010 р.

Як дізнатися, хто Вас додав в закладки на ВКонтакте?

Как узнать кто добавил в закладки вконтакте?

Вас напевно завжди мучила цікавість? І, напевно, вам завжди хотілося дізнатися, у кого ж ви перебуваєте в закладках, хто вважає вас цікавим? Ви можете легко про це дізнатися. Все що потрібно для цієї інструкції - це інтерпретатор Ruby і бібліотека WWW::Mechanize

пʼятницю, 29 січня 2010 р.

Вирішення проблеми з wxRuby на Ubuntu 9.10

Існує баг з wxRuby на Ubuntu Karmic Koala.
Темою цього допису буде вирішення цієї проблеми, щоб зробити можливою розробку додатків у зв'язці Ruby 1.9 та wxRuby на Ubuntu 9.10.
Отже,покрокова інструкція.

Інсталяція необхідних пакетів для розробників

$ sudo apt-get install build-essential libssl-dev libreadline5 libreadline5-dev zlib1g zlib1g-dev
$ sudo apt-get install libgtk2.0-dev
$ sudo apt-get install libwxgtk2.8-0 libwxgtk2.8-0-dev

Встановлення Ruby (1.9.1)

Про те як зібрати Ruby 1.9.1 з вихідних кодів я описував тут
Коротко:
Завантажуємо останню свіжу версію Ruby (на момент написання статті це 1.9.1-p376)
Розпаковуємо архів і встановлюємо:
$ tar xzvf ruby-1.9.1-p376.tar.gz
$ ./configure --prefix=/opt/ruby191
$ make
$ make test
$ sudo make install

Встановлення змінних оточення

Оскільки Ruby ми збирали у /opt/ruby191, встановлюємо відповідні змінні оточення
$ PATH=/opt/ruby191/bin:$PATH
$ LD_LIBRARY_PATH=/opt/ruby191/lib:$LD_LIBRARY_PATH

Встановлення SWIG (1.3.38)

Спочатку видаляємо пакети SWIG з дистрибутиву якщо вони встановлені:
$ sudo apt-get remove swig swig1.3 --purge

Максимальна версія SWIG, що допускається для компіляції wxRuby - це 1.3.38.
Скачуємо архів swig-1.3.38.tar.gz з сайту www.swig.org
Розпаковуємо командою:
$ tar xzvf swig-1.3.38.tar.gz

У каталозі із вихідними кодами SWIG:
$ ./configure --prefix=/opt
...
checking for ruby... ruby
checking for Ruby header files... could not locate ruby.h...using -I/opt/ruby191/lib/ruby/1.9.1/i686-linux
checking for Ruby library... -Wl,-R -Wl,/opt/ruby191/lib -L/opt/ruby191/lib -lruby-static in /opt/ruby191/lib
...
$ make
$ sudo make install

Встановлення wxRuby (2.0.1)

Звантажуємо архів з вихідними кодами wxRuby з сайту wxruby.rubyforge.org
Розархівовуємо командою
$ tar xzvf wxruby-2.0.1.tar.gz
і в каталозі з вихідним кодом робимо:
$ rake1.9.1 WXRUBY_VERSION=2.0.1
$ strip -x lib/wxruby2.so
$ rake1.9.1 gem
$ sudo gem1.9.1 install -l wxruby-ruby19

Тестуємо

$ ruby1.9.1 /opt/ruby191/lib/ruby/gems/1.9.1/gems/wxruby-ruby19-2.0.1-x86-linux/samples/bigdemo/bigdemo.rb