Sinatra — это DSL для быстрого создания веб-приложений на Ruby с минимальными усилиями:
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
Установите необходимые драгоценные камни:
gem install sinatra rackup puma
И запустите:
ruby myapp.rb
Посмотреть по адресу: http://localhost:4567.
Измененный вами код не вступит в силу, пока вы не перезапустите сервер. Пожалуйста, перезагружайте сервер каждый раз, когда вы меняете или используете перезагрузку кода, например rerun илиrack-unreloader.
Рекомендуется также запустить gem install puma
, который Синатра подберет, если он доступен.
yield
и вложенными макетамиВ Синатре маршрут — это метод HTTP в сочетании с шаблоном сопоставления URL-адресов. Каждый маршрут связан с блоком:
get '/' do
.. show something ..
end
post '/' do
.. create something ..
end
put '/' do
.. replace something ..
end
patch '/' do
.. modify something ..
end
delete '/' do
.. annihilate something ..
end
options '/' do
.. appease something ..
end
link '/' do
.. affiliate something ..
end
unlink '/' do
.. separate something ..
end
Маршруты сопоставляются в том порядке, в котором они определены. Вызывается первый маршрут, соответствующий запросу.
Маршруты с косой чертой на конце отличаются от маршрутов без:
get '/foo' do
# Does not match "GET /foo/"
end
Шаблоны маршрутов могут включать именованные параметры, доступные через хэш params
:
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
Вы также можете получить доступ к именованным параметрам через параметры блока:
get '/hello/:name' do | n |
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
# n stores params['name']
"Hello #{ n } !"
end
Шаблоны маршрутов также могут включать параметры splat (или подстановочные знаки), доступные через массив params['splat']
:
get '/say/*/to/*' do
# matches /say/hello/to/world
params [ 'splat' ] # => ["hello", "world"]
end
get '/download/*.*' do
# matches /download/path/to/file.xml
params [ 'splat' ] # => ["path/to/file", "xml"]
end
Или с параметрами блока:
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
Сопоставление маршрутов с помощью регулярных выражений:
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
Или с параметром блока:
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
Шаблоны маршрутов могут иметь дополнительные параметры:
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
Маршруты также могут использовать параметры запроса:
get '/posts' do
# matches "GET /posts?title=foo&author=bar"
title = params [ 'title' ]
author = params [ 'author' ]
# uses title and author variables; query is optional to the /posts route
end
Кстати, если вы не отключите защиту от атак обхода пути (см. ниже), путь запроса может быть изменен перед сопоставлением с вашими маршрутами.
Вы можете настроить параметры Mustermann, используемые для данного маршрута, передав хеш :mustermann_opts
:
get 'A/postsz' , :mustermann_opts => { :type => :regexp , :check_anchors => false } do
# matches /posts exactly, with explicit anchoring
"If you match an anchored pattern clap your hands!"
end
Это похоже на состояние, но это не так! Эти параметры будут объединены в глобальный хэш :mustermann_opts
описанный ниже.
Маршруты могут включать в себя различные условия соответствия, например пользовательский агент:
get '/foo' , :agent => /Songbird ( d . d )[ d / ]*?/ do
"You're using Songbird version #{ params [ 'agent' ] [ 0 ] } "
end
get '/foo' do
# Matches non-songbird browsers
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
provides
поиск по заголовку Accept запроса.
Вы можете легко определить свои собственные условия:
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
Для условия, которое принимает несколько значений, используйте знак:
set ( :auth ) do |* roles | # <- notice the splat here
condition do
unless logged_in? && roles . any? { | role | current_user . in_role? role }
redirect "/login/" , 303
end
end
end
get "/my/account/" , :auth => [ :user , :admin ] do
"Your Account Details"
end
get "/only/admin/" , :auth => :admin do
"Only admins are allowed here!"
end
Возвращаемое значение блока маршрута определяет, по крайней мере, тело ответа, передаваемое HTTP-клиенту, или, по крайней мере, следующему промежуточному программному обеспечению в стеке Rack. Чаще всего это строка, как в приведенных выше примерах. Но принимаются и другие ценности.
Вы можете вернуть объект, который может быть действительным ответом Rack, объектом тела Rack или кодом состояния HTTP:
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
и не передает в данный блок ничего, кроме строк.Таким образом мы можем, например, легко реализовать пример потоковой передачи:
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
Вы также можете использовать вспомогательный метод stream
(описанный ниже), чтобы уменьшить шаблонность и встроить логику потоковой передачи в маршрут.
Как показано выше, Sinatra поставляется со встроенной поддержкой использования строковых шаблонов и регулярных выражений в качестве сопоставлений маршрутов. Однако на этом дело не заканчивается. Вы можете легко определить свои собственные сопоставители:
class AllButPattern
def initialize ( except )
@except = except
end
def to_pattern ( options )
return self
end
def params ( route )
return { } unless @except === route
end
end
def all_but ( pattern )
AllButPattern . new ( pattern )
end
get all_but ( "/index" ) do
# ...
end
Обратите внимание, что приведенный выше пример может быть переработанным, поскольку его также можно выразить следующим образом:
get /.*/ do
pass if request . path_info == "/index"
# ...
end
Статические файлы обслуживаются из каталога ./public
. Вы можете указать другое местоположение, установив опцию :public_folder
:
set :public_folder , __dir__ + '/static'
Обратите внимание, что имя общедоступного каталога не включено в URL-адрес. Файл ./public/css/style.css
доступен по адресу http://example.com/css/style.css
.
Используйте параметр :static_cache_control
(см. ниже), чтобы добавить информацию заголовка Cache-Control
.
Каждый язык шаблонов предоставляется через собственный метод рендеринга. Эти методы просто возвращают строку:
get '/' do
erb :index
end
Это отображает views/index.erb
.
Вместо имени шаблона вы также можете просто передать содержимое шаблона напрямую:
get '/' do
code = "<%= Time.now %>"
erb code
end
Шаблоны принимают второй аргумент — хэш опций:
get '/' do
erb :index , :layout => :post
end
Это отобразит views/index.erb
встроенные views/post.erb
(по умолчанию views/layout.erb
, если он существует).
Любые параметры, не понятные Синатре, будут переданы в шаблонизатор:
get '/' do
haml :index , :format => :html5
end
Вы также можете установить параметры для каждого языка шаблона в целом:
set :haml , :format => :html5
get '/' do
haml :index
end
Параметры, передаваемые в метод рендеринга, переопределяют параметры, установленные через set
.
Доступные опции:
Предполагается, что шаблоны расположены непосредственно в каталоге ./views
. Чтобы использовать другой каталог представлений:
set :views , settings . root + '/templates'
Важно помнить, что вам всегда нужно ссылаться на шаблоны с помощью символов, даже если они находятся в подкаталоге (в этом случае используйте: :'subdir/template'
или 'subdir/template'.to_sym
). Вы должны использовать символ, потому что в противном случае методы рендеринга будут отображать любые строки, переданные им напрямую.
get '/' do
haml '%div.title Hello World'
end
Отображает строку шаблона. При желании вы можете указать :path
и :line
для более четкой обратной трассировки, если с этой строкой связан путь или строка файловой системы:
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
Некоторые языки имеют несколько реализаций. Чтобы указать, какую реализацию использовать (и обеспечить потокобезопасность), вам нужно просто сначала потребовать ее:
require 'rdiscount'
get ( '/' ) { markdown :index }
Зависимость | хамл |
Расширение файла | .haml |
Пример | haml :index, :format => :html5 |
Зависимость | erubi или erb (входит в Ruby) |
Расширения файлов | .erb , .rhtml или .erubi (только Erubi) |
Пример | эрб: индекс |
Зависимость | строитель |
Расширение файла | .строитель |
Пример | строитель { |xml| xml.em "привет" } |
Также требуется блок для встроенных шаблонов (см. пример).
Зависимость | нокогири |
Расширение файла | .нокогири |
Пример | нокогири { |xml| xml.em "привет" } |
Также требуется блок для встроенных шаблонов (см. пример).
Зависимость | встроенный в sass |
Расширение файла | .дерзость |
Пример | sass :stylesheet, :style => :expanded |
Зависимость | встроенный в sass |
Расширение файла | .scss |
Пример | scss: таблица стилей,: стиль =>: расширенный |
Зависимость | жидкость |
Расширение файла | .жидкость |
Пример | Liquid :index, :locals => { :key => 'value' } |
Поскольку вы не можете вызывать методы Ruby (за исключением yield
) из шаблона Liquid, вы почти всегда хотите передать ему локальные значения.
Зависимость | Любой из: RDiscount, RedCarpet, kramdown, commonmarker pandoc. |
Расширения файлов | .markdown , .mkd и .md |
Пример | уценка :index, :layout_engine => :erb |
Невозможно вызывать методы из Markdown или передавать в него локальные значения. Поэтому вы обычно будете использовать его в сочетании с другим механизмом рендеринга:
erb :overview , :locals => { :text => markdown ( :introduction ) }
Обратите внимание, что вы также можете вызвать метод markdown
из других шаблонов:
% h1 Hello From Haml!
% p = markdown ( :greetings )
Поскольку вы не можете вызвать Ruby из Markdown, вы не можете использовать макеты, написанные в Markdown. Однако для шаблона можно использовать другой механизм рендеринга, отличный от макета, передав параметр :layout_engine
.
Зависимость | РДок |
Расширение файла | .rdoc |
Пример | rdoc :README, :layout_engine => :erb |
Невозможно вызвать методы из RDoc или передать ему локальные значения. Поэтому вы обычно будете использовать его в сочетании с другим механизмом рендеринга:
erb :overview , :locals => { :text => rdoc ( :introduction ) }
Обратите внимание, что вы также можете вызвать метод rdoc
из других шаблонов:
% h1 Hello From Haml!
% p = rdoc ( :greetings )
Поскольку вы не можете вызвать Ruby из RDoc, вы не можете использовать макеты, написанные на RDoc. Однако для шаблона можно использовать другой механизм рендеринга, отличный от макета, передав параметр :layout_engine
.
Зависимость | Аскиидоктор |
Расширение файла | .asciidoc , .adoc и .ad |
Пример | asciidoc :README, :layout_engine => :erb |
Поскольку вы не можете вызывать методы Ruby непосредственно из шаблона AsciiDoc, вам почти всегда нужно передавать в него локальные значения.
Зависимость | Маркабы |
Расширение файла | .маб |
Пример | markaby { h1 "Добро пожаловать!" } |
Также требуется блок для встроенных шаблонов (см. пример).
Зависимость | Рабл |
Расширение файла | .рабль |
Пример | Рабл: индекс |
Зависимость | Слим Ланг |
Расширение файла | .стройный |
Пример | тонкий: индекс |
Зависимость | Яджл-Рубин |
Расширение файла | .яйл |
Пример | yajl :index, :locals => { :key => 'qux' }, :callback => 'присутствует', :variable => 'ресурс' |
Исходный код шаблона оценивается как строка Ruby, а результирующая переменная json преобразуется с помощью #to_json
:
json = { :foo => 'bar' }
json [ :baz ] = key
Опции :callback
и :variable
можно использовать для украшения отображаемого объекта:
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
Шаблоны оцениваются в том же контексте, что и обработчики маршрутов. Переменные экземпляра, установленные в обработчиках маршрутов, напрямую доступны из шаблонов:
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
Или укажите явный хэш локальных переменных:
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
Обычно это используется при рендеринге шаблонов как частей из других шаблонов.
yield
и вложенными макетами Макет обычно представляет собой просто шаблон, который вызывает yield
. Такой шаблон можно использовать либо с помощью опции :template
, как описано выше, либо его можно визуализировать с помощью блока следующим образом:
erb :post , :layout => false do
erb :index
end
Этот код по большей части эквивалентен erb :index, :layout => :post
.
Передача блоков методам рендеринга наиболее полезна для создания вложенных макетов:
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
Это также можно сделать с помощью меньшего количества строк кода:
erb :admin_layout , :layout => :main_layout do
erb :user
end
В настоящее время блок принимают следующие методы рендеринга: erb
, haml
, liquid
, slim
. Кроме того, общий метод render
принимает блок.
Шаблоны могут быть определены в конце исходного файла:
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 => false
, или отключить их по умолчанию с помощью set :haml, :layout => false
:
get '/' do
haml :index , :layout => ! request . xhr?
end
Чтобы связать расширение файла с механизмом шаблонов, используйте Tilt.register
. Например, если вы хотите использовать расширение файла tt
для шаблонов Haml, вы можете сделать следующее:
Tilt . register Tilt [ :haml ] , :tt
Сначала зарегистрируйте свой движок в Tilt, затем создайте метод рендеринга:
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
Рендерит ./views/index.myat
. Узнайте больше о Тилте.
Чтобы реализовать собственный механизм поиска шаблонов, вы можете написать собственный метод #find_template
:
configure do
set :views , [ './views/a' , './views/b' ]
end
def find_template ( views , name , engine , & block )
Array ( views ) . each do | v |
super ( v , name , engine , & block )
end
end
Фильтры Before оцениваются перед каждым запросом в том же контексте, что и маршруты, и могут изменять запрос и ответ. Переменные экземпляра, установленные в фильтрах, доступны по маршрутам и шаблонам:
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
Фильтры After оцениваются после каждого запроса в том же контексте, что и маршруты, а также могут изменять запрос и ответ. Переменные экземпляра, установленные перед фильтрами и маршрутами, доступны после фильтров:
after do
puts response . status
end
Примечание. Если вы не используете метод body
, а не просто возвращаете строку из маршрутов, тело еще не будет доступно в фильтре after, поскольку оно генерируется позже.
Фильтры опционально используют шаблон, поэтому они будут оцениваться только в том случае, если путь запроса соответствует этому шаблону:
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
Используйте helpers
метод верхнего уровня, чтобы определить вспомогательные методы для использования в обработчиках маршрутов и шаблонах: