Skip to content

Latest commit

 

History

History
1263 lines (855 loc) · 48.3 KB

README.ru.rdoc

File metadata and controls

1263 lines (855 loc) · 48.3 KB

Sinatra

Внимание: Этот документ является переводом Английской версии и может быть устаревшим

Sinatra — это предметно-ориентированный язык (DSL) для быстрого создания приложений на Ruby с приложением минимума усилий:

# myapp.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

Установите gem и запустите приложение с помощью:

gem install sinatra
ruby -rubygems myapp.rb

Результат будет тут: localhost:4567

Маршруты

В Sinatra маршрут — это пара: HTTP метод и шаблон (образец) URL. Каждый маршрут ассоциирован с блоком:

get '/' do
  .. что-то показать ..
end

post '/' do
  .. что-то создать ..
end

put '/' do
  .. что-то обновить ..
end

delete '/' do
  .. что-то удалить ..
end

options '/' do
  .. что-то ответить ..
end

Маршруты сверяются с запросом по очередности определения. Первый же совпавший с запросом маршрут и будет вызван.

Шаблоны маршрутов могут включать в себя параметры доступные в params xэше:

get '/hello/:name' do
  # соответствует "GET /hello/foo" и "GET /hello/bar",
  # где params[:name] 'foo' или 'bar'
  "Hello #{params[:name]}!"
end

Можно также использовать именные параметры в переменных блоков:

get '/hello/:name' do |n|
  "Hello #{n}!"
end

Шаблоны маршрутов также могут включать splat (wildcard, *, любая строка символов) параметры доступные в params[:splat] массиве.

get '/say/*/to/*' do
  # соответствует /say/hello/to/world
  params[:splat] # => ["hello", "world"]
end

get '/download/*.*' do
  # соответствует /download/path/to/file.xml
  params[:splat] # => ["path/to/file", "xml"]
end

Маршруты также могут использовать регулярные выражения в качестве шаблона URL:

get %r{/hello/([\w]+)} do
  "Hello, #{params[:captures].first}!"
end

Или с параметром блока:

get %r{/hello/([\w]+)} do |c|
  "Hello, #{c}!"
end

Условия

Маршруты могут включать различные условия совпадений, такие как user agent:

get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
  "You're using Songbird version #{params[:agent][0]}"
end

get '/foo' do
  # соответствует non-songbird браузерам
end

Другими доступными условиями являются host_name и provides:

get '/', :host_name => /^admin\./ do
  "Admin Area, Access denied!"
end

get '/', :provides => 'html' do
  haml :index
end

get '/', :provides => ['rss', 'atom', 'xml'] do
  builder :feed
end

Довольно легко можно задать собственные условия:

set(:probability) { |value| condition { rand <= value } }

get '/win_a_car', :probability => 0.1 do
  "You won!"
end

get '/win_a_car' do
  "Sorry, you lost."
end

Возвращаемые значения

Возвращаемое значение блока маршрута ограничивается телом ответа, которое будет передано HTTP клиенту, или следующей “прослойкой” (middleware, промежуточная программа) в Rack стеке. Чаще всего это строка, как в вышеизложенных примерах. Но и другие значения также приемлемы.

Вы можете вернуть любой объект, который будет либо корректным Rack ответом, Rack телом ответа, либо кодом состояния HTTP:

  • Массив с тремя переменными: [status (Fixnum), headers (Hash), response body (должен отвечать на #each)]

  • Массив с двумя переменными: [status (Fixnum), response body (должен отвечать на #each)]

  • Объект, отвечающий на #each, который передает только строковые типы данных в этот блок

  • Fixnum, соответствующий коду состояния HTTP

Таким образом мы легко можем создать поточный пример:

class Stream
  def each
    100.times { |i| yield "#{i}\n" }
  end
end

get('/') { Stream.new }

Статические файлы

Статические файлы отдаются из ./public директории. Вы можете указать другое место, используя :public опцию:

set :public, File.dirname(__FILE__) + '/static'

Учтите, что имя директории со статическими файлами не включено в URL. Например, файл ./public/css/style.css будет доступен как http://example.com/css/style.css.

Виды / Шаблоны

Шаблоны по умолчанию будут использованы из директории ./views. Для использования другой директории:

set :views, File.dirname(__FILE__) + '/templates'

Важно помнить, что вы всегда должны указывать шаблоны с помощью символов, даже если это подкаталог (в этом случае используйте :'subdir/template'). Вы должны использовать символ, иначе методы, ответственные за рендеринг, отобразят просто переданную им строку.

Haml шаблоны

haml gem/библиотека необходима для рендеринга HAML шаблонов:

# Вам нужно будет подключить haml gem в приложении
require 'haml'

get '/' do
  haml :index
end

Отрисует ./views/index.haml.

Опции Haml могут быть установлены глобально через конфигурацию Sinatra, см. Опции и Конфигурация, и переопределены локально.

set :haml, :format => :html5 # :xhtml - Haml формат по умолчанию

get '/' do
  haml :index, :format => :html4 # переопределен
end

Erb шаблоны

# Вам нужно будет подключить erb в приложении
require 'erb'

get '/' do
  erb :index
end

Отрисует ./views/index.erb.

Erubis шаблоны

erubis gem/библиотека необходима для рендеринга Erubis шаблонов:

# Вам нужно будет подключить Erubis в приложении
require 'erubis'

get '/' do
  erubis :index
end

Отрисует ./views/index.erubis.

Также возможно заменить Erb на Erubis:

require 'erubis'
Tilt.register :erb, Tilt[:erubis]

get '/' do
  erb :index
end

Отрисует ./views/index.erb с помощью Erubis.

Builder шаблоны

builder gem/библиотека необходима для рендеринга builder шаблонов:

# Вам нужно будет подключить builder в приложении
require 'builder'

get '/' do
  builder :index
end

Отрисует ./views/index.builder.

Nokogiri шаблоны

nokogiri gem/библиотека необходима для рендеринга nokogiri шаблонов:

# Вам нужно будет подключить nokogiri в приложении
require 'nokogiri'

get '/' do
  nokogiri :index
end

Отрисует ./views/index.nokogiri.

Sass шаблоны

haml gem/библиотека необходима для рендеринга Sass шаблонов:

# Вам нужно будет подключить haml или sass в приложении
require 'sass'

get '/stylesheet.css' do
  sass :stylesheet
end

Отрисует ./views/stylesheet.sass.

Опции Sass могут быть установлены глобально через конфигурацию Sinatra, см. Опции и Конфигурация, и переопределены локально.

set :sass, :style => :compact # :nested - стиль Sass по умолчанию

get '/stylesheet.css' do
  sass :stylesheet, :style => :expanded # переопределен
end

Scss шаблоны

haml gem/библиотека необходима для рендеринга Scss шаблонов:

# Вам нужно будет подключить haml или sass в приложении
require 'sass'

get '/stylesheet.css' do
  scss :stylesheet
end

Отрисует ./views/stylesheet.scss.

Опции Scss могут быть установлены глобально через конфигурацию Sinatra, см. Опции и Конфигурация, и переопределены локально.

set :scss, :style => :compact # :nested - стиль Scss по умолчанию

get '/stylesheet.css' do
  scss :stylesheet, :style => :expanded # переопределен
end

Less шаблоны

less gem/библиотека необходима для рендеринга Less шаблонов:

# Вам нужно будет подключить less в приложении
require 'less'

get '/stylesheet.css' do
  less :stylesheet
end

Отрисует ./views/stylesheet.less.

Liquid шаблоны

liquid gem/библиотека необходима для рендеринга liquid шаблонов:

# Вам нужно будет подключить liquid в приложении
require 'liquid'

get '/' do
  liquid :index
end

Отрисует ./views/index.liquid.

Так как в Liquid шаблонах невозможно вызывать методы из Ruby (кроме yield), то вы почти всегда будете передавать локальные переменные:

liquid :index, :locals => { :key => 'value' }

Markdown шаблоны

rdiscount gem/библиотека необходима для рендеринга Markdown шаблонов:

# Вам нужно будет подключить rdiscount в приложении
require "rdiscount"

get '/' do
  markdown :index
end

Отрисует ./views/index.markdown (md и mkd также являются допустимыми файловыми расширениями).

В Markdown невозможно вызывать методы или передавать локальные переменные. Следовательно, вам, скорее всего, придется использовать этот шаблон совместно с другим движком рендеринга:

erb :overview, :locals => { :text => markdown(:introduction) }

Заметьте, что вы можете вызывать метод markdown из других шаблонов:

%h1 Hello From Haml!
%p= markdown(:greetings)

Вы не можете вызывать Ruby из Markdown, соответственно, вы не можете использовать лэйаут-шаблоны (layouts) на Markdown. Тем не менее, есть возможность использовать один движок рендеринга для шаблона, а другой для лэйаута с помощью опции ‘:layout_engine`:

get '/' do
  markdown :index, :layout_engine => :erb
end

Отрисует ./views/index.md с ./views/layout.erb в качестве лэйаута.

Также вы можете задать такие опции рендеринга глобально:

set :markdown, :layout_engine => :haml, :layout => :post

get '/' do
  markdown :index
end

Отрисует ./views/index.md (и любой другой шаблон на Markdown) с ./views/post.haml в качестве лэйаута.

Также возможно обрабатывать Markdown с помощью BlueCloth, а не RDiscount:

require 'bluecloth'

Tilt.register 'markdown', BlueClothTemplate
Tilt.register 'mkd',      BlueClothTemplate
Tilt.register 'md',       BlueClothTemplate

get '/' do
  markdown :index
end

Отрисует ./views/index.md с помощью BlueCloth.

Textile шаблоны

RedCloth gem/библиотека необходима для рендеринга Textile шаблонов:

# Вам нужно будет подключить redcloth в приложении
require "redcloth"

get '/' do
  textile :index
end

Отрисует ./views/index.textile.

В Textile невозможно вызывать методы или передавать локальные переменные. Следовательно, вам, скорее всего, придется использовать этот шаблон совместно с другим движком рендеринга:

erb :overview, :locals => { :text => textile(:introduction) }

Заметьте, что вы можете вызывать метод textile из других шаблонов:

%h1 Hello From Haml!
%p= textile(:greetings)

Вы не можете вызывать Ruby из Textile, соответственно, вы не можете использовать лэйаут-шаблоны на Textile. Тем не менее, есть возможность использовать один движок рендеринга для шаблона, а другой для лэйаута с помощью опции ‘:layout_engine`:

get '/' do
  textile :index, :layout_engine => :erb
end

Отрисует ./views/index.textile с ./views/layout.erb в качестве лэйаута.

Также вы можете задать такие опции рендеринга глобально:

set :textile, :layout_engine => :haml, :layout => :post

get '/' do
  textile :index
end

Отрисует ./views/index.textile (и любой другой шаблон на Textile) с ./views/post.haml в качестве лэйаута.

RDoc шаблоны

rdoc gem/библиотека необходима для рендеринга RDoc шаблонов:

# Вам нужно будет подключить rdoc/markup/to_html в приложении
require "rdoc/markup/to_html"

get '/' do
  rdoc :index
end

Отрисует ./views/index.rdoc.

В RDoc невозможно вызывать методы или передавать локальные переменные. Следовательно, вам, скорее всего, придется использовать этот шаблон совместно с другим движком рендеринга:

erb :overview, :locals => { :text => rdoc(:introduction) }

Заметьте, что вы можете вызывать метод rdoc из других шаблонов:

%h1 Hello From Haml!
%p= rdoc(:greetings)

Вы не можете вызывать Ruby из RDoc, соответственно, вы не можете использовать лэйаут-шаблоны на RDoc. Тем не менее, есть возможность использовать один движок рендеринга для шаблона, а другой для лэйаута с помощью опции ‘:layout_engine`:

get '/' do
  rdoc :index, :layout_engine => :erb
end

Отрисует ./views/index.rdoc с ./views/layout.erb в качестве лэйаута.

Также вы можете задать такие опции рендеринга глобально:

set :rdoc, :layout_engine => :haml, :layout => :post

get '/' do
  rdoc :index
end

Отрисует ./views/index.rdoc (и любой другой шаблон на RDoc) с ./views/post.haml в качестве лэйаута.

Radius шаблоны

radius gem/библиотека необходима для рендеринга Radius шаблонов:

# Вам нужно будет подключить radius в приложении
require 'radius'

get '/' do
  radius :index
end

Отрисует ./views/index.radius.

Так как в Radius шаблоне невозможно вызывать методы из Ruby (кроме yield), то вы почти всегда будете передавать локальные переменные:

radius :index, :locals => { :key => 'value' }

Markaby шаблоны

markaby gem/библиотека необходима для рендеринга Markaby шаблонов:

# Вам нужно будет подключить markaby в приложении
require 'markaby'

get '/' do
  markaby :index
end

Отрисует ./views/index.mab.

Вы также можете использовать внутристроковые Markaby шаблоны:

get '/' do
  markaby { h1 "Welcome!" }
end

Slim шаблоны

slim gem/библиотека необходима для рендеринга slim шаблонов:

# Вам нужно будет подключить slim в приложении
require 'slim'

get '/' do
  slim :index
end

Отрисует ./views/index.slim.

CoffeeScript шаблоны

Вам понадобится coffee-script gem/библиотека и что-то одно из следующего списка, чтобы запускать JavaScript:

  • node (из Node.js)

  • вы можете использовать OSX (есть встроенные средства для выполнения JavaScript)

  • therubyracer gem/библиотека

Подробнее смотрите на странице проекта.

Таким образом вы можете использовать CoffeeScript шаблоны.

# Вам нужно будет подключить coffee-script в приложении
require 'coffee-script'

get '/application.js' do
  coffee :application
end

Отрисует ./views/application.coffee.

Встроенные шаблоны

get '/' do
  haml '%div.title Hello World'
end

Отрисует встроенный (строчный) шаблон.

Доступ к переменным в шаблонах

Шаблоны интерпретируются в том же контексте, что и обработчики маршрутов. Переменные экземпляра, установленные в процессе обработки маршрутов, будут доступны напрямую в шаблонах:

get '/:id' do
  @foo = Foo.find(params[:id])
  haml '%h1= @foo.name'
end

Либо установите их через хеш локальных переменных:

get '/:id' do
  foo = Foo.find(params[:id])
  haml '%h1= foo.name', :locals => { :foo => foo }
end

Это обычный подход, когда шаблоны рендерятся как частные (partials) из других шаблонов.

Вложенные шаблоны

Шаблоны также могут быть определены в конце файла-исходника:

require 'sinatra'

get '/' do
  haml :index
end

__END__

Заметьте: Вложенные шаблоны, определенные в файле-исходнике, который подключил Sinatra, будут автоматически загружены. Вызовите enable :inline_templates напрямую, если у вас вложенные шаблоны в других файлах.

Именные шаблоны

Шаблоны также могут быть определены, используя template метод:

template :layout do
  "%html\n  =yield\n"
end

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

get '/' do
  haml :index
end

Если шаблон с именем “layout” существует, то он будет использован каждый раз, когда шаблоны будут отрисовываться. Вы можете отключать лэйаут в каждом конкретном случае с помощью :layout => false или отключить его для всего приложения, например, так: set :haml, :layout => false.

get '/' do
  haml :index, :layout => !request.xhr?
end

Привязка файловых расширений

Чтобы связать расширение файла и движок рендеринга, используйте Tilt.register. Например, если вы хотите использовать расширение tt для шаблонов Textile:

Tilt.register :tt, Tilt[:textile]

Добавление собственного движка рендеринга

Сначала зарегистрируйте свой движок в Tilt, затем создайте метод, отвечающий за отрисовку:

Tilt.register :myat, MyAwesomeTemplateEngine

helpers do
  def myat(*args) render(:myat, *args) end
end

get '/' do
  myat :index
end

Отрисует ./views/index.myat. Чтобы узнать больше о Tilt, смотрите github.com/rtomayko/tilt

Методы-помощники

Используйте метод helpers, чтобы определить методы-помощники, которые в дальнейшем можно будет использовать в обработчиках маршрутов и шаблонах:

helpers do
  def bar(name)
    "#{name}bar"
  end
end

get '/:name' do
  bar(params[:name])
end

Фильтры

Before-фильтры выполняются перед каждым запросом в том же контексте, что и маршруты. Фильтры могут изменять как запрос, так и ответ на него. Переменные экземпляра, установленные в фильтрах, доступны в маршрутах и шаблонах:

before do
  @note = 'Hi!'
  request.path_info = '/foo/bar/baz'
end

get '/foo/*' do
  @note #=> 'Hi!'
  params[:splat] #=> 'bar/baz'
end

After-фильтры выполняются после каждого запроса в том же контексте, что и пути. Фильтры могут изменять как запрос, так и ответ на него. Переменные экземпляра, установленные в before-фильтрах и маршрутах, будут доступны в after-фильтрах:

after do
  puts response.status
end

Фильтры могут использовать шаблоны URL и будут интерпретированы, только если путь запроса совпадет с этим шаблоном:

before '/protected/*' do
  authenticate!
end

after '/create/:slug' do |slug|
  session[:last_slug] = slug
end

Как и маршруты, фильтры могут использовать условия:

before :agent => /Songbird/ do
  # ...
end

after '/blog/*', :host_name => 'example.com' do
  # ...
end

Прерывание

Чтобы незамедлительно прервать обработку запроса внутри фильтра или маршрута, используйте:

halt

Можно также указать статус при прерывании:

halt 410

Тело:

halt 'this will be the body'

И то, и другое:

halt 401, 'go away!'

Можно указать заголовки:

halt 402, {'Content-Type' => 'text/plain'}, 'revenge'

Передача

Маршрут может передать обработку запроса следующему совпадающему маршруту, используя pass:

get '/guess/:who' do
  pass unless params[:who] == 'Frank'
  'You got me!'
end

get '/guess/*' do
  'You missed!'
end

Блок маршрута сразу же прерывается, и контроль переходит к следующему совпадающему маршруту. Если соответствующий маршрут не найден, то ответом на запрос будет 404.

Доспут к объекту запроса

Объект входящего запроса доступен на уровне обработки запроса (в фильтрах, маршрутах, обработчиках ошибок) с помощью ‘request` метода:

# приложение запущено на http://example.com/example
get '/foo' do
  request.body              # тело запроса, посланное клиентом (см. ниже)
  request.scheme            # "http"
  request.script_name       # "/example"
  request.path_info         # "/foo"
  request.port              # 80
  request.request_method    # "GET"
  request.query_string      # ""
  request.content_length    # длина тела запроса
  request.media_type        # медиатип тела запроса
  request.host              # "example.com"
  request.get?              # true (есть аналоги для других методов HTTP)
  request.form_data?        # false
  request["SOME_HEADER"]    # значение заголовка SOME_HEADER
  request.referer           # источник запроса клиента либо '/'
  request.user_agent        # user agent (используется для :agent условия)
  request.cookies           # хеш с куками браузера
  request.xhr?              # является ли запрос ajax запросом?
  request.url               # "http://example.com/example/foo"
  request.path              # "/example/foo"
  request.ip                # IP-адрес клиента
  request.secure?           # false
  request.env               # "сырой" env хеш, полученный Rack
end

Некоторые опции, такие как script_name или path_info доступны для записи:

before { request.path_info = "/" }

get "/" do
  "all requests end up here"
end

request.body является IO или StringIO объектом:

post "/api" do
  request.body.rewind  # в случае, если кто-то уже прочитал тело запроса
  data = JSON.parse request.body.read
  "Hello #{data['name']}!"
end

Конфигурация

Этот блок исполняется один раз при старте в любом окружении, режиме (environment):

configure do
  ...
end

Будет запущено, когда окружение (RACK_ENV переменная) установлена в :production:

configure :production do
  ...
end

Будет запущено, когда окружение :production или :test:

configure :production, :test do
  ...
end

Обработка ошибок

Обработчики ошибок исполняются в том же контексте, что и маршруты, before-фильтры, а это означает, что всякие прелести вроде haml, erb, halt и т.д. доступны и им.

NotFound

Когда возбуждено исключение Sinatra::NotFound, или кодом ответа является 404, то будет вызван not_found обработчик:

not_found do
  'This is nowhere to be found.'
end

Ошибки

Обработчик ошибок error будет вызван, когда исключение возбуждено из блока маршрута, либо из фильтра. Объект-исключение доступен как переменная sinatra.error в Rack:

error do
  'Sorry there was a nasty error - ' + env['sinatra.error'].name
end

Частные ошибки:

error MyCustomError do
  'So what happened was...' + request.env['sinatra.error'].message
end

Тогда, если это произошло:

get '/' do
  raise MyCustomError, 'something bad'
end

То вы получите:

So what happened was... something bad

Также вы можете установить обработчик ошибок для кода состояния HTTP:

error 403 do
  'Access forbidden'
end

get '/secret' do
  403
end

Либо набора кодов:

error 400..510 do
  'Boom'
end

Sinatra устанавливает специальные not_found и error обработчики, когда запущена в режиме разработки (окружение :development).

Mime-типы

Когда вы используете send_file или статические файлы, у вас могут быть mime-типы, которые Sinatra не понимает по умолчанию. Используйте mime_type для их регистрации по расширению файла:

mime_type :foo, 'text/foo'

Вы также можете использовать это в content_type помощнике:

content_type :foo

Rack “прослойки”

Sinatra использует Rack, минимальный стандартный интерфейс для веб-фреймворков на Ruby. Одной из самых интересных для разработчиков возможностей Rack является поддержка “прослоек” (“middleware”) — компонентов, “сидящих” между сервером и вашим приложением, которые отслеживают и/или манипулируют HTTP запросами/ответами для предоставления различной функциональности.

В Sinatra очень просто использовать такие “прослойки” с помощью метода use:

require 'sinatra'
require 'my_custom_middleware'

use Rack::Lint
use MyCustomMiddleware

get '/hello' do
  'Hello World'
end

Семантика use идентична той, что определена для Rack::Builder DSL (чаще всего используется в rackup файлах). Например, use метод принимает множественные переменные, также как и блоки:

use Rack::Auth::Basic do |username, password|
  username == 'admin' && password == 'secret'
end

Rack распространяется с различными стандартными “прослойками” для логирования, отладки, маршрутизации URL, аутентификации, обработки сессий. Sinatra использует многие из этих компонентов автоматически, основываясь на конфигурации, чтобы вам не приходилось регистрировать/использовать (use) их вручную.

Тестирование

Тесты для Sinatra приложений могут быть написаны с помощью библиотек, фреймворков, поддерживающих тестирование Rack. Rack::Test рекомендован:

require 'my_sinatra_app'
require 'test/unit'
require 'rack/test'

class MyAppTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    Sinatra::Application
  end

  def test_my_default
    get '/'
    assert_equal 'Hello World!', last_response.body
  end

  def test_with_params
    get '/meet', :name => 'Frank'
    assert_equal 'Hello Frank!', last_response.body
  end

  def test_with_rack_env
    get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
    assert_equal "You're using Songbird!", last_response.body
  end
end

Обратите внимание: Встроенные модуль Sinatra::Test и класс Sinatra::TestHarness являются устаревшими, начиная с релиза 0.9.2.

Sinatra::Base — “прослойки”, библиотеки и модульные приложения

Описание своего приложения самым простейшим способом (с помощью DSL верхнего уровня, как в примерах выше) работает отлично для крохотных приложений, но имеет множество недостатков, когда надо создать компоненты, такие как Rack middleware (“прослойки”), Rails metal, простые библиотеки с серверными компонентами, расширения Sinatra. DSL верхнего уровня загрязняет пространство имен Object и подразумевает стиль конфигурации микро-приложения (например, единый файл приложения, ./public и ./views директории, создание логов, страницу деталей об исключениях и т.д.). И тут на помощь приходит Sinatra::Base:

require 'sinatra/base'

class MyApp < Sinatra::Base
  set :sessions, true
  set :foo, 'bar'

  get '/' do
    'Hello world!'
  end
end

Методы, доступные Sinatra::Base сабклассам идентичны тем, что доступны в DSL верхнего уровня. Большинство приложений верхнего уровня могут быть конвертированы в Sinatra::Base компоненты с помощью двух модификаций:

  • Вы должны подключать sinatra/base вместо sinatra, иначе все методы предоставляемые Sinatra будут импортированные в глобальное пространство имен.

  • Поместите все маршруты, обработчики ошибок, фильтры и опции в сабкласс Sinatra::Base.

Sinatra::Base — это чистый лист. Большинство опций, включая встроенный сервер, по умолчанию отключены. Смотрите Опции и Конфигурация для детальной информации об опциях и их поведении.

Запуск модульных приложений

Есть два общепринятых способа запускать модульные приложения: запуск напрямую с помощью run!:

# my_app.rb
require 'sinatra/base'

class MyApp < Sinatra::Base
  # ... здесь код приложения ...

  # запускаем сервер, если исполняется текущий файл
  run! if app_file == $0
end

И запускаем с помощью:

ruby my_app.rb

Или с помощью конфигурационного файла config.ru, который позволяет использовать любой Rack-совместимый сервер приложений.

# config.ru
require './my_app'
run MyApp

Запускаем:

rackup -p 4567

Запуск “классических” приложений с config.ru

Файл приложения:

# app.rb
require 'sinatra'

get '/' do
  'Hello world!'
end

И соответствующий config.ru:

require './app'
run Sinatra::Application

Когда использовать config.ru?

Вот несколько причин, по которым вы, возможно, захотите использовать config.ru:

  • вы хотите разворачивать свое приложение на различных Rack-совместимых серверах (Passenger, Unicorn, Heroku, …).

  • вы хотите использовать более одного сабкласса Sinatra::Base.

  • вы хотите использовать Sinatra только в качестве “прослойки” Rack.

Совсем необязательно переходить на использование config.ru лишь потому, что вы стали использовать модульный стиль приложения. И необязательно использовать модульный стиль, чтобы запускать приложение с помощью config.ru.

Использование Sinatra в качестве “прослойки”

Не только сама Sinatra может использовать “прослойки” Rack, но и любое Sinatra приложение само может быть добавлено к любому Rack эндпоинту в качестве “прослойки”. Этим эндпоинтом может быть другое Sinatra приложение, или приложение, основанное на Rack (Rails/Ramaze/Camping/…).

require 'sinatra/base'

class LoginScreen < Sinatra::Base
  enable :sessions

  get('/login') { haml :login }

  post('/login') do
    if params[:name] = 'admin' and params[:password] = 'admin'
      session['user_name'] = params[:name]
    else
      redirect '/login'
    end
  end
end

class MyApp < Sinatra::Base
  # "прослойка" будет запущена перед фильтрами
  use LoginScreen

  before do
    unless session['user_name']
      halt "Access denied, please <a href='/login'>login</a>."
    end
  end

  get('/') { "Hello #{session['user_name']}." }
end

Области видимости и привязка

Текущая область видимости определяет методы и переменные, доступные в данный момент.

Область видимости приложения / класса

Любое Sinatra приложение соответствует сабклассу Sinatra::Base. Если вы используете DSL верхнего уровня (require 'sinatra'), то этим классом будет Sinatra::Application, иначе это будет сабкласс, который вы создали вручную. На уровне класса вам будут доступны такие методы, как ‘get` или `before`, но вы не сможете иметь доступ к объектам `request` или `session`, так как существует только единый класс приложения для всех запросов.

Опции, созданные с помощью ‘set`, являются методами уровня класса:

class MyApp < Sinatra::Base
  # Я в области видимости приложения!
  set :foo, 42
  foo # => 42

  get '/foo' do
    # Я больше не в области видимости приложения!
  end
end

У вас будет область видимости приложения внутри:

  • Тела вашего класса приложения

  • Методов, определенных расширениями

  • Блока, переданного в ‘helpers`

  • Блоков, использованных как значения для ‘set`

Вы можете получить доступ к объекту области видимости (классу приложения) следующими способами:

  • объект, переданный блокам конфигурации (configure { |c| ... })

  • ‘settings` внутри области видимости запроса

Область видимости запроса/экземпляра

Для каждого входящего запроса будет создан новый экземпляр вашего приложения, и все блоки обработчика будут запущены в этом контексте. В этой области видимости вам доступны ‘request` и `session` объекты, вызовы методов рендеринга, такие как `erb` или `haml`. Вы можете получить доступ к области видимости приложения из контекста запроса, используя помощник `settings`:

class MyApp < Sinatra::Base
  # Я в области видимости приложения!
  get '/define_route/:name' do
    # Область видимости запроса '/define_route/:name'
    @value = 42

    settings.get("/#{params[:name]}") do
      # Область видимости запроса "/#{params[:name]}"
      @value # => nil (другой запрос)
    end

    "Route defined!"
  end
end

У вас будет область видимости запроса внутри:

  • get/head/post/put/delete/options блоков

  • before/after фильтрах

  • методах помощниках

  • шаблонах/видах

Область видимости делегирования

Область видимости делегирования просто перенаправляет методы в область видимости класса. Однако, оно не полностью на 100% ведет себя как область видимости класса, так как у вас нету привязки к классу: только методы, явно помеченные для делегирования, будут доступны, а переменных/состояний области видимости класса не будет (иначе говоря, у вас будет другой ‘self` объект). Вы можете непосредственно добавить методы делегирования, используя Sinatra::Delegator.delegate :method_name.

У вас будет контекст делегирования внутри:

  • Привязки верхнего уровня, если вы сделали require "sinatra"

  • Объекта, расширенного с помощью примеси ‘Sinatra::Delegator`

Посмотрите сами в код: тут Sinatra::Delegator примесь будет включена в глобальное пространство имен.

Командная строка

Sinatra приложения могут быть запущены напрямую:

ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]

Опции включают:

-h # помощь
-p # настроить порт (по умолчанию 4567)
-o # настроить хост (по умолчанию 0.0.0.0)
-e # настроить окружение, режим (по умолчанию development)
-s # настроить rack сервер/обработчик (по умолчанию thin)
-x # включить мьютекс (по умолчанию выключен)

На острие

Если вы хотите использовать самый последний код Sinatra, не бойтесь запускать свое приложение вместе с master бранчем Sinatra, он весьма стабилен.

Мы также время от времени выпускаем предварительные версии, так что вы можете делать так:

gem install sinatra --pre

Чтобы воспользоваться некоторыми самыми последними возможностям.

С помощью Bundler

Если вы хотите запускать свое приложение с последней версией Sinatra, то рекомендуем использовать Bundler.

Сначала установите Bundler, если у вас его еще нет:

gem install bundler

Затем создайте файл Gemfile в директории вашего проекта:

source :rubygems
gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"

# другие зависимости
gem 'haml'                    # например, если используете haml
gem 'activerecord', '~> 3.0'  # может быть, вам нужен и ActiveRecord 3.x

Обратите внимание, вам нужно будет указывать все зависимости вашего приложения в этом файле. Однако, непосредственные зависимости Sinatra (Rack и Tilt) Bundler автоматически скачает и добавит.

Теперь вы можете запускать свое приложение примерно так:

bundle exec ruby myapp.rb

Вручную

Создайте локальный клон репозитория и запускайте свое приложение с sinatra/lib директорией в LOAD_PATH:

cd myapp
git clone git://github.com/sinatra/sinatra.git
ruby -Isinatra/lib myapp.rb

Чтобы обновить исходники Sinatra:

cd myapp/sinatra
git pull

Установка глобально

Вы можете самостоятельно собрать gem:

git clone git://github.com/sinatra/sinatra.git
cd sinatra
rake sinatra.gemspec
rake install

Если вы устанавливаете пакеты (gem) от пользователя root, то вашим последним шагом должна быть команда

sudo rake install

Дальнейшее чтение