Sinatra는 최소한의 노력으로 Ruby로 웹 애플리케이션을 빠르게 생성하기 위한 DSL입니다.
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
필요한 보석을 설치합니다:
gem install sinatra rackup puma
그리고 다음과 같이 실행하세요:
ruby myapp.rb
보기: http://localhost:4567
변경한 코드는 서버를 다시 시작할 때까지 적용되지 않습니다. Rerun이나 Rack-Unreloader와 같은 코드 리로더를 사용하거나 변경할 때마다 서버를 다시 시작하십시오.
가능한 경우 Sinatra가 선택하는 gem install puma
실행하는 것도 권장됩니다.
yield
및 중첩 레이아웃이 있는 템플릿Sinatra에서 경로는 URL 일치 패턴과 쌍을 이루는 HTTP 메서드입니다. 각 경로는 블록과 연결됩니다.
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
경로 패턴에는 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_opts
해시를 전달하여 특정 경로에 사용되는 Mustermann 옵션을 사용자 정의할 수 있습니다.
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
요청의 Accept 헤더 검색을 provides
.
자신만의 조건을 쉽게 정의할 수 있습니다.
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 body 객체 또는 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
로 제공됩니다.
Cache-Control
헤더 정보를 추가하려면 :static_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/post.erb
에 포함된 views/index.erb
가 렌더링됩니다(기본값은 views/layout.erb
, 존재하는 경우).
Sinatra가 이해하지 못하는 모든 옵션은 템플릿 엔진으로 전달됩니다:
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에만 해당) |
예 | 어브:인덱스 |
의존 | 건축업자 |
파일 확장자 | .builder |
예 | 빌더 { |xml| xml.em "안녕" } |
또한 인라인 템플릿에 대한 블록도 필요합니다(예제 참조).
의존 | 노코기리 |
파일 확장자 | .nokogiri |
예 | 노코기리 { |xml| xml.em "안녕" } |
또한 인라인 템플릿에 대한 블록도 필요합니다(예제 참조).
의존 | Sass 내장 |
파일 확장자 | .sass |
예 | sass :스타일시트, :스타일 => :확장 |
의존 | Sass 내장 |
파일 확장자 | .scss |
예 | scss :스타일시트, :스타일 => :확장됨 |
의존 | 액체 |
파일 확장자 | .액체 |
예 | liquid :index, :locals => { :key => '값' } |
Liquid 템플릿에서는 Ruby 메서드( yield
제외)를 호출할 수 없으므로 거의 항상 로컬을 전달하려고 합니다.
의존 | 다음 중 하나: 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 )
Markdown에서는 Ruby를 호출할 수 없기 때문에 Markdown으로 작성된 레이아웃을 사용할 수 없습니다. 그러나 :layout_engine
옵션을 전달하면 레이아웃이 아닌 템플릿에 다른 렌더링 엔진을 사용할 수 있습니다.
의존 | RDoc |
파일 확장자 | .rdoc |
예 | rdoc :README, :layout_engine => :erb |
RDoc에서 메서드를 호출하거나 로컬을 전달할 수 없습니다. 따라서 일반적으로 다른 렌더링 엔진과 함께 사용합니다.
erb :overview , :locals => { :text => rdoc ( :introduction ) }
다른 템플릿 내에서 rdoc
메소드를 호출할 수도 있습니다.
% h1 Hello From Haml!
% p = rdoc ( :greetings )
RDoc에서는 Ruby를 호출할 수 없으므로 RDoc으로 작성된 레이아웃을 사용할 수 없습니다. 그러나 :layout_engine
옵션을 전달하면 레이아웃이 아닌 템플릿에 다른 렌더링 엔진을 사용할 수 있습니다.
의존 | Asciidoctor |
파일 확장자 | .asciidoc , .adoc 및 .ad |
예 | asciidoc :README, :layout_engine => :erb |
AsciiDoc 템플릿에서 Ruby 메소드를 직접 호출할 수 없기 때문에 거의 항상 로컬을 전달하려고 합니다.
의존 | 마카비 |
파일 확장자 | .mab |
예 | markaby { h1 "환영합니다!" } |
또한 인라인 템플릿에 대한 블록도 필요합니다(예제 참조).
의존 | 라블 |
파일 확장자 | .rabl |
예 | rabl :인덱스 |
의존 | 슬림랭 |
파일 확장자 | .아주 적은 |
예 | 슬림:인덱스 |
의존 | yajl-루비 |
파일 확장자 | .yajl |
예 | 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"이라는 템플릿이 존재하는 경우 템플릿이 렌더링될 때마다 해당 템플릿이 사용됩니다. :layout => false
전달하여 레이아웃을 개별적으로 비활성화하거나 set :haml, :layout => false
통해 기본적으로 비활성화할 수 있습니다.
get '/' do
haml :index , :layout => ! request . xhr?
end
파일 확장자를 템플릿 엔진과 연결하려면 Tilt.register
사용하세요. 예를 들어 Haml 템플릿에 파일 확장자 tt
사용하려는 경우 다음을 수행할 수 있습니다.
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 do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
경로와 동일한 컨텍스트 내의 각 요청 후에 필터가 평가된 후 요청 및 응답을 수정할 수도 있습니다. 이전 필터 및 경로에 설정된 인스턴스 변수는 이후 필터에서 액세스할 수 있습니다.
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
메서드를 사용하여 경로 처리기 및 템플릿에 사용할 도우미 메서드를 정의합니다.