середу, 28 жовтня 2009 р.

Привіт, Sinatra!

Sinatra — об'єктно-орієнтований програмний каркас(framework) для створення веб-застосунків, написана на мові програмування Ruby. На офійному сайті написано, що Sinatra це навіть не фреймворк, а DSL для створення веб-додатків. Залежить від інтерфейсу веб-сервера Rack. Вона є альтернативою іншим Ruby фреймворкам, таким як Ruby on Rails, Merb, Nitro та Camping.
Sinatra є відкритим програмним забезпеченням і розповсюджується під ліцензією MIT.
Розроблена та створена Blake Mizerany, Sinatra є крихітною(близько 1500 рядків коду, що майже 1/100-а розміру Rails) та надзвичайно гнучкою. Вона не слідує типовій архітектурі Модель-Вид-Контролер(Model-View-Controller, MVC), яка використовується в інших фреймвоках, таких як Ruby On Rails. Натомість, Sinatra зосереджена на "швидкому створенню веб-додатків на Ruby із мінімальними зусиллями". Sinatra використовує всі можливості Ruby і є його оригінальним розширенням.

Sinatra дає незвичайне відчуття присутності. Це як музика. Ви диригент оркестру. І перша скрипка звучить так, як ви їх наказали, хоча ви не обов'язково повинні знати, як на ній грати. Але в той же час у вас є можливість посмикати струни, побити в барабани, засурмити фанфари. Sinatra крихітна, гнучка і модульна. Ви вільні у виборі, що використовувати у якості бібліотеки моделі, двигуна шаблонів, двигуна JavaScript. Незважаючи на свій юний вік Sinatra є потужним і багатообіцяючим інструментом, про що свідчить підтримка з боку таких таких маститих проектів, як Engine Yard, Heroku, GitHub і Songbird.

Інсталяція Sinatra
Розпочнемо знайомство із встановлення Sinatra.
У вас уже повинен бути встановлений Ruby. Для тих хто вже користується новою гілкою 1.9 можу вас втішити - починаючи з версії 0.9.2, Sinatra повністю сумісна з Ruby 1.9 і Rack 1.0. Найпростіший шлях - встановити Sinatra через Rubygems:
$ gem install sinatra


Привіт, Sinatra
Тепер давайте створимо наш перший веб-додаток.
# myapp.rb
require 'rubygems'
require 'sinatra'

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




Звичайно це не дуже корисна програма, це традиційний "Hello World!". Незважаючи на свою простоту, цей приклад корисний тим, що дозволяє виконати всі дії, необхідні для написання і запуску будь-якого Sinatra додатку.
Інша річ, яку ви могли помітити, вам не потрібно запускати нічого подібного Rails генераторам, для створення додатку. Для запуску програми код Ruby потрібно зберегти в файлі під якоюсь назвою (в нашому випадку це myapp.rb). Потім програму потрібно запустити. В залежності від операційної системи, це робиться по різному. Наприклад, під управлінням Linux, потрібно набрати на терміналі:
$ ruby myapp.rb


У результаті запуститься веб-сервер WEBrick, який можна переглянути з вашого улюбленого навігатора тенет за адресою http://localhost:4567.

Маршрути
В Sinatra-додатках вхідні запити спочатку відсилаються маршрутизатору, який і вирішує, куди запит повинен бути відісланий і як, власне, цей запит повинен бути оброблений. У Sinatra, маршрут пов'язаний із HTTP-методом, і записується у парі з відповідним зразком URL.

  • GET

  • POST

  • PUT

  • DELETE


Кожен маршрут пов'язаний з блоком:
get '/' do
# показати щось
end


post '/' do
# створити щось
end


put '/' do
# оновити щось
end


delete '/' do
# знищити шось
end



Маршрути збігаються у тому порядку, в якому вони визначені. Тобто, викликається перший маршрут, який відповідає запиту. З цієї причини ви повинні розміщувати найбільш специфічні обробники зверху, а найбільш нечіткі - знизу.

Маршрут може включати в себе імена параметрів, які доступні через параметри хешу:
get '/hello/:name' do
# збігається з "/hello/foo" і "/hello/bar"
# params[:name] буде 'foo' або 'bar'
"Hello #{params[:name]}!"
end


Також маршрут може включати підстановлювальний знак (wildcard), який доступний через масив params[:splat] :
get '/say/*/to/*'
# збігається з "/say/hello/to/world"
params[:splat] # => ["hello", "world"]
end


get '/download/*.*' do
# збігається з "/download/path/to/file.xml"
params[:splat] # => ["path/to/file", "xml"]
end


Маршрут, відповідний з регулярними виразами:
get %r{/hello/id([\d]+)} do
# збігається з "/hello/id1234"
# params[:captures] => ["1234"]
"Hello, #{params[:captures].first}!"
end


Або те саме з параметром блоку:
get %r{/hello/id([\d]+)} do |c|
"Hello, #{c}!"
end


User Agent.
Наступний маршрут відповідає будь-якому броузеру:
get '/agent', :agent => /(.+)/ do
"You are using #{params[:agent].first}"
end


Тільки Opera:
get '/agent', :agent => /Opera\/(\d+\.\d+).*?/ do
"You are using Opera version #{params[:agent].first}"
end


Інші методи викликаються так само як "get" маршрути. Ви просто використовуєте функції "post", "put" чи "delete" для визначення маршруту. Щоб отримати доступ до параметрів POST, використовується params[:xxx], де xxx - це ім'я елементу форми, яке було надіслано.
post '/foo' do
"You just asked for foo, with post param bar equal to #{params[:bar]}"
end


Статичні файли
Статичні файли віддаються з директорії ./public. Ви можете визначити інше місце, встановивши опцію :public
set :public, File.dirname(__FILE__) + '/static'


Зверніть увагу, що ім'я публічного каталогу не включається в шлях URL. Файл ./public/css/style.css буде доступний як http://localhost/css/style.css.

Шаблони
Шаблони безпосередньо розміщуються у директорії ./views. Щоб використовувати іншу директорію, необхідно встановити опцію :views
set :views, File.dirname(__FILE__) + '/templates'


Важливо пам'ятати, що вам завжди доведеться посилатися на шаблон використовуючи об'єкт типу Symbol, навіть якщо він знаходяться у підкаталозі (в такому випадку використовувати :'subdir/template'). Методи будуть виконувати будь-які рядки, передані їм безпосередньо.

Шаблони HAML
Haml (XHTML Abstraction Markup Language) — мова розмітки для спрощеного генерування XHTML
get '/' do
haml :index
end

Обробляє ./view/index.haml

Параметри HAML можуть бути встановлені глобально через конфігурацію Sinatra, або перевизначені індивідуально.
set :haml, {:format => :html5 } # формат Haml по замовчуванню :xhtml


get '/' do
haml :index, :haml_options => {:format => :html4 } # перевизначення
end


Шаблони Erb
require 'erb'

get '/' do
erb :index
end

Обробляє ./view/index.erb

Шаблони Builder
require 'builder'

get '/' do
content_type 'application/xml', :charset => 'utf-8'
builder :index
end

Обробляє ./view/index.builder

Шаблони Sass
Sass (Syntactically Awesome Stylesheets) - еквівалент HAML для CSS
require 'sass'

get '/stylesheet.css' do
content_type 'text/css', :charset => 'utf-8'
sass :stylesheet
end

Обробляє ./view/stylesheet.sass

Параметри Sass можуть бути встановлені глобально через конфігурацію Sinatra, або перевизначені індивідуально.
set :sass, {:style => :compact } # стиль Sass по замовчуванню :nested


get '/stylesheet.css' do
content_type 'text/css', :charset => 'utf-8'
sass :stylesheet, :sass_options => {:style => :expanded } # перевизначення
end


Вбудовані шаблони
get '/' do
haml '%div.title Hello World'
end

Обробляє вказаний рядок.

Доступ до змінних у шаблоні
Шаблони оцінюються в тому контексті, як і обробники маршруту. Змінні, встановленні в обробнику маршруту безпосередньо доступні шаблону.
get '/:id' do
@foo = Foo.find(params[:id])
haml '%h1= @foo.name'
end


Або вказати явний хеш(Hash) локальних змінних:
get '/:id' do
foo = Foo.find(params[:id])
haml '%h1= foo.name', :locals => { :foo => foo }
end


Зазвичай це використовується для обробки шаблонів, як фрагментів(partials) з інших шаблонів.

In-file шаблони
Шаблони можуть бути визначеними у кінці вихідного файлу:
require 'rubygems'
require 'sinatra'

get '/' do
haml :index
end

__END__

@@ layout
%html
= yield

@@ index
%div.title Hello world!!!!!


Іменовані шаблони
Шаблони також можуть бути визначені з використання шаблону верхнього рівня:
template :layout do
"%html\n =yield\n"
end

template :index do
'%div.title Hello World!'
end

get '/' do
haml :index
end


Якщо шаблон під назвою "layout" існує, він буде використовуватися щоразу при обробці шаблону. Ви можете відключити макети(layouts), передавши
:layout => false


Що почитати на дозвіллі?

1 коментар:

Stanislav O. Pogrebnyak сказав...

Зовсім нещодавно теж грався з сінатрою, для мене було цікавим примусити її працювати з jruby. І що мені сподобалося - це все з коробки. Для невеличких апі, наприклад, заміни сервлетів на java рідними рубовськими кращого немає.