= Sinatra Внимание: Этот документ является переводом Английской версии и может быть устаревшим Sinatra — это предметно-ориентированный язык (DSL) для быстрого создания приложений на Ruby с приложением минимума усилий: # myapp.rb require 'sinatra' get '/' do 'Hello world!' end Установите gem и запустите приложение с помощью: gem install sinatra ruby -rubygems myapp.rb Результат будет тут: http://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}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options] могут быть установлены глобально через конфигурацию Sinatra, см. {Опции и Конфигурация}[http://www.sinatrarb.com/configuration.html], и переопределены локально. 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}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options] могут быть установлены глобально через конфигурацию Sinatra, см. {Опции и Конфигурация}[http://www.sinatrarb.com/configuration.html], и переопределены локально. 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}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options] могут быть установлены глобально через конфигурацию Sinatra, см. {Опции и Конфигурация}[http://www.sinatrarb.com/configuration.html], и переопределены локально. 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 в приложении require "rdoc" 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/библиотека Подробнее смотрите на {странице проекта}[http://github.com/josh/ruby-coffee-script]. Таким образом вы можете использовать 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__ @@ layout %html = yield @@ index %div.title Hello world!!!!! Заметьте: Вложенные шаблоны, определенные в файле-исходнике, который подключил 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, смотрите https://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[http://rack.rubyforge.org/], минимальный стандартный интерфейс для веб-фреймворков на 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[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL (чаще всего используется в rackup файлах). Например, +use+ метод принимает множественные переменные, также как и блоки: use Rack::Auth::Basic do |username, password| username == 'admin' && password == 'secret' end Rack распространяется с различными стандартными "прослойками" для логирования, отладки, маршрутизации URL, аутентификации, обработки сессий. Sinatra использует многие из этих компонентов автоматически, основываясь на конфигурации, чтобы вам не приходилось регистрировать/использовать (+use+) их вручную. == Тестирование Тесты для Sinatra приложений могут быть написаны с помощью библиотек, фреймворков, поддерживающих тестирование Rack. {Rack::Test}[http://gitrdoc.com/brynary/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 — это чистый лист. Большинство опций, включая встроенный сервер, по умолчанию отключены. Смотрите {Опции и Конфигурация}[http://www.sinatrarb.com/configuration.html] для детальной информации об опциях и их поведении. === Запуск модульных приложений Есть два общепринятых способа запускать модульные приложения: запуск напрямую с помощью 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 login." 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 примесь}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128] будет {включена в глобальное пространство имен}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28]. == Командная строка 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}[http://gembundler.com/]. Сначала установите 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 == Дальнейшее чтение * {Вебсайт проекта}[http://www.sinatrarb.com/] - Дополнительная документация, новости и ссылки на другие ресурсы. * {Участие}[http://www.sinatrarb.com/contributing] - Нашли баг? Нужна помощь? Написали патч? * {Слежение за проблемами}[http://github.com/sinatra/sinatra/issues] * {Twitter}[http://twitter.com/sinatra] * {Лист рассылки}[http://groups.google.com/group/sinatrarb/topics] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net