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