четвер, 10 лютого 2011 р.

I'm alive! - 2011

Давненько сюди не писав. Просто не було настрою.
Це буде перший запис у новому 2011, році який надіюсь буде не менш багатий на події ніж попередній. Світ Ruby у 2010 був багатим на події та нові релізи. Найбільш помітні з них на мою думку:
Хочеться вірити у цьому році ця тенденція збережеться.

Стосовно цього блогу, в найближчих планах мабуть написати щось про QtRuby.

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

субота, 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"