sinatra-acd 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/AUTHORS +61 -0
  4. data/CHANGES +1293 -0
  5. data/Gemfile +76 -0
  6. data/LICENSE +23 -0
  7. data/README.de.md +2864 -0
  8. data/README.es.md +2786 -0
  9. data/README.fr.md +2924 -0
  10. data/README.hu.md +694 -0
  11. data/README.ja.md +2726 -0
  12. data/README.ko.md +2832 -0
  13. data/README.md +2980 -0
  14. data/README.pt-br.md +965 -0
  15. data/README.pt-pt.md +791 -0
  16. data/README.ru.md +2799 -0
  17. data/README.zh.md +2158 -0
  18. data/Rakefile +199 -0
  19. data/examples/chat.rb +61 -0
  20. data/examples/simple.rb +3 -0
  21. data/examples/stream.ru +26 -0
  22. data/lib/sinatra.rb +4 -0
  23. data/lib/sinatra/base.rb +2044 -0
  24. data/lib/sinatra/images/404.png +0 -0
  25. data/lib/sinatra/images/500.png +0 -0
  26. data/lib/sinatra/main.rb +34 -0
  27. data/lib/sinatra/show_exceptions.rb +345 -0
  28. data/lib/sinatra/version.rb +3 -0
  29. data/sinatra.gemspec +19 -0
  30. data/test/asciidoctor_test.rb +72 -0
  31. data/test/base_test.rb +171 -0
  32. data/test/builder_test.rb +91 -0
  33. data/test/coffee_test.rb +90 -0
  34. data/test/compile_test.rb +183 -0
  35. data/test/contest.rb +100 -0
  36. data/test/creole_test.rb +65 -0
  37. data/test/delegator_test.rb +160 -0
  38. data/test/encoding_test.rb +20 -0
  39. data/test/erb_test.rb +116 -0
  40. data/test/extensions_test.rb +98 -0
  41. data/test/filter_test.rb +487 -0
  42. data/test/haml_test.rb +109 -0
  43. data/test/helper.rb +131 -0
  44. data/test/helpers_test.rb +1917 -0
  45. data/test/integration/app.rb +79 -0
  46. data/test/integration_helper.rb +236 -0
  47. data/test/integration_test.rb +104 -0
  48. data/test/less_test.rb +69 -0
  49. data/test/liquid_test.rb +77 -0
  50. data/test/mapped_error_test.rb +285 -0
  51. data/test/markaby_test.rb +80 -0
  52. data/test/markdown_test.rb +82 -0
  53. data/test/mediawiki_test.rb +68 -0
  54. data/test/middleware_test.rb +68 -0
  55. data/test/nokogiri_test.rb +67 -0
  56. data/test/public/favicon.ico +0 -0
  57. data/test/rabl_test.rb +89 -0
  58. data/test/rack_test.rb +45 -0
  59. data/test/radius_test.rb +59 -0
  60. data/test/rdoc_test.rb +66 -0
  61. data/test/readme_test.rb +130 -0
  62. data/test/request_test.rb +97 -0
  63. data/test/response_test.rb +63 -0
  64. data/test/result_test.rb +76 -0
  65. data/test/route_added_hook_test.rb +59 -0
  66. data/test/routing_test.rb +1412 -0
  67. data/test/sass_test.rb +115 -0
  68. data/test/scss_test.rb +88 -0
  69. data/test/server_test.rb +48 -0
  70. data/test/settings_test.rb +582 -0
  71. data/test/sinatra_test.rb +12 -0
  72. data/test/slim_test.rb +102 -0
  73. data/test/static_test.rb +236 -0
  74. data/test/streaming_test.rb +149 -0
  75. data/test/stylus_test.rb +90 -0
  76. data/test/templates_test.rb +382 -0
  77. data/test/textile_test.rb +65 -0
  78. data/test/views/a/in_a.str +1 -0
  79. data/test/views/ascii.erb +2 -0
  80. data/test/views/b/in_b.str +1 -0
  81. data/test/views/calc.html.erb +1 -0
  82. data/test/views/error.builder +3 -0
  83. data/test/views/error.erb +3 -0
  84. data/test/views/error.haml +3 -0
  85. data/test/views/error.sass +2 -0
  86. data/test/views/explicitly_nested.str +1 -0
  87. data/test/views/foo/hello.test +1 -0
  88. data/test/views/hello.asciidoc +1 -0
  89. data/test/views/hello.builder +1 -0
  90. data/test/views/hello.coffee +1 -0
  91. data/test/views/hello.creole +1 -0
  92. data/test/views/hello.erb +1 -0
  93. data/test/views/hello.haml +1 -0
  94. data/test/views/hello.less +5 -0
  95. data/test/views/hello.liquid +1 -0
  96. data/test/views/hello.mab +1 -0
  97. data/test/views/hello.md +1 -0
  98. data/test/views/hello.mediawiki +1 -0
  99. data/test/views/hello.nokogiri +1 -0
  100. data/test/views/hello.rabl +2 -0
  101. data/test/views/hello.radius +1 -0
  102. data/test/views/hello.rdoc +1 -0
  103. data/test/views/hello.sass +2 -0
  104. data/test/views/hello.scss +3 -0
  105. data/test/views/hello.slim +1 -0
  106. data/test/views/hello.str +1 -0
  107. data/test/views/hello.styl +2 -0
  108. data/test/views/hello.test +1 -0
  109. data/test/views/hello.textile +1 -0
  110. data/test/views/hello.wlang +1 -0
  111. data/test/views/hello.yajl +1 -0
  112. data/test/views/layout2.builder +3 -0
  113. data/test/views/layout2.erb +2 -0
  114. data/test/views/layout2.haml +2 -0
  115. data/test/views/layout2.liquid +2 -0
  116. data/test/views/layout2.mab +2 -0
  117. data/test/views/layout2.nokogiri +3 -0
  118. data/test/views/layout2.rabl +3 -0
  119. data/test/views/layout2.radius +2 -0
  120. data/test/views/layout2.slim +3 -0
  121. data/test/views/layout2.str +2 -0
  122. data/test/views/layout2.test +1 -0
  123. data/test/views/layout2.wlang +2 -0
  124. data/test/views/nested.str +1 -0
  125. data/test/views/utf8.erb +2 -0
  126. data/test/wlang_test.rb +87 -0
  127. data/test/yajl_test.rb +86 -0
  128. metadata +280 -0
@@ -0,0 +1,2832 @@
1
+ # Sinatra
2
+
3
+ *주의: 이 문서는 영문판의 번역본이며 최신판 문서와 다를 수 있습니다.*
4
+
5
+ Sinatra는 최소한의 노력으로 루비 기반 웹 애플리케이션을 신속하게 만들 수 있게
6
+ 해 주는 [DSL](http://en.wikipedia.org/wiki/Domain-specific_language)입니다.
7
+
8
+ ``` ruby
9
+ # myapp.rb
10
+ require 'sinatra'
11
+
12
+ get '/' do
13
+ 'Hello world!'
14
+ end
15
+ ```
16
+
17
+ 젬을 설치합니다.
18
+
19
+ ``` shell
20
+ gem install sinatra
21
+ ```
22
+
23
+ 실행합니다.
24
+
25
+ ``` shell
26
+ ruby myapp.rb
27
+ ```
28
+
29
+ `http://localhost:4567`를 확인해 보세요.
30
+
31
+ `gem install thin`도 함께 실행하기를 권장합니다.
32
+ thin이 설치되어 있을 경우 Sinatra는 thin을 통해 실행합니다.
33
+
34
+ ## 목차
35
+
36
+ * [Sinatra](#sinatra)
37
+ * [목차](#목차)
38
+ * [라우터(Routes)](#라우터routes)
39
+ * [조건(Conditions)](#조건conditions)
40
+ * [반환값(Return Values)](#반환값return-values)
41
+ * [커스텀 라우터 매처(Custom Route Matchers)](#커스텀-라우터-매처custom-route-matchers)
42
+ * [정적 파일(Static Files)](#정적-파일static-files)
43
+ * [뷰 / 템플릿(Views / Templates)](#뷰--템플릿views--templates)
44
+ * [리터럴 템플릿(Literal Templates)](#리터럴-템플릿literal-templates)
45
+ * [가능한 템플릿 언어들(Available Template Languages)](#가능한-템플릿-언어들available-template-languages)
46
+ * [Haml 템플릿](#haml-템플릿)
47
+ * [Erb 템플릿](#erb-템플릿)
48
+ * [Builder 템플릿](#builder-템플릿)
49
+ * [Nokogiri 템플릿](#nokogiri-템플릿)
50
+ * [Sass 템플릿](#sass-템플릿)
51
+ * [SCSS 템플릿](#scss-템플릿)
52
+ * [Less 템플릿](#less-템플릿)
53
+ * [Liquid 템플릿](#liquid-템플릿)
54
+ * [Markdown 템플릿](#markdown-템플릿)
55
+ * [Textile 템플릿](#textile-템플릿)
56
+ * [RDoc 템플릿](#rdoc-템플릿)
57
+ * [Radius 템플릿](#radius-템플릿)
58
+ * [Markaby 템플릿](#markaby-템플릿)
59
+ * [RABL 템플릿](#rabl-템플릿)
60
+ * [Slim 템플릿](#slim-템플릿)
61
+ * [Creole 템플릿](#creole-템플릿)
62
+ * [CoffeeScript 템플릿](#coffeescript-템플릿)
63
+ * [Stylus 템플릿](#stylus-템플릿)
64
+ * [Yajl 템플릿](#yajl-템플릿)
65
+ * [WLang 템플릿](#wlang-템플릿)
66
+ * [템플릿에서 변수에 접근하기](#템플릿에서-변수에-접근하기)
67
+ * [템플릿에서의 `yield` 와 중첩 레이아웃](#템플릿에서의-yield-와-중첩-레이아웃)
68
+ * [인라인 템플릿](#인라인-템플릿)
69
+ * [이름을 가지는 템플릿(Named Templates)](#이름을-가지는-템플릿named-templates)
70
+ * [파일 확장자 연결하기](#파일-확장자-연결하기)
71
+ * [나만의 고유한 템플릿 엔진 추가하기](#나만의-고유한-템플릿-엔진-추가하기)
72
+ * [필터(Filters)](#필터filters)
73
+ * [헬퍼(Helpers)](#헬퍼helpers)
74
+ * [세션(Sessions) 사용하기](#세션sessions-사용하기)
75
+ * [중단하기(Halting)](#중단하기halting)
76
+ * [넘기기(Passing)](#넘기기passing)
77
+ * [다른 라우터 부르기(Triggering Another Route)](#다른-라우터-부르기triggering-another-route)
78
+ * [본문, 상태 코드 및 헤더 설정하기](#본문-상태-코드-및-헤더-설정하기)
79
+ * [응답 스트리밍(Streaming Responses)](#응답-스트리밍streaming-responses)
80
+ * [로깅(Logging)](#로깅logging)
81
+ * [마임 타입(Mime Types)](#마임-타입mime-types)
82
+ * [URL 생성하기](#url-생성하기)
83
+ * [브라우저 재지정(Browser Redirect)](#브라우저-재지정browser-redirect)
84
+ * [캐시 컨트롤(Cache Control)](#캐시-컨트롤cache-control)
85
+ * [파일 전송하기(Sending Files)](#파일-전송하기sending-files)
86
+ * [요청 객체에 접근하기(Accessing the Request Object)](#요청-객체에-접근하기accessing-the-request-object)
87
+ * [첨부(Attachments)](#첨부attachments)
88
+ * [날짜와 시간 다루기](#날짜와-시간-다루기)
89
+ * [템플릿 파일 참조하기](#템플릿-파일-참조하기)
90
+ * [설정(Configuration)](#설정configuration)
91
+ * [공격 방어 설정하기(Configuring attack protection)](#공격-방어-설정하기configuring-attack-protection)
92
+ * [가능한 설정들(Available Settings)](#가능한-설정들available-settings)
93
+ * [환경(Environments)](#환경environments)
94
+ * [에러 처리(Error Handling)](#에러-처리error-handling)
95
+ * [찾을 수 없음(Not Found)](#찾을-수-없음not-found)
96
+ * [에러](#에러)
97
+ * [Rack 미들웨어(Rack Middleware)](#rack-미들웨어rack-middleware)
98
+ * [테스팅(Testing)](#테스팅testing)
99
+ * [Sinatra::Base - 미들웨어(Middleware), 라이브러리(Libraries), 그리고 모듈 앱(Modular Apps)](#sinatrabase---미들웨어middleware-라이브러리libraries-그리고-모듈-앱modular-apps)
100
+ * [모듈(Modular) vs. 전통적 방식(Classic Style)](#모듈modular-vs-전통적-방식classic-style)
101
+ * [모듈 애플리케이션(Modular Application) 제공하기](#모듈-애플리케이션modular-application-제공하기)
102
+ * [config.ru로 전통적 방식의 애플리케이션 사용하기](#configru로-전통적-방식의-애플리케이션-사용하기)
103
+ * [언제 config.ru를 사용할까?](#언제-configru를-사용할까)
104
+ * [Sinatra를 미들웨어로 사용하기](#sinatra를-미들웨어로-사용하기)
105
+ * [동적인 애플리케이션 생성(Dynamic Application Creation)](#동적인-애플리케이션-생성dynamic-application-creation)
106
+ * [범위(Scopes)와 바인딩(Binding)](#범위scopes와-바인딩binding)
107
+ * [애플리케이션/클래스 범위](#애플리케이션클래스-범위)
108
+ * [요청/인스턴스 범위](#요청인스턴스-범위)
109
+ * [위임 범위(Delegation Scope)](#위임-범위delegation-scope)
110
+ * [명령행(Command Line)](#명령행command-line)
111
+ * [요구사항(Requirement)](#요구사항requirement)
112
+ * [최신(The Bleeding Edge)](#최신the-bleeding-edge)
113
+ * [Bundler를 사용하여](#bundler를-사용하여)
114
+ * [직접 하기(Roll Your Own)](#직접-하기roll-your-own)
115
+ * [전역으로 설치(Install Globally)](#전역으로-설치install-globally)
116
+ * [버저닝(Versioning)](#버저닝versioning)
117
+ * [더 읽을 거리(Further Reading)](#더-읽을-거리further-reading)
118
+
119
+ ## 라우터(Routes)
120
+
121
+ Sinatra에서, 라우터(route)는 URL-매칭 패턴과 쌍을 이루는 HTTP 메서드입니다.
122
+ 각각의 라우터는 블록과 연결됩니다.
123
+
124
+ ``` ruby
125
+ get '/' do
126
+ .. 무언가 보여주기(show) ..
127
+ end
128
+
129
+ post '/' do
130
+ .. 무언가 만들기(create) ..
131
+ end
132
+
133
+ put '/' do
134
+ .. 무언가 대체하기(replace) ..
135
+ end
136
+
137
+ patch '/' do
138
+ .. 무언가 수정하기(modify) ..
139
+ end
140
+
141
+ delete '/' do
142
+ .. 무언가 없애기(annihilate) ..
143
+ end
144
+
145
+ options '/' do
146
+ .. 무언가 주기(appease) ..
147
+ end
148
+
149
+ link '/' do
150
+ .. 무언가 관계맺기(affiliate) ..
151
+ end
152
+
153
+ unlink '/' do
154
+ .. 무언가 격리하기(separate) ..
155
+ end
156
+ ```
157
+
158
+ 라우터는 정의된 순서에 따라 매치되고 요청에 대해 가장 먼저 매칭된 라우터가 호출됩니다.
159
+
160
+ 라우터 패턴에는 이름을 가진 매개변수가 포함될 수 있으며, `params` 해시로 접근할 수 있습니다.
161
+
162
+ ``` ruby
163
+ get '/hello/:name' do
164
+ # "GET /hello/foo" 및 "GET /hello/bar"와 매치
165
+ # params[:name]은 'foo' 또는 'bar'
166
+ "Hello #{params[:name]}!"
167
+ end
168
+ ```
169
+
170
+ 또한 블록 매개변수를 통하여도 이름을 가진 매개변수에 접근할 수 있습니다.
171
+
172
+ ``` ruby
173
+ get '/hello/:name' do |n|
174
+ # "GET /hello/foo" 및 "GET /hello/bar"와 매치
175
+ # params[:name]은 'foo' 또는 'bar'
176
+ "Hello #{n}!"
177
+ end
178
+ ```
179
+
180
+ 라우터 패턴에는 스플랫(splat, 또는 와일드카드)도 매개변수도 포함될 수 있으며, 이럴 경우 `params[:splat]` 배열을 통해 접근할 수 있습니다.
181
+
182
+ ``` ruby
183
+ get '/say/*/to/*' do
184
+ # /say/hello/to/world와 매치
185
+ params[:splat] # => ["hello", "world"]
186
+ end
187
+
188
+ get '/download/*.*' do
189
+ # /download/path/to/file.xml과 매치
190
+ params[:splat] # => ["path/to/file", "xml"]
191
+ end
192
+ ```
193
+
194
+ 블록 매개변수로도 접근할 수 있습니다.
195
+
196
+ ``` ruby
197
+ get '/download/*.*' do |path, ext|
198
+ [path, ext] # => ["path/to/file", "xml"]
199
+ end
200
+ ```
201
+
202
+ 라우터는 정규표현식으로 매치할 수 있습니다.
203
+
204
+ ``` ruby
205
+ get %r{/hello/([\w]+)} do
206
+ "Hello, #{params[:captures].first}!"
207
+ end
208
+ ```
209
+
210
+ 블록 매개변수로도 사용가능합니다.
211
+
212
+ ``` ruby
213
+ get %r{/hello/([\w]+)} do |c|
214
+ "Hello, #{c}!"
215
+ end
216
+ ```
217
+
218
+ 라우터 패턴에는 선택적인(optional) 매개변수도 올 수 있습니다.
219
+
220
+ ``` ruby
221
+ get '/posts.?:format?' do
222
+ # "GET /posts" 는 물론 "GET /posts.json", "GET /posts.xml" 와 같은 어떤 확장자와도 매칭
223
+ end
224
+ ```
225
+
226
+ 한편, 경로 탐색 공격 방지(path traversal attack protection, 아래 참조)를 비활성화시키지 않았다면,
227
+ 요청 경로는 라우터와 매칭되기 이전에 수정될 수 있습니다.
228
+
229
+ ### 조건(Conditions)
230
+
231
+ 라우터는 사용자 에이전트(user agent)같은 다양한 매칭 조건을 포함할 수 있습니다.
232
+
233
+ ``` ruby
234
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
235
+ "Songbird 버전 #{params[:agent][0]}을 사용하는군요!"
236
+ end
237
+
238
+ get '/foo' do
239
+ # songbird 브라우저가 아닌 경우 매치
240
+ end
241
+ ```
242
+
243
+ 다른 가능한 조건에는 `host_name`과 `provides`가 있습니다.
244
+
245
+ ``` ruby
246
+ get '/', :host_name => /^admin\./ do
247
+ "Admin Area, Access denied!"
248
+ end
249
+
250
+ get '/', :provides => 'html' do
251
+ haml :index
252
+ end
253
+
254
+ get '/', :provides => ['rss', 'atom', 'xml'] do
255
+ builder :feed
256
+ end
257
+ ```
258
+
259
+ 사용자 정의 조건도 쉽게 만들 수 있습니다.
260
+
261
+ ``` ruby
262
+ set(:probability) { |value| condition { rand <= value } }
263
+
264
+ get '/win_a_car', :probability => 0.1 do
265
+ "내가 졌소!"
266
+ end
267
+
268
+ get '/win_a_car' do
269
+ "미안해서 어쩌나."
270
+ end
271
+ ```
272
+
273
+ 여러 값을 받는 조건에는 스플랫(splat)을 사용합니다.
274
+
275
+ ``` ruby
276
+ set(:auth) do |*roles| # <- 이게 스플랫
277
+ condition do
278
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
279
+ redirect "/login/", 303
280
+ end
281
+ end
282
+ end
283
+
284
+ get "/my/account/", :auth => [:user, :admin] do
285
+ "내 계정 정보"
286
+ end
287
+
288
+ get "/only/admin/", :auth => :admin do
289
+ "관리자 외 접근불가!"
290
+ end
291
+ ```
292
+
293
+ ### 반환값(Return Values)
294
+
295
+ 라우터 블록의 반환 값은 HTTP 클라이언트로 전달되는 응답 본문만을 결정하거나, 또는 Rack 스택에서 다음 번 미들웨어만를 결정합니다.
296
+ 위의 예제에서 볼 수 있지만 대부분의 경우 이 반환값은 문자열입니다.하지만 다른 값도 허용됩니다.
297
+
298
+ 유효한 Rack 응답, Rack 본문 객체 또는 HTTP 상태 코드가 되는 어떠한 객체라도 반환할 수 있습니다.
299
+
300
+ * 세 요소를 가진 배열: `[상태 (Fixnum), 헤더 (Hash), 응답 본문 (#each에 반응)]`
301
+ * 두 요소를 가진 배열: `[상태 (Fixnum), 응답 본문 (#each에 반응)]`
302
+ * `#each`에 반응하고 주어진 블록으로 문자열만을 전달하는 객체
303
+ * 상태 코드를 의미하는 Fixnum
304
+
305
+ 이것을 이용한 예를 들자면, 스트리밍(streaming) 예제를 쉽게 구현할 수 있습니다.
306
+
307
+ ``` ruby
308
+ class Stream
309
+ def each
310
+ 100.times { |i| yield "#{i}\n" }
311
+ end
312
+ end
313
+
314
+ get('/') { Stream.new }
315
+ ```
316
+
317
+ `stream` 헬퍼 메서드(아래 참조)를 사용하면 이런 번거로움을 줄이고 스트리밍 로직을 라우터 속에 포함 시킬 수도 있습니다.
318
+
319
+ ### 커스텀 라우터 매처(Custom Route Matchers)
320
+
321
+ 위에서 보듯, Sinatra에는 문자열 패턴 및 정규표현식을 이용한 라우터 매칭 지원이 내장되어 있습니다.
322
+ 하지만, 그게 끝은 아닙니다. 여러분 만의 매처(matcher)도 쉽게 정의할 수 있습니다.
323
+
324
+ ``` ruby
325
+ class AllButPattern
326
+ Match = Struct.new(:captures)
327
+
328
+ def initialize(except)
329
+ @except = except
330
+ @captures = Match.new([])
331
+ end
332
+
333
+ def match(str)
334
+ @captures unless @except === str
335
+ end
336
+ end
337
+
338
+ def all_but(pattern)
339
+ AllButPattern.new(pattern)
340
+ end
341
+
342
+ get all_but("/index") do
343
+ # ...
344
+ end
345
+ ```
346
+
347
+ 사실 위의 예제는 조금 과하게 작성된 면이 있습니다. 간단하게 표현할 수도 있어요.
348
+
349
+ ``` ruby
350
+ get // do
351
+ pass if request.path_info == "/index"
352
+ # ...
353
+ end
354
+ ```
355
+
356
+ 또는 거꾸로 탐색(negative look ahead)할 수도 있습니다.
357
+
358
+ ``` ruby
359
+ get %r{^(?!/index$)} do
360
+ # ...
361
+ end
362
+ ```
363
+
364
+ ## 정적 파일(Static Files)
365
+
366
+ 정적 파일들은 `./public` 디렉터리에서 제공됩니다. 위치를 다른 곳으로
367
+ 변경하려면 `:public_folder` 옵션을 지정하면 됩니다.
368
+
369
+ ``` ruby
370
+ set :public_folder, File.dirname(__FILE__) + '/static'
371
+ ```
372
+
373
+ public 디렉터리명은 URL에 포함되지 않는다는 점에 주의하세요.
374
+ `./public/css/style.css` 파일은 아마 `http://example.com/css/style.css` 로 접근할 수 있을 것 입니다.
375
+
376
+ `Cache-Control` 헤더 정보를 추가하려면 `:static_cache_control` 설정(아래 참조)을 사용하면 됩니다.
377
+
378
+ ## 뷰 / 템플릿(Views / Templates)
379
+
380
+ 템플릿 언어들은 각각의 렌더링 메서드를 통해 표출됩니다.
381
+ 이들 메서드는 문자열을 반환할 뿐입니다.
382
+
383
+ ``` ruby
384
+ get '/' do
385
+ erb :index
386
+ end
387
+ ```
388
+
389
+ 이 구문은 `views/index.erb`를 렌더합니다.
390
+
391
+ 템플릿 이름 대신 템플릿의 내용을 직접 넘길 수도 있습니다.
392
+
393
+ ``` ruby
394
+ get '/' do
395
+ code = "<%= Time.now %>"
396
+ erb code
397
+ end
398
+ ```
399
+
400
+ 템플릿은 두 번째 인자로 옵션값의 해시를 받습니다.
401
+
402
+ ``` ruby
403
+ get '/' do
404
+ erb :index, :layout => :post
405
+ end
406
+ ```
407
+
408
+ 이 구문은 `views/post.erb` 속에 내장된 `views/index.erb`를 렌더합니다.
409
+ (`views/layout.erb`파일이 존재할 경우 기본값은 `views/layout.erb`입니다.)
410
+
411
+ Sinatra가 이해하지 못하는 모든 옵션값들은 템플릿 엔진으로 전달됩니다.
412
+
413
+ ``` ruby
414
+ get '/' do
415
+ haml :index, :format => :html5
416
+ end
417
+ ```
418
+
419
+ 옵션값은 템플릿 언어별로 전역적으로 설정할 수도 있습니다.
420
+
421
+ ``` ruby
422
+ set :haml, :format => :html5
423
+
424
+ get '/' do
425
+ haml :index
426
+ end
427
+ ```
428
+
429
+ render 메서드에서 전달된 옵션값들은 `set`을 통해 설정한 옵션값보다 우선합니다.
430
+
431
+ 가능한 옵션값들은 다음과 같습니다.
432
+
433
+ <dl>
434
+ <dt>locals</dt>
435
+ <dd>
436
+ 문서로 전달되는 local 목록. 파셜과 함께 사용하기 좋음.
437
+ 예제: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
438
+ </dd>
439
+
440
+ <dt>default_encoding</dt>
441
+ <dd>
442
+ 불확실한 경우에 사용할 문자열 인코딩.
443
+ 기본값은 <tt>settings.default_encoding</tt>.
444
+ </dd>
445
+
446
+ <dt>views</dt>
447
+ <dd>
448
+ 템플릿을 로드할 뷰 폴더.
449
+ 기본값은 <tt>settings.views</tt>.
450
+ </dd>
451
+
452
+ <dt>layout</dt>
453
+ <dd>
454
+ 레이아웃을 사용할지 여부 (<tt>true</tt> 또는 <tt>false</tt>), 만약 이 값이 심볼일 경우,
455
+ 사용할 템플릿을 지정. 예제: <tt>erb :index, :layout => !request.xhr?</tt>
456
+ </dd>
457
+
458
+ <dt>content_type</dt>
459
+ <dd>
460
+ 템플릿이 생성하는 Content-Type, 기본값은 템플릿 언어에 의존.
461
+ </dd>
462
+
463
+ <dt>scope</dt>
464
+ <dd>
465
+ 템플릿을 렌더링하는 범위. 기본값은 어플리케이션 인스턴스.
466
+ 만약 이 값을 변경하면, 인스턴스 변수와 헬퍼 메서드들을 사용할 수 없게 됨.
467
+ </dd>
468
+
469
+ <dt>layout_engine</dt>
470
+ <dd>
471
+ 레이아웃 렌더링에 사용할 템플릿 엔진. 레이아웃을 지원하지 않는 언어인 경우에 유용.
472
+ 기본값은 템플릿에서 사용하는 엔진. 예제: <tt>set :rdoc, :layout_engine => :erb</tt>
473
+ </dd>
474
+ </dl>
475
+
476
+
477
+ 템플릿은 `./views` 디렉터리에 있는 것으로 가정됩니다. 뷰 디렉터리를
478
+ 다른 곳으로 하고 싶으시면 이렇게 하세요.
479
+
480
+ ``` ruby
481
+ set :views, settings.root + '/templates'
482
+ ```
483
+
484
+ 템플릿은 언제나 심볼로 참조되어야 한다는 것에 주의하세요.
485
+ 템플릿이 하위 디렉터리에 위치한 경우(그럴 경우에는 `:'subdir/template'`을
486
+ 사용)에도 예외는 없습니다. 반드시 심볼이어야 하는 이유는, 문자열을 넘기면
487
+ 렌더링 메서드가 전달된 문자열을 직접 렌더하기 때문입니다.
488
+
489
+ ### 리터럴 템플릿(Literal Templates)
490
+
491
+ ``` ruby
492
+ get '/' do
493
+ haml '%div.title Hello World'
494
+ end
495
+ ```
496
+
497
+ 템플릿 문자열을 렌더합니다.
498
+
499
+ ### 가능한 템플릿 언어들(Available Template Languages)
500
+
501
+ 일부 언어는 여러 개의 구현이 있습니다. (스레드에 안전하게 thread-safe) 어느 구현을
502
+ 사용할지 저정하려면, 먼저 require 하기만 하면 됩니다.
503
+
504
+ ``` ruby
505
+ require 'rdiscount' # or require 'bluecloth'
506
+ get('/') { markdown :index }
507
+ ```
508
+
509
+ #### Haml 템플릿
510
+
511
+ <table>
512
+ <tr>
513
+ <td>의존성</td>
514
+ <td><a href="http://haml.info/">haml</a></td>
515
+ </tr>
516
+ <tr>
517
+ <td>파일 확장자</td>
518
+ <td><tt>.haml</tt></td>
519
+ </tr>
520
+ <tr>
521
+ <td>예제</td>
522
+ <td><tt>haml :index, :format => :html5</tt></td>
523
+ </tr>
524
+ </table>
525
+
526
+ #### Erb 템플릿
527
+
528
+ <table>
529
+ <tr>
530
+ <td>의존성</td>
531
+ <td><a href="http://www.kuwata-lab.com/erubis/">erubis</a> 또는 erb (루비 속에 포함)</td>
532
+ </tr>
533
+ <tr>
534
+ <td>파일 확장자</td>
535
+ <td><tt>.erb</tt>, <tt>.rhtml</tt>, <tt>.erubis</tt> (Erubis만 해당)</td>
536
+ </tr>
537
+ <tr>
538
+ <td>예제</td>
539
+ <td><tt>erb :index</tt></td>
540
+ </tr>
541
+ </table>
542
+
543
+ #### Builder 템플릿
544
+
545
+ <table>
546
+ <tr>
547
+ <td>의존성</td>
548
+ <td><a href="http://builder.rubyforge.org/">builder</a></td>
549
+ </tr>
550
+ <tr>
551
+ <td>파일 확장자</td>
552
+ <td><tt>.builder</tt></td>
553
+ </tr>
554
+ <tr>
555
+ <td>예제</td>
556
+ <td><tt>builder { |xml| xml.em "hi" }</tt></td>
557
+ </tr>
558
+ </table>
559
+
560
+ 인라인 템플릿으로 블록을 받을 수도 있습니다(예제 참조).
561
+
562
+ #### Nokogiri 템플릿
563
+
564
+ <table>
565
+ <tr>
566
+ <td>의존성</td>
567
+ <td><a href="http://nokogiri.org/">nokogiri</a></td>
568
+ </tr>
569
+ <tr>
570
+ <td>파일 확장자</td>
571
+ <td><tt>.nokogiri</tt></td>
572
+ </tr>
573
+ <tr>
574
+ <td>예제</td>
575
+ <td><tt>nokogiri { |xml| xml.em "hi" }</tt></td>
576
+ </tr>
577
+ </table>
578
+
579
+ 인라인 템플릿으로 블록을 받을 수도 있습니다(예제 참조).
580
+
581
+ #### Sass 템플릿
582
+
583
+ <table>
584
+ <tr>
585
+ <td>의존성</td>
586
+ <td><a href="http://sass-lang.com/">sass</a></td>
587
+ </tr>
588
+ <tr>
589
+ <td>파일 확장자</td>
590
+ <td><tt>.sass</tt></td>
591
+ </tr>
592
+ <tr>
593
+ <td>예제</td>
594
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
595
+ </tr>
596
+ </table>
597
+
598
+ #### SCSS 템플릿
599
+
600
+ <table>
601
+ <tr>
602
+ <td>의존성</td>
603
+ <td><a href="http://sass-lang.com/">sass</a></td>
604
+ </tr>
605
+ <tr>
606
+ <td>파일 확장자</td>
607
+ <td><tt>.scss</tt></td>
608
+ </tr>
609
+ <tr>
610
+ <td>예제</td>
611
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
612
+ </tr>
613
+ </table>
614
+
615
+ #### Less 템플릿
616
+
617
+ <table>
618
+ <tr>
619
+ <td>의존성</td>
620
+ <td><a href="http://www.lesscss.org/">less</a></td>
621
+ </tr>
622
+ <tr>
623
+ <td>파일 확장자</td>
624
+ <td><tt>.less</tt></td>
625
+ </tr>
626
+ <tr>
627
+ <td>예제</td>
628
+ <td><tt>less :stylesheet</tt></td>
629
+ </tr>
630
+ </table>
631
+
632
+ #### Liquid 템플릿
633
+
634
+ <table>
635
+ <tr>
636
+ <td>의존성</td>
637
+ <td><a href="http://www.liquidmarkup.org/">liquid</a></td>
638
+ </tr>
639
+ <tr>
640
+ <td>파일 확장자</td>
641
+ <td><tt>.liquid</tt></td>
642
+ </tr>
643
+ <tr>
644
+ <td>예제</td>
645
+ <td><tt>liquid :index, :locals => { :key => 'value' }</tt></td>
646
+ </tr>
647
+ </table>
648
+
649
+ Liquid 템플릿에서는 루비 메서드(`yield` 제외)를 호출할 수 없기
650
+ 때문에, 거의 대부분의 경우 locals를 전달해야 합니다.
651
+
652
+ #### Markdown 템플릿
653
+
654
+ <table>
655
+ <tr>
656
+ <td>의존성</td>
657
+ <td>
658
+ <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
659
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
660
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
661
+ <a href="http://kramdown.rubyforge.org/" title="kramdown">kramdown</a>,
662
+ <a href="http://maruku.rubyforge.org/" title="maruku">maruku</a>
663
+ 중 아무거나
664
+ </td>
665
+ </tr>
666
+ <tr>
667
+ <td>파일 확장</td>
668
+ <td><tt>.markdown</tt>, <tt>.mkd</tt>, <tt>.md</tt></td>
669
+ </tr>
670
+ <tr>
671
+ <td>예제</td>
672
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
673
+ </tr>
674
+ </table>
675
+
676
+ Markdown에서는 메서드 호출 뿐 아니라 locals 전달도 안됩니다.
677
+ 따라서 일반적으로는 다른 렌더링 엔진과 함께 사용하게 됩니다.
678
+
679
+ ``` ruby
680
+ erb :overview, :locals => { :text => markdown(:introduction) }
681
+ ```
682
+
683
+ 다른 템플릿 속에서 `markdown` 메서드를 호출할 수도 있습니다.
684
+
685
+ ``` ruby
686
+ %h1 안녕 Haml!
687
+ %p= markdown(:greetings)
688
+ ```
689
+
690
+ Markdown에서 루비를 호출할 수 없기 때문에, Markdown으로 작성된 레이아웃은
691
+ 사용할 수 없습니다. 하지만, `:layout_engine` 옵션으로 레이아웃의 템플릿을
692
+ 다른 렌더링 엔진으로 렌더링 할 수는 있습니다.
693
+
694
+ #### Textile 템플릿
695
+
696
+ <table>
697
+ <tr>
698
+ <td>의존성</td>
699
+ <td><a href="http://redcloth.org/">RedCloth</a></td>
700
+ </tr>
701
+ <tr>
702
+ <td>파일 확장자</td>
703
+ <td><tt>.textile</tt></td>
704
+ </tr>
705
+ <tr>
706
+ <td>예제</td>
707
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
708
+ </tr>
709
+ </table>
710
+
711
+ Textile에서는 메서드 호출 뿐 아니라 locals 전달도 안됩니다.
712
+ 따라서 일반적으로는 다른 렌더링 엔진과 함께 사용하게 됩니다.
713
+
714
+ ``` ruby
715
+ erb :overview, :locals => { :text => textile(:introduction) }
716
+ ```
717
+
718
+ 다른 템플릿 속에서 `textile` 메서드를 호출할 수도 있습니다.
719
+
720
+ ``` ruby
721
+ %h1 안녕 Haml!
722
+ %p= textile(:greetings)
723
+ ```
724
+
725
+ Textile에서 루비를 호출할 수 없기 때문에, Textile으로 작성된 레이아웃은
726
+ 사용할 수 없습니다. 하지만, `:layout_engine` 옵션으로 레이아웃의 템플릿을
727
+ 다른 렌더링 엔진으로 렌더링 할 수는 있습니다.
728
+
729
+ #### RDoc 템플릿
730
+
731
+ <table>
732
+ <tr>
733
+ <td>의존성</td>
734
+ <td><a href="http://rdoc.rubyforge.org/">rdoc</a></td>
735
+ </tr>
736
+ <tr>
737
+ <td>파일 확장자</td>
738
+ <td><tt>.rdoc</tt></td>
739
+ </tr>
740
+ <tr>
741
+ <td>예제</td>
742
+ <td><tt>rdoc :README, :layout_engine => :erb</tt></td>
743
+ </tr>
744
+ </table>
745
+
746
+ RDoc에서는 메서드 호출 뿐 아니라 locals 전달도 안됩니다.
747
+ 따라서 일반적으로는 다른 렌더링 엔진과 함께 사용하게 됩니다.
748
+
749
+ ``` ruby
750
+ erb :overview, :locals => { :text => rdoc(:introduction) }
751
+ ```
752
+
753
+ 다른 템플릿 속에서 `rdoc` 메서드를 호출할 수도 있습니다.
754
+
755
+ ``` ruby
756
+ %h1 Hello From Haml!
757
+ %p= rdoc(:greetings)
758
+ ```
759
+
760
+ RDoc에서 루비를 호출할 수 없기 때문에, RDoc으로 작성된 레이아웃은
761
+ 사용할 수 없습니다. 하지만, `:layout_engine` 옵션으로 레이아웃의 템플릿을
762
+ 다른 렌더링 엔진으로 렌더링 할 수는 있습니다.
763
+
764
+ #### Radius 템플릿
765
+
766
+ <table>
767
+ <tr>
768
+ <td>의존성</td>
769
+ <td><a href="http://radius.rubyforge.org/">radius</a></td>
770
+ </tr>
771
+ <tr>
772
+ <td>파일 확장자</td>
773
+ <td><tt>.radius</tt></td>
774
+ </tr>
775
+ <tr>
776
+ <td>예제</td>
777
+ <td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
778
+ </tr>
779
+ </table>
780
+
781
+ Radius 템플릿에서는 루비 메서드를 호출할 수 없기
782
+ 때문에, 거의 대부분의 경우 locals를 전달해야 합니다.
783
+
784
+ #### Markaby 템플릿
785
+
786
+ <table>
787
+ <tr>
788
+ <td>의존성</td>
789
+ <td><a href="http://markaby.github.com/">markaby</a></td>
790
+ </tr>
791
+ <tr>
792
+ <td>파일확장</td>
793
+ <td><tt>.mab</tt></td>
794
+ </tr>
795
+ <tr>
796
+ <td>예제</td>
797
+ <td><tt>markaby { h1 "Welcome!" }</tt></td>
798
+ </tr>
799
+ </table>
800
+
801
+ 인라인 템플릿으로 블록을 받을 수도 있습니다(예제 참조).
802
+
803
+ #### RABL 템플릿
804
+
805
+ <table>
806
+ <tr>
807
+ <td>의존성</td>
808
+ <td><a href="https://github.com/nesquena/rabl">rabl</a></td>
809
+ </tr>
810
+ <tr>
811
+ <td>파일 확장자</td>
812
+ <td><tt>.rabl</tt></td>
813
+ </tr>
814
+ <tr>
815
+ <td>예제</td>
816
+ <td><tt>rabl :index</tt></td>
817
+ </tr>
818
+ </table>
819
+
820
+ #### Slim 템플릿
821
+
822
+ <table>
823
+ <tr>
824
+ <td>의존성</td>
825
+ <td><a href="http://slim-lang.com/">slim</a></td>
826
+ </tr>
827
+ <tr>
828
+ <td>파일 확장자</td>
829
+ <td><tt>.slim</tt></td>
830
+ </tr>
831
+ <tr>
832
+ <td>예제</td>
833
+ <td><tt>slim :index</tt></td>
834
+ </tr>
835
+ </table>
836
+
837
+ #### Creole 템플릿
838
+
839
+ <table>
840
+ <tr>
841
+ <td>의존성</td>
842
+ <td><a href="https://github.com/minad/creole">creole</a></td>
843
+ </tr>
844
+ <tr>
845
+ <td>파일 확장자</td>
846
+ <td><tt>.creole</tt></td>
847
+ </tr>
848
+ <tr>
849
+ <td>예제</td>
850
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
851
+ </tr>
852
+ </table>
853
+
854
+ Creole에서는 메서드 호출 뿐 아니라 locals 전달도 안됩니다.
855
+ 따라서 일반적으로는 다른 렌더링 엔진과 함께 사용하게 됩니다.
856
+
857
+ ``` ruby
858
+ erb :overview, :locals => { :text => creole(:introduction) }
859
+ ```
860
+
861
+ 다른 템플릿 속에서 `creole` 메서드를 호출할 수도 있습니다.
862
+
863
+ ``` ruby
864
+ %h1 Hello From Haml!
865
+ %p= creole(:greetings)
866
+ ```
867
+
868
+ Creole에서 루비를 호출할 수 없기 때문에, Creole으로 작성된 레이아웃은
869
+ 사용할 수 없습니다. 하지만, `:layout_engine` 옵션으로 레이아웃의 템플릿을
870
+ 다른 렌더링 엔진으로 렌더링 할 수는 있습니다.
871
+
872
+ #### CoffeeScript 템플릿
873
+
874
+ <table>
875
+ <tr>
876
+ <td>의존성</td>
877
+ <td>
878
+ <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
879
+ CoffeeScript
880
+ </a> 와
881
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
882
+ 자바스크립트 실행법
883
+ </a>
884
+ </td>
885
+ </tr>
886
+ <tr>
887
+ <td>파일 확장자</td>
888
+ <td><tt>.coffee</tt></td>
889
+ </tr>
890
+ <tr>
891
+ <td>예제</td>
892
+ <td><tt>coffee :index</tt></td>
893
+ </tr>
894
+ </table>
895
+
896
+ #### Stylus 템플릿
897
+
898
+ <table>
899
+ <tr>
900
+ <td>의존성</td>
901
+ <td>
902
+ <a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
903
+ Stylus
904
+ </a> 와
905
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
906
+ 자바스크립트 실행법
907
+ </a>
908
+ </td>
909
+ </tr>
910
+ <tr>
911
+ <td>파일 확장자</td>
912
+ <td><tt>.styl</tt></td>
913
+ </tr>
914
+ <tr>
915
+ <td>예제</td>
916
+ <td><tt>stylus :index</tt></td>
917
+ </tr>
918
+ </table>
919
+
920
+ Stylus 템플릿을 사용가능하게 하려면, 먼저 `stylus`와 `stylus/tilt`를 로드
921
+ 해야합니다.
922
+
923
+ ``` ruby
924
+ require 'sinatra'
925
+ require 'stylus'
926
+ require 'stylus/tilt'
927
+
928
+ get '/' do
929
+ stylus :example
930
+ end
931
+ ```
932
+
933
+ #### Yajl 템플릿
934
+
935
+ <table>
936
+ <tr>
937
+ <td>의존성</td>
938
+ <td><a href="https://github.com/brianmario/yajl-ruby">yajl-ruby</a></td>
939
+ </tr>
940
+ <tr>
941
+ <td>파일 확장자</td>
942
+ <td><tt>.yajl</tt></td>
943
+ </tr>
944
+ <tr>
945
+ <td>예제</td>
946
+ <td>
947
+ <tt>
948
+ yajl :index,
949
+ :locals => { :key => 'qux' },
950
+ :callback => 'present',
951
+ :variable => 'resource'
952
+ </tt>
953
+ </td>
954
+ </tr>
955
+ </table>
956
+
957
+ 템플릿 소스는 루비 문자열로 평가(evaluate)되고, 결과인 json 변수는 `#to_json`으로 변환됩니다.
958
+
959
+ ``` ruby
960
+ json = { :foo => 'bar' }
961
+ json[:baz] = key
962
+ ```
963
+
964
+ `:callback`과 `:variable` 옵션은 렌더된 객체를 꾸미는데(decorate) 사용할 수 있습니다.
965
+
966
+ ```javascript
967
+ var resource = {"foo":"bar","baz":"qux"};
968
+ present(resource);
969
+ ```
970
+
971
+ #### WLang 템플릿
972
+
973
+ <table>
974
+ <tr>
975
+ <td>의존성</td>
976
+ <td><a href="https://github.com/blambeau/wlang/" title="WLang">WLang</a></td>
977
+ </tr>
978
+ <tr>
979
+ <td>파일 확장자</td>
980
+ <td><tt>.wlang</tt></td>
981
+ </tr>
982
+ <tr>
983
+ <td>예제</td>
984
+ <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
985
+ </tr>
986
+ </table>
987
+
988
+ WLang 템플릿에서는 루비 메서드(`yield` 제외)를 호출할 수 없기
989
+ 때문에, 거의 대부분의 경우 locals를 전달해야 합니다. 그래도
990
+ WLang으로 쓰여진 레이아웃과 `yield`는 지원합니다.
991
+
992
+ ### 템플릿에서 변수에 접근하기
993
+
994
+ 템플릿은 라우터 핸들러와 같은 맥락(context)에서 평가됩니다. 라우터
995
+ 핸들러에서 설정한 인스턴스 변수들은 템플릿에서 직접 접근 가능합니다.
996
+
997
+ ``` ruby
998
+ get '/:id' do
999
+ @foo = Foo.find(params[:id])
1000
+ haml '%h1= @foo.name'
1001
+ end
1002
+ ```
1003
+
1004
+ 명시적으로 로컬 변수의 해시를 지정할 수도 있습니다.
1005
+
1006
+ ``` ruby
1007
+ get '/:id' do
1008
+ foo = Foo.find(params[:id])
1009
+ haml '%h1= bar.name', :locals => { :bar => foo }
1010
+ end
1011
+ ```
1012
+
1013
+ 이 방법은 주로 템플릿을 다른 템플릿 속에서 파셜(partial)로 렌더링할
1014
+ 때 사용됩니다.
1015
+
1016
+ ### 템플릿에서의 `yield` 와 중첩 레이아웃
1017
+
1018
+ 레이아웃은 보통 `yield`만 호출하는 템플릿입니다.
1019
+ 위에 설명된 `:template` 옵션을 통해 템플릿을 사용하거나,
1020
+ 다음 예제처럼 블록으로 렌더링 할 수 있습니다.
1021
+
1022
+ ``` ruby
1023
+ erb :post, :layout => false do
1024
+ erb :index
1025
+ end
1026
+ ```
1027
+
1028
+ 위 코드는 `erb :index, :layout => :post`와 대부분 동일합니다.
1029
+
1030
+ 렌더링 메서드에 블록 넘기기는 중첩 레이아웃을 만들때 유용합니다.
1031
+
1032
+ ``` ruby
1033
+ erb :main_layout, :layout => false do
1034
+ erb :admin_layout do
1035
+ erb :user
1036
+ end
1037
+ end
1038
+ ```
1039
+
1040
+ 위의 코드도 줄일 수 있습니다.
1041
+
1042
+ ``` ruby
1043
+ erb :admin_layout, :layout => :main_layout do
1044
+ erb :user
1045
+ end
1046
+ ```
1047
+
1048
+ 현재, `erb`, `haml`, `liquid`, `slim `, `wlang`는 블럭을 지원합니다.
1049
+ 일반적인 `render` 메소드도 블럭을 지원합니다.
1050
+
1051
+ ### 인라인 템플릿
1052
+
1053
+ 템플릿은 소스 파일의 마지막에서 정의할 수도 있습니다.
1054
+
1055
+ ``` ruby
1056
+ require 'sinatra'
1057
+
1058
+ get '/' do
1059
+ haml :index
1060
+ end
1061
+
1062
+ __END__
1063
+
1064
+ @@ layout
1065
+ %html
1066
+ = yield
1067
+
1068
+ @@ index
1069
+ %div.title Hello world.
1070
+ ```
1071
+
1072
+ 참고: sinatra를 require한 소스 파일에 정의된 인라인 템플릿은 자동으로
1073
+ 로드됩니다. 다른 소스 파일에서 인라인 템플릿을 사용하려면 명시적으로
1074
+ `enable :inline_templates`을 호출하면 됩니다.
1075
+
1076
+ ### 이름을 가지는 템플릿(Named Templates)
1077
+
1078
+ 템플릿은 톱 레벨(top-level)에서 `template`메서드로도 정의할 수 있습니다.
1079
+
1080
+ ``` ruby
1081
+ template :layout do
1082
+ "%html\n =yield\n"
1083
+ end
1084
+
1085
+ template :index do
1086
+ '%div.title Hello World!'
1087
+ end
1088
+
1089
+ get '/' do
1090
+ haml :index
1091
+ end
1092
+ ```
1093
+
1094
+ "layout"이라는 이름의 템플릿이 존재하면, 템플릿이 렌더될 때마다 사용됩니다.
1095
+ 레이아웃을 비활성화할 때는 `:layout => false`를 전달하여 개별적으로
1096
+ 비활성시키거나 `set :haml, :layout => false`으로 기본값을 비활성으로 둘 수
1097
+ 있습니다.
1098
+
1099
+ ``` ruby
1100
+ get '/' do
1101
+ haml :index, :layout => !request.xhr?
1102
+ end
1103
+ ```
1104
+
1105
+ ### 파일 확장자 연결하기
1106
+
1107
+ 어떤 파일 확장자를 특정 템플릿 엔진과 연결하려면, `Tilt.register`를 사용하면
1108
+ 됩니다. 예를 들어, `tt`라는 파일 확장자를 Textile 템플릿과 연결하고 싶다면,
1109
+ 다음과 같이 하면 됩니다.
1110
+
1111
+ ``` ruby
1112
+ Tilt.register :tt, Tilt[:textile]
1113
+ ```
1114
+
1115
+ ### 나만의 고유한 템플릿 엔진 추가하기
1116
+
1117
+ 우선, Tilt로 여러분 엔진을 등록하고, 렌더링 메서드를 생성합니다.
1118
+
1119
+ ``` ruby
1120
+ Tilt.register :myat, MyAwesomeTemplateEngine
1121
+
1122
+ helpers do
1123
+ def myat(*args) render(:myat, *args) end
1124
+ end
1125
+
1126
+ get '/' do
1127
+ myat :index
1128
+ end
1129
+ ```
1130
+
1131
+ 위 코드는 `./views/index.myat` 를 렌더합니다.
1132
+ Tilt에 대한 더 자세한 내용은 https://github.com/rtomayko/tilt 참조하세요.
1133
+
1134
+ ## 필터(Filters)
1135
+
1136
+ 사전 필터(before filter)는 라우터와 동일한 맥락에서 매 요청 전에 평가되며
1137
+ 요청과 응답을 변형할 수 있습니다. 필터에서 설정된 인스턴스 변수들은 라우터와
1138
+ 템플릿에서 접근 가능합니다.
1139
+
1140
+ ``` ruby
1141
+ before do
1142
+ @note = 'Hi!'
1143
+ request.path_info = '/foo/bar/baz'
1144
+ end
1145
+
1146
+ get '/foo/*' do
1147
+ @note #=> 'Hi!'
1148
+ params[:splat] #=> 'bar/baz'
1149
+ end
1150
+ ```
1151
+
1152
+ 사후 필터(after filter)는 라우터와 동일한 맥락에서 매 요청 이후에 평가되며
1153
+ 마찬가지로 요청과 응답을 변형할 수 있습니다. 사전 필터와 라우터에서 설정된
1154
+ 인스턴스 변수들은 사후 필터에서 접근 가능합니다.
1155
+
1156
+ ``` ruby
1157
+ after do
1158
+ puts response.status
1159
+ end
1160
+ ```
1161
+
1162
+ 참고: 만약 라우터에서 `body` 메서드를 사용하지 않고 그냥 문자열만 반환한
1163
+ 경우라면, body는 나중에 생성되는 탓에, 아직 사후 필터에서 사용할 수 없을
1164
+ 것입니다.
1165
+
1166
+ 필터는 패턴을 취할 수도 있으며, 이 경우 요청 경로가 그 패턴과 매치할
1167
+ 경우에만 필터가 평가될 것입니다.
1168
+
1169
+ ``` ruby
1170
+ before '/protected/*' do
1171
+ authenticate!
1172
+ end
1173
+
1174
+ after '/create/:slug' do |slug|
1175
+ session[:last_slug] = slug
1176
+ end
1177
+ ```
1178
+
1179
+ 라우터와 마찬가지로, 필터 역시 조건을 취할 수 있습니다.
1180
+
1181
+ ``` ruby
1182
+ before :agent => /Songbird/ do
1183
+ # ...
1184
+ end
1185
+
1186
+ after '/blog/*', :host_name => 'example.com' do
1187
+ # ...
1188
+ end
1189
+ ```
1190
+
1191
+ ## 헬퍼(Helpers)
1192
+
1193
+ 톱-레벨의 `helpers` 메서드를 사용하여 라우터 핸들러와 템플릿에서 사용할 헬퍼
1194
+ 메서드들을 정의할 수 있습니다.
1195
+
1196
+ ``` ruby
1197
+ helpers do
1198
+ def bar(name)
1199
+ "#{name}bar"
1200
+ end
1201
+ end
1202
+
1203
+ get '/:name' do
1204
+ bar(params[:name])
1205
+ end
1206
+ ```
1207
+
1208
+ 또는, 헬퍼 메서드는 별도의 모듈 속에 정의할 수도 있습니다.
1209
+
1210
+ ``` ruby
1211
+ module FooUtils
1212
+ def foo(name) "#{name}foo" end
1213
+ end
1214
+
1215
+ module BarUtils
1216
+ def bar(name) "#{name}bar" end
1217
+ end
1218
+
1219
+ helpers FooUtils, BarUtils
1220
+ ```
1221
+
1222
+ 이 것은 모듈을 애플리케이션 클래스에 포함(include)시킨 것과 같습니다.
1223
+
1224
+ ### 세션(Sessions) 사용하기
1225
+
1226
+ 세션은 요청 동안에 상태를 유지하기 위해 사용합니다.
1227
+ 세션이 활성화되면, 사용자 세션 당 세션 해시 하나씩을 갖게 됩니다.
1228
+
1229
+ ``` ruby
1230
+ enable :sessions
1231
+
1232
+ get '/' do
1233
+ "value = " << session[:value].inspect
1234
+ end
1235
+
1236
+ get '/:value' do
1237
+ session[:value] = params[:value]
1238
+ end
1239
+ ```
1240
+
1241
+ `enable :sessions`은 실은 모든 데이터를 쿠키 속에 저장하는 것에 주의하세요.
1242
+ 이 방식이 바람직하지 않을 수도 있습니다. (예를 들어, 많은 양의 데이터를
1243
+ 저장하게 되면 트래픽이 늘어납니다).
1244
+ 이런 경우에는 랙 세션 미들웨어(Rack session middleware)를 사용할 수 있습니다.
1245
+ `enable :sessions`을 호출하지 **않는** 대신에, 선택한 미들웨어를 다른
1246
+ 미들웨어들처럼 포함시키면 됩니다.
1247
+
1248
+ ``` ruby
1249
+ use Rack::Session::Pool, :expire_after => 2592000
1250
+
1251
+ get '/' do
1252
+ "value = " << session[:value].inspect
1253
+ end
1254
+
1255
+ get '/:value' do
1256
+ session[:value] = params[:value]
1257
+ end
1258
+ ```
1259
+
1260
+ 보안 강화을 위해서, 쿠키 속의 세션 데이터는 세션 시크릿(secret)으로
1261
+ 사인(sign)됩니다. Sinatra는 무작위 시크릿을 생성합니다. 하지만, 이
1262
+ 시크릿은 애플리케이션 시작 시마다 변경되기 때문에, 애플리케이션의
1263
+ 모든 인스턴스들이 공유할 시크릿을 직접 만들 수도 있습니다.
1264
+
1265
+ ``` ruby
1266
+ set :session_secret, 'super secret'
1267
+ ```
1268
+
1269
+ 조금 더 세부적인 설정이 필요하다면, `sessions` 설정에서 옵션이 있는
1270
+ 해시를 저장할 수도 있습니다.
1271
+
1272
+ ``` ruby
1273
+ set :sessions, :domain => 'foo.com'
1274
+ ```
1275
+
1276
+ 세션을 다른 foo.com의 서브도메인 들과 공유하기 원한다면, 다음에 나오는
1277
+ 것 처럼 도메인 앞에 *.*을 붙이셔야 합니다.
1278
+
1279
+ ``` ruby
1280
+ set :sessions, :domain => '.foo.com'
1281
+ ```
1282
+
1283
+ ### 중단하기(Halting)
1284
+
1285
+ 필터나 라우터에서 요청을 즉각 중단하고 싶을 때 사용하합니다.
1286
+
1287
+ ``` ruby
1288
+ halt
1289
+ ```
1290
+
1291
+ 중단할 때 상태를 지정할 수도 있습니다.
1292
+
1293
+ ``` ruby
1294
+ halt 410
1295
+ ```
1296
+
1297
+ 본문을 넣을 수도 있습니다.
1298
+
1299
+ ``` ruby
1300
+ halt 'this will be the body'
1301
+ ```
1302
+
1303
+ 둘 다 할 수도 있습니다.
1304
+
1305
+ ``` ruby
1306
+ halt 401, 'go away!'
1307
+ ```
1308
+
1309
+ 헤더를 추가할 경우에는 다음과 같이 하면 됩니다.
1310
+
1311
+ ``` ruby
1312
+ halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
1313
+ ```
1314
+
1315
+ 당연히 `halt`와 템플릿은 같이 사용할 수 있습니다.
1316
+
1317
+ ``` ruby
1318
+ halt erb(:error)
1319
+ ```
1320
+
1321
+ ### 넘기기(Passing)
1322
+
1323
+ 라우터는 `pass`를 사용하여 다음 번 매칭되는 라우터로 처리를 넘길 수 있습니다.
1324
+
1325
+ ``` ruby
1326
+ get '/guess/:who' do
1327
+ pass unless params[:who] == 'Frank'
1328
+ 'You got me!'
1329
+ end
1330
+
1331
+ get '/guess/*' do
1332
+ 'You missed!'
1333
+ end
1334
+ ```
1335
+
1336
+ 이 때 라우터 블록에서 즉각 빠져나오게 되고 제어는 다음 번 매칭되는 라우터로
1337
+ 넘어갑니다. 만약 매칭되는 라우터를 찾지 못하면, 404가 반환됩니다.
1338
+
1339
+ ### 다른 라우터 부르기(Triggering Another Route)
1340
+
1341
+ 때로는 `pass`가 아니라, 다른 라우터를 호출한 결과를 얻고 싶을 때도
1342
+ 있습니다. 이럴때는 간단하게 `call`을 사용하면 됩니다.
1343
+
1344
+ ``` ruby
1345
+ get '/foo' do
1346
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
1347
+ [status, headers, body.map(&:upcase)]
1348
+ end
1349
+
1350
+ get '/bar' do
1351
+ "bar"
1352
+ end
1353
+ ```
1354
+
1355
+ 위 예제의 경우, `"bar"`를 헬퍼로 옮겨 `/foo`와 `/bar` 모두에서 사용하도록
1356
+ 하면 테스팅을 쉽게 하고 성능을 높일 수 있습니다.
1357
+
1358
+ 요청의 사본이 아닌 바로 그 인스턴스로 보내지도록 하고 싶다면,
1359
+ `call` 대신 `call!`을 사용하면 됩니다.
1360
+
1361
+ `call`에 대한 더 자세한 내용은 Rack 명세를 참고하세요.
1362
+
1363
+ ### 본문, 상태 코드 및 헤더 설정하기
1364
+
1365
+ 라우터 블록의 반환값과 함께 상태 코드(status code)와 응답 본문(response body)을
1366
+ 설정할수 있고 권장됩니다. 하지만, 경우에 따라서는 본문을 실행 흐름 중의 임의
1367
+ 지점에서 설정해야 할때도 있습니다. 이런 경우 `body` 헬퍼 메서드를 사용하면
1368
+ 됩니다. 이렇게 하면, 그 순간부터 본문에 접근할 때 그 메서드를 사용할 수가 있습니다.
1369
+
1370
+ ``` ruby
1371
+ get '/foo' do
1372
+ body "bar"
1373
+ end
1374
+
1375
+ after do
1376
+ puts body
1377
+ end
1378
+ ```
1379
+
1380
+ `body`로 블록을 전달하는 것도 가능하며, 이 블록은 랙(Rack) 핸들러에 의해
1381
+ 실행됩니다. (이 방법은 스트리밍을 구현할 때 사용할 수 있습니다. "값
1382
+ 반환하기"를 참고하세요).
1383
+
1384
+ 본문와 마찬가지로, 상태코드와 헤더도 설정할 수 있습니다.
1385
+
1386
+ ``` ruby
1387
+ get '/foo' do
1388
+ status 418
1389
+ headers \
1390
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1391
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1392
+ body "I'm a tea pot!"
1393
+ end
1394
+ ```
1395
+
1396
+ `body`처럼, `header`와 `status`도 매개변수 없이 사용하여 현재 값을
1397
+ 액세스할 수 있습니다.
1398
+
1399
+ ### 응답 스트리밍(Streaming Responses)
1400
+
1401
+ 응답 본문의 일정 부분을 계속 생성하는 가운데 데이터를 내보내기 시작하고
1402
+ 싶을 경우가 있습니다. 극단적인 예제로, 클라이언트가 접속을 끊기 전까지
1403
+ 계속 데이터를 내보내고 싶을 경우도 있죠. 여러분만의 래퍼(wrapper)를
1404
+ 만들지 않으려면 `stream` 헬퍼를 사용하면 됩니다.
1405
+
1406
+ ``` ruby
1407
+ get '/' do
1408
+ stream do |out|
1409
+ out << "It's gonna be legen -\n"
1410
+ sleep 0.5
1411
+ out << " (wait for it) \n"
1412
+ sleep 1
1413
+ out << "- dary!\n"
1414
+ end
1415
+ end
1416
+ ```
1417
+
1418
+ 이렇게 스트리밍 API나 [서버 발송 이벤트Server Sent
1419
+ Events](http://dev.w3.org/html5/eventsource/)를 구현할 수 있고, 이 방법은
1420
+ [WebSockets](http://en.wikipedia.org/wiki/WebSocket)을 위한 기반으로 사용됩니다.
1421
+ 이 방법은 일부 콘텐츠가 느린 자원에 의존하는 경우에 스로풋(throughtput)을
1422
+ 높이기 위해 사용되기도 합니다.
1423
+
1424
+ 스트리밍 동작, 특히 동시 요청의 수는 애플리케이션을 서빙하는 웹서버에 크게
1425
+ 의존합니다. WEBRick서버 같은 일부의 경우 아예 스트리밍을 지원하지 조차 않습니다.
1426
+ 만약 서버가 스트리밍을 지원하지 않는다면, 본문은 `stream` 으로 전달된 블록이
1427
+ 수행을 마친 후에 한꺼번에 반환됩니다. 이런 한번에 쏘는 샷건같은 방식으로는
1428
+ 스트리밍은 움직이지 않습니다.
1429
+
1430
+ 선택적 매개변수 `keep_open`이 설정되어 있다면, 스트림 객체에서 `close`를
1431
+ 호출하지 않을 것이고, 나중에 실행 흐름 상의 어느 시점에서 스트림을 닫을 수
1432
+ 있습니다. 이 옵션은 Thin과 Rainbow 같은 이벤트 기반 서버에서만 작동하고
1433
+ 다른 서버들은 여전히 스트림을 닫습니다.
1434
+
1435
+ ``` ruby
1436
+ # long polling
1437
+
1438
+ set :server, :thin
1439
+ connections = []
1440
+
1441
+ get '/subscribe' do
1442
+ # register a client's interest in server events
1443
+ stream(:keep_open) { |out| connections << out }
1444
+
1445
+ # purge dead connections
1446
+ connections.reject!(&:closed?)
1447
+
1448
+ # acknowledge
1449
+ "subscribed"
1450
+ end
1451
+
1452
+ post '/message' do
1453
+ connections.each do |out|
1454
+ # notify client that a new message has arrived
1455
+ out << params[:message] << "\n"
1456
+
1457
+ # indicate client to connect again
1458
+ out.close
1459
+ end
1460
+
1461
+ # acknowledge
1462
+ "message received"
1463
+ end
1464
+ ```
1465
+
1466
+ ### 로깅(Logging)
1467
+
1468
+ 요청 스코프(request scope) 내에서, `Logger`의 인스턴스인 `logger`
1469
+ 헬퍼를 사용할 수 있습니다.
1470
+
1471
+ ``` ruby
1472
+ get '/' do
1473
+ logger.info "loading data"
1474
+ # ...
1475
+ end
1476
+ ```
1477
+
1478
+ 이 로거는 자동으로 Rack 핸들러에서 설정한 로그설정을 참고합니다.
1479
+ 만약 로깅이 비활성상태라면, 이 메서드는 더미(dummy) 객체를 반환하기 때문에,
1480
+ 라우터나 필터에서 이 부분에 대해 걱정할 필요는 없습니다.
1481
+
1482
+ 로깅은 `Sinatra::Application`에서만 기본으로 활성화되어 있음에 유의합시다.
1483
+ 만약 `Sinatra::Base`로부터 상속받은 경우라면 직접 활성화시켜 줘야 합니다.
1484
+
1485
+ ``` ruby
1486
+ class MyApp < Sinatra::Base
1487
+ configure :production, :development do
1488
+ enable :logging
1489
+ end
1490
+ end
1491
+ ```
1492
+
1493
+ 로깅 미들웨어를 사용하지 않으려면, `logging` 설정을 `nil`로 두면 됩니다.
1494
+ 하지만, 이 경우 주의할 것은 `logger`는 `nil`을 반환하는 것입니다.
1495
+ 통상적인 유스케이스는 여러분만의 로거를 사용하고자 할 경우일 것입니다.
1496
+ Sinatra는 `env['rack.logger']`에서 찾은 로거를 사용할 것입니다.
1497
+
1498
+ ### 마임 타입(Mime Types)
1499
+
1500
+ `send_file`이나 정적인 파일을 사용할 때에 Sinatra가 인식하지 못하는
1501
+ 마임 타입이 있을 수 있습니다. 이 경우 `mime_type`을 사용하여 파일
1502
+ 확장자를 등록합니다.
1503
+
1504
+ ``` ruby
1505
+ configure do
1506
+ mime_type :foo, 'text/foo'
1507
+ end
1508
+ ```
1509
+
1510
+ `content_type` 헬퍼로 쓸 수도 있습니다.
1511
+
1512
+ ``` ruby
1513
+ get '/' do
1514
+ content_type :foo
1515
+ "foo foo foo"
1516
+ end
1517
+ ```
1518
+
1519
+ ### URL 생성하기
1520
+
1521
+ URL을 생성할때 `url` 헬퍼 메서드를 사용합니다. 예를 들어 Haml에서는 이렇게
1522
+ 합니다.
1523
+
1524
+ ``` ruby
1525
+ %a{:href => url('/foo')} foo
1526
+ ```
1527
+
1528
+ 이것은 리버스 프록시(reverse proxies)와 Rack 라우터가 있다면 참고합니다.
1529
+
1530
+ 이 메서드는 `to`라는 별칭으로도 사용할 수 있습니다. (아래 예제 참조)
1531
+
1532
+ ### 브라우저 재지정(Browser Redirect)
1533
+
1534
+ `redirect` 헬퍼 메서드를 사용하여 브라우저를 리다이렉트 시킬 수 있습니다.
1535
+
1536
+ ``` ruby
1537
+ get '/foo' do
1538
+ redirect to('/bar')
1539
+ end
1540
+ ```
1541
+
1542
+ 다른 부가적인 매개변수들은 `halt`에 전달하는 인자들과 비슷합니다.
1543
+
1544
+ ``` ruby
1545
+ redirect to('/bar'), 303
1546
+ redirect 'http://google.com', 'wrong place, buddy'
1547
+ ```
1548
+
1549
+ `redirect back`을 사용하면 쉽게 사용자가 왔던 페이지로 다시 돌아가게
1550
+ 할 수 있습니다.
1551
+
1552
+ ``` ruby
1553
+ get '/foo' do
1554
+ "<a href='/bar'>do something</a>"
1555
+ end
1556
+
1557
+ get '/bar' do
1558
+ do_something
1559
+ redirect back
1560
+ end
1561
+ ```
1562
+
1563
+ 리다이렉트와 함께 인자를 전달하려면, 쿼리로 붙이거나,
1564
+
1565
+ ``` ruby
1566
+ redirect to('/bar?sum=42')
1567
+ ```
1568
+
1569
+ 세션을 사용하면 됩니다.
1570
+
1571
+ ``` ruby
1572
+ enable :sessions
1573
+
1574
+ get '/foo' do
1575
+ session[:secret] = 'foo'
1576
+ redirect to('/bar')
1577
+ end
1578
+
1579
+ get '/bar' do
1580
+ session[:secret]
1581
+ end
1582
+ ```
1583
+
1584
+ ### 캐시 컨트롤(Cache Control)
1585
+
1586
+ 헤더를 정확하게 설정하는 것은 적절한 HTTP 캐싱의 기본입니다.
1587
+
1588
+ Cache-Control 헤더를 다음과 같이 간단하게 설정할 수 있습니다.
1589
+
1590
+ ``` ruby
1591
+ get '/' do
1592
+ cache_control :public
1593
+ "cache it!"
1594
+ end
1595
+ ```
1596
+
1597
+ 프로 팁: 캐싱은 사전 필터에서 설정하세요.
1598
+
1599
+ ``` ruby
1600
+ before do
1601
+ cache_control :public, :must_revalidate, :max_age => 60
1602
+ end
1603
+ ```
1604
+
1605
+ `expires` 헬퍼를 사용하여 그에 상응하는 헤더를 설정한다면,
1606
+ `Cache-Control`이 자동으로 설정됩니다.
1607
+
1608
+ ``` ruby
1609
+ before do
1610
+ expires 500, :public, :must_revalidate
1611
+ end
1612
+ ```
1613
+
1614
+ 캐시를 잘 사용하려면, `etag` 또는 `last_modified`의 사용을 고려해야 할 것이다.
1615
+ 무거운 작업을 하기 *전*에 이들 헬퍼를 호출하길 권장합니다. 이렇게 하면,
1616
+ 클라이언트 캐시에 현재 버전이 이미 들어 있을 경우엔 즉각 응답을
1617
+ 뿌릴(flush) 것입니다.
1618
+
1619
+ ``` ruby
1620
+ get '/article/:id' do
1621
+ @article = Article.find params[:id]
1622
+ last_modified @article.updated_at
1623
+ etag @article.sha1
1624
+ erb :article
1625
+ end
1626
+ ```
1627
+
1628
+ [약한 ETag](http://en.wikipedia.org/wiki/HTTP_ETag#Strong_and_weak_validation)를
1629
+ 사용할 수 도 있습니다.
1630
+
1631
+ ``` ruby
1632
+ etag @article.sha1, :weak
1633
+ ```
1634
+
1635
+ 이들 헬퍼는 어떠한 캐싱도 하지 않으며, 대신 캐시에 필요한 정보를 제공합니다.
1636
+ 손쉬운 리버스 프록시(reverse-proxy) 캐싱 솔루션을 찾고 있다면,
1637
+ [rack-cache](https://github.com/rtomayko/rack-cache)를 써보세요.
1638
+
1639
+ ``` ruby
1640
+ require "rack/cache"
1641
+ require "sinatra"
1642
+
1643
+ use Rack::Cache
1644
+
1645
+ get '/' do
1646
+ cache_control :public, :max_age => 36000
1647
+ sleep 5
1648
+ "hello"
1649
+ end
1650
+ ```
1651
+
1652
+ 정적 파일에 `Cache-Control` 헤더 정보를 추가하려면 `:static_cache_control`
1653
+ 설정(아래 참조)을 쓰세요.
1654
+
1655
+ RFC 2616에 따르면 If-Match 또는 If-None-Match 헤더가 `*`로 설정된 경우 요청한
1656
+ 리소스(resource)가 이미 존재하느냐 여부에 따라 다르게 취급해야 한다고 되어
1657
+ 있습니다. Sinatra는 (get 처럼) 안전하거나 (put 처럼) 멱등인 요청에 대한 리소스는
1658
+ 이미 존재한다고 가정하지만, 다른 리소스(예를 들면 post 요청 같은)의 경우는
1659
+ 새 리소스로 취급합니다. 이 행동은 `:new_resource` 옵션을 전달하여 변경할 수 있습니다.
1660
+
1661
+ ``` ruby
1662
+ get '/create' do
1663
+ etag '', :new_resource => true
1664
+ Article.create
1665
+ erb :new_article
1666
+ end
1667
+ ```
1668
+
1669
+ 약한 ETag를 사용하고자 한다면, `:kind`으로 전달합시다.
1670
+
1671
+ ``` ruby
1672
+ etag '', :new_resource => true, :kind => :weak
1673
+ ```
1674
+
1675
+ ### 파일 전송하기(Sending Files)
1676
+
1677
+ 파일을 전송하려면, `send_file` 헬퍼 메서드를 사용하면 됩니다.
1678
+
1679
+ ``` ruby
1680
+ get '/' do
1681
+ send_file 'foo.png'
1682
+ end
1683
+ ```
1684
+
1685
+ 이 메서드는 몇 가지 옵션을 받습니다.
1686
+
1687
+ ``` ruby
1688
+ send_file 'foo.png', :type => :jpg
1689
+ ```
1690
+
1691
+ 옵션들:
1692
+
1693
+ <dl>
1694
+ <dt>filename</dt>
1695
+ <dd>응답에서의 파일명. 기본값은 실제 파일명.</dd>
1696
+
1697
+ <dt>last_modified</dt>
1698
+ <dd>Last-Modified 헤더값. 기본값은 파일의 mtime.</dd>
1699
+
1700
+ <dt>type</dt>
1701
+ <dd>사용할 컨텐츠 유형. 없으면 파일 확장자로부터 유추.</dd>
1702
+
1703
+ <dt>disposition</dt>
1704
+ <dd>
1705
+ Content-Disposition에서 사용됨. 가능한 값들: <tt>nil</tt> (기본값),
1706
+ <tt>:attachment</tt> 및 <tt>:inline</tt>
1707
+ </dd>
1708
+
1709
+ <dt>length</dt>
1710
+ <dd>Content-Length, 기본값은 파일 크기.</dd>
1711
+
1712
+ <dt>status</dt>
1713
+ <dd>
1714
+ 전송할 상태 코드. 오류 페이지로 정적 파일을 전송할 경우에 유용.
1715
+
1716
+ Rack 핸들러가 지원할 경우, Ruby 프로세스로부터의 스트리밍이 아닌
1717
+ 다른 수단이 사용가능함. 이 헬퍼 메서드를 사용하게 되면, Sinatra는
1718
+ 자동으로 범위 요청(range request)을 처리함.
1719
+ </dd>
1720
+ </dl>
1721
+
1722
+
1723
+ ### 요청 객체에 접근하기(Accessing the Request Object)
1724
+
1725
+ 들어오는 요청 객에는 요청 레벨(필터, 라우터, 오류 핸들러)에서 `request`
1726
+ 메서드를 통해 접근 가능합니다.
1727
+
1728
+ ``` ruby
1729
+ # http://example.com/example 상에서 실행 중인 앱
1730
+ get '/foo' do
1731
+ t = %w[text/css text/html application/javascript]
1732
+ request.accept # ['text/html', '*/*']
1733
+ request.accept? 'text/xml' # true
1734
+ request.preferred_type(t) # 'text/html'
1735
+ request.body # 클라이언트로부터 전송된 요청 본문 (아래 참조)
1736
+ request.scheme # "http"
1737
+ request.script_name # "/example"
1738
+ request.path_info # "/foo"
1739
+ request.port # 80
1740
+ request.request_method # "GET"
1741
+ request.query_string # ""
1742
+ request.content_length # request.body의 길이
1743
+ request.media_type # request.body의 미디어 유형
1744
+ request.host # "example.com"
1745
+ request.get? # true (다른 동사에 대해 유사한 메서드 있음)
1746
+ request.form_data? # false
1747
+ request["SOME_HEADER"] # SOME_HEADER 헤더의 값
1748
+ request.referrer # 클라이언트의 리퍼러 또는 '/'
1749
+ request.user_agent # 사용자 에이전트 (:agent 조건에서 사용됨)
1750
+ request.cookies # 브라우저 쿠키의 해시
1751
+ request.xhr? # 이게 ajax 요청인가요?
1752
+ request.url # "http://example.com/example/foo"
1753
+ request.path # "/example/foo"
1754
+ request.ip # 클라이언트 IP 주소
1755
+ request.secure? # false (ssl 접속인 경우 true)
1756
+ request.forwarded? # true (리버스 프록시 하에서 작동 중이라면)
1757
+ request.env # Rack에 의해 처리되는 로우(raw) env 해시
1758
+ end
1759
+ ```
1760
+
1761
+ `script_name`, `path_info`같은 일부 옵션들은 이렇게 쓸 수도 있습니다.
1762
+
1763
+ ``` ruby
1764
+ before { request.path_info = "/" }
1765
+
1766
+ get "/" do
1767
+ "all requests end up here"
1768
+ end
1769
+ ```
1770
+
1771
+ `request.body`는 IO 객체이거나 StringIO 객체입니다.
1772
+
1773
+ ``` ruby
1774
+ post "/api" do
1775
+ request.body.rewind # 누군가 이미 읽은 경우
1776
+ data = JSON.parse request.body.read
1777
+ "Hello #{data['name']}!"
1778
+ end
1779
+ ```
1780
+
1781
+ ### 첨부(Attachments)
1782
+
1783
+ `attachment` 헬퍼를 사용하여 응답이 브라우저에 표시하는 대신
1784
+ 디스크에 저장되어야 함을 블라우저에게 알릴 수 있습니다.
1785
+
1786
+ ``` ruby
1787
+ get '/' do
1788
+ attachment
1789
+ "store it!"
1790
+ end
1791
+ ```
1792
+
1793
+ 파일명을 전달할 수도 있습니다.
1794
+
1795
+ ``` ruby
1796
+ get '/' do
1797
+ attachment "info.txt"
1798
+ "store it!"
1799
+ end
1800
+ ```
1801
+
1802
+ ### 날짜와 시간 다루기
1803
+
1804
+ Sinatra는 `time_for_` 헬퍼 메서드를 제공합니다. 이 메서드는
1805
+ 주어진 값으로부터 Time 객체를 생성한다. `DateTime`, `Date` 같은
1806
+ 비슷한 클래스들도 변환됩니다.
1807
+
1808
+ ``` ruby
1809
+ get '/' do
1810
+ pass if Time.now > time_for('Dec 23, 2012')
1811
+ "still time"
1812
+ end
1813
+ ```
1814
+
1815
+ 이 메서드는 내부적으로 `expires` 나 `last_modified` 같은 곳에서 사용됩니다.
1816
+ 따라서 여러분은 애플리케이션에서 `time_for`를 오버라이딩하여 이들 메서드의
1817
+ 동작을 쉽게 확장할 수 있습니다.
1818
+
1819
+ ``` ruby
1820
+ helpers do
1821
+ def time_for(value)
1822
+ case value
1823
+ when :yesterday then Time.now - 24*60*60
1824
+ when :tomorrow then Time.now + 24*60*60
1825
+ else super
1826
+ end
1827
+ end
1828
+ end
1829
+
1830
+ get '/' do
1831
+ last_modified :yesterday
1832
+ expires :tomorrow
1833
+ "hello"
1834
+ end
1835
+ ```
1836
+
1837
+ ### 템플릿 파일 참조하기
1838
+
1839
+ `find_template`는 렌더링할 템플릿 파일을 찾는데 사용됩니다.
1840
+
1841
+ ``` ruby
1842
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1843
+ puts "could be #{file}"
1844
+ end
1845
+ ```
1846
+
1847
+ 이것만으로는 그렇게 유용하지는 않습니다만, 이 메서드를 오버라이드하여 여러분만의
1848
+ 참조 메커니즘에서 가로채게 하면 유용해집니다. 예를 들어, 하나 이상의 뷰 디렉터리를
1849
+ 사용하고자 한다면 이렇게 하세요.
1850
+
1851
+ ``` ruby
1852
+ set :views, ['views', 'templates']
1853
+
1854
+ helpers do
1855
+ def find_template(views, name, engine, &block)
1856
+ Array(views).each { |v| super(v, name, engine, &block) }
1857
+ end
1858
+ end
1859
+ ```
1860
+
1861
+ 다른 예제는 각 엔진마다 다른 디렉터리를 사용할 경우입니다.
1862
+
1863
+ ``` ruby
1864
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1865
+
1866
+ helpers do
1867
+ def find_template(views, name, engine, &block)
1868
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1869
+ folder ||= views[:default]
1870
+ super(folder, name, engine, &block)
1871
+ end
1872
+ end
1873
+ ```
1874
+
1875
+ 여러분은 이것을 간단하게 확장(extension)으로 만들어 다른 사람들과 공유할 수 있다!
1876
+
1877
+ `find_template`은 그 파일이 실제 존재하는지 검사하지 않음에 유의합니다.
1878
+ 모든 가능한 경로에 대해 주어진 블록을 호출할 뿐입니다. 이것은 성능 문제는
1879
+ 되지 않습니다. 왜냐하면 `render`는 파일이 발견되는 즉시 `break`하기 때문입니다.
1880
+ 또한, 템플릿 위치(그리고 콘텐츠)는 개발 모드에서 실행 중이 아니라면 캐시될 것입니다.
1881
+ 정말로 멋진 메세드를 작성하고 싶다면 이 점을 명심하세요.
1882
+
1883
+ ## 설정(Configuration)
1884
+
1885
+ 모든 환경에서, 시작될 때, 한번만 실행되게 하려면 이렇게 하면 됩니다.
1886
+
1887
+ ``` ruby
1888
+ configure do
1889
+ # 옵션 하나 설정
1890
+ set :option, 'value'
1891
+
1892
+ # 여러 옵션 설정
1893
+ set :a => 1, :b => 2
1894
+
1895
+ # `set :option, true`와 동일
1896
+ enable :option
1897
+
1898
+ # `set :option, false`와 동일
1899
+ disable :option
1900
+
1901
+ # 블록으로 동적인 설정을 할 수도 있음
1902
+ set(:css_dir) { File.join(views, 'css') }
1903
+ end
1904
+ ```
1905
+
1906
+ 환경(RACK_ENV 환경 변수)이 `:production`일 때만 실행되게 하려면 이렇게 하면 됩니다.
1907
+
1908
+ ``` ruby
1909
+ configure :production do
1910
+ ...
1911
+ end
1912
+ ```
1913
+
1914
+ 환경이 `:production` 또는 `:test`일 때 실행되게 하려면 이렇게 하면 됩니다.
1915
+
1916
+ ``` ruby
1917
+ configure :production, :test do
1918
+ ...
1919
+ end
1920
+ ```
1921
+
1922
+ 이 옵션들은 `settings`를 통해 접근 가능합니다.
1923
+
1924
+ ``` ruby
1925
+ configure do
1926
+ set :foo, 'bar'
1927
+ end
1928
+
1929
+ get '/' do
1930
+ settings.foo? # => true
1931
+ settings.foo # => 'bar'
1932
+ ...
1933
+ end
1934
+ ```
1935
+
1936
+ ### 공격 방어 설정하기(Configuring attack protection)
1937
+
1938
+ Sinatra는 [Rack::Protection](https://github.com/rkh/rack-protection#readme)을 사용하여
1939
+ 일반적이고 일어날 수 있는 공격에 대비합니다. 이 모듈은 간단하게 비활성시킬 수 있습니다.
1940
+ (하지만 애플리케이션에 엄청나게 많은 취약성을 야기합니다.)
1941
+
1942
+ ``` ruby
1943
+ disable :protection
1944
+ ```
1945
+
1946
+ 하나의 방어층만 스킵하려면, 옵션 해시에 `protection`을 설정하면 됩니다.
1947
+
1948
+ ``` ruby
1949
+ set :protection, :except => :path_traversal
1950
+ ```
1951
+
1952
+ 배열로 넘김으로써 방어층 여러 개를 비활성화할 수 있습니다.
1953
+
1954
+ ``` ruby
1955
+ set :protection, :except => [:path_traversal, :session_hijacking]
1956
+ ```
1957
+
1958
+ 기본적으로 `:sessions`가 활성 중일 때만 Sinatra는 방어층을 설정합니다.
1959
+ 때로는 자신만의 세션을 설정할 때도 있습니다. 이런 경우 `:session` 옵션을
1960
+ 넘겨줌으로써 세션을 기반으로한 방어층을 설정 할 수 있습니다.
1961
+
1962
+ ``` ruby
1963
+ use Rack::Session::Pool
1964
+ set :protection, :session => true
1965
+ ```
1966
+
1967
+ ### 가능한 설정들(Available Settings)
1968
+
1969
+ <dl>
1970
+ <dt>absolute_redirects</dt>
1971
+ <dd>
1972
+ 만약 비활성이면, Sinatra는 상대경로 리다이렉트를 허용할 것이지만,
1973
+ 이렇게 되면 Sinatra는 더 이상 오직 절대경로 리다이렉트만 허용하고 있는
1974
+ RFC 2616(HTTP 1.1)에 위배됨.
1975
+ </dd>
1976
+ <dd>
1977
+ 적정하게 설정되지 않은 리버스 프록시 하에서 앱을 실행 중이라면 활성화시킬 것.
1978
+ <tt>rul</tt> 헬퍼는, 만약 두 번째 매개변수로 <tt>false</tt>를 전달하지만 않는다면,
1979
+ 여전히 절대경로 URL을 생성할 것임에 유의.
1980
+ </dd>
1981
+ <dd>기본값은 비활성.</dd>
1982
+
1983
+ <dt>add_charsets</dt>
1984
+ <dd>
1985
+ <tt>content_type</tt>가 문자셋 정보에 자동으로 추가하게 될 마임(mime) 타입.
1986
+ 이 옵션은 오버라이딩하지 말고 추가해야 함.
1987
+ <tt>settings.add_charsets << "application/foobar"</tt>
1988
+ </dd>
1989
+
1990
+ <dt>app_file</dt>
1991
+ <dd>
1992
+ 메인 애플리케이션 파일의 경로. 프로젝트 루트, 뷰, public 폴더,
1993
+ 인라인 템플릿을 파악할 때 사용됨.
1994
+ </dd>
1995
+
1996
+ <dt>bind</dt>
1997
+ <dd>바인드할 IP 주소(기본값: <tt>0.0.0.0</tt> <em>이나</em> `environment`가 개발로 설정 되어있으면 <tt>localhost</tt>). 오직 빌트인(built-in) 서버에서만 사용됨.</dd>
1998
+
1999
+ <dt>default_encoding</dt>
2000
+ <dd>인코딩을 알 수 없을 때 인코딩(기본값은 <tt>"utf-8"</tt>).</dd>
2001
+
2002
+ <dt>dump_errors</dt>
2003
+ <dd>로그안의 에러 출력.</dd>
2004
+
2005
+ <dt>environment</dt>
2006
+ <dd>
2007
+ 현재 환경, 기본값은 <tt>ENV['RACK_ENV']</tt> ENV에 없을 경우엔 "development".
2008
+ </dd>
2009
+
2010
+ <dt>logging</dt>
2011
+ <dd>로거(logger) 사용.</dd>
2012
+
2013
+ <dt>lock</dt>
2014
+ <dd>
2015
+ Ruby 프로세스 당 요청을 동시에 할 경우에만 매 요청에 걸쳐 잠금(lock)을 설정.
2016
+ </dd>
2017
+ <dd>앱이 스레드에 안전(thread-safe)하지 않으면 활성화시킬 것. 기본값은 비활성.</dd>
2018
+
2019
+ <dt>method_override</dt>
2020
+ <dd>
2021
+ put/delete를 지원하지 않는 브라우저에서 put/delete 폼을 허용하는
2022
+ <tt>_method</tt> 꼼수 사용.
2023
+ </dd>
2024
+
2025
+ <dt>port</dt>
2026
+ <dd>접속 포트. 빌트인 서버에서만 사용됨.</dd>
2027
+
2028
+ <dt>prefixed_redirects</dt>
2029
+ <dd>
2030
+ 절대경로가 주어지지 않은 리다이렉트에 <tt>request.script_name</tt>를
2031
+ 삽입할지 여부를 결정. 활성화 하면 <tt>redirect '/foo'</tt>는
2032
+ <tt>redirect to('/foo')</tt>처럼 동작. 기본값은 비활성.
2033
+ </dd>
2034
+
2035
+ <dt>protection</dt>
2036
+ <dd>웹 공격 방어를 활성화시킬 건지 여부. 위의 보안 섹션 참조.</dd>
2037
+
2038
+ <dt>public_dir</dt>
2039
+ <dd><tt>public_folder</tt>의 별칭. 밑을 참조.</dd>
2040
+
2041
+ <dt>public_folder</dt>
2042
+ <dd>
2043
+ public 파일이 제공될 폴더의 경로.
2044
+ static 파일 제공이 활성화된 경우만 사용됨(아래 <tt>static</tt>참조).
2045
+ 만약 설정이 없으면 <tt>app_file</tt>로부터 유추됨.
2046
+ </dd>
2047
+
2048
+ <dt>reload_templates</dt>
2049
+ <dd>
2050
+ 요청 간에 템플릿을 리로드(reload)할 건지 여부. 개발 모드에서는 활성됨.
2051
+ </dd>
2052
+
2053
+ <dt>root</dt>
2054
+ <dd>
2055
+ 프로젝트 루트 디렉터리 경로. 설정이 없으면 <tt>app_file</tt> 설정으로부터 유추됨.
2056
+ </dd>
2057
+
2058
+ <dt>raise_errors</dt>
2059
+ <dd>
2060
+ 예외 발생(애플리케이션은 중단됨).
2061
+ 기본값은 <tt>environment</tt>가 <tt>"test"</tt>인 경우는 활성, 그렇지 않으면 비활성.
2062
+ </dd>
2063
+
2064
+ <dt>run</dt>
2065
+ <dd>
2066
+ 활성화되면, Sinatra가 웹서버의 시작을 핸들링.
2067
+ rackup 또는 다른 도구를 사용하는 경우라면 활성화시키지 말 것.
2068
+ </dd>
2069
+
2070
+ <dt>running</dt>
2071
+ <dd>빌트인 서버가 실행 중인가? 이 설정은 변경하지 말 것!</dd>
2072
+
2073
+ <dt>server</dt>
2074
+ <dd>
2075
+ 빌트인 서버로 사용할 서버 또는 서버 목록.
2076
+ 기본값은 루비구현에 따라 다르며 순서는 우선순위를 의미.
2077
+ </dd>
2078
+
2079
+ <dt>sessions</dt>
2080
+ <dd>
2081
+ <tt>Rack::Session::Cookie</tt>를 사용한 쿠키 기반 세션 활성화.
2082
+ 보다 자세한 정보는 '세션 사용하기' 참조.
2083
+ </dd>
2084
+
2085
+ <dt>show_exceptions</dt>
2086
+ <dd>
2087
+ 예외 발생 시에 브라우저에 스택 추적을 보임.
2088
+ 기본값은 <tt>environment</tt>가 <tt>"development"</tt>인
2089
+ 경우는 활성, 나머지는 비활성.
2090
+ </dd>
2091
+ <dd>
2092
+ <tt>:after_handler</tt>를 설정함으로써 브라우저에서
2093
+ 스택 트레이스를 보여주기 전에 앱에 특화된 에러 핸들링을
2094
+ 할 수도 있음.
2095
+ </dd>
2096
+
2097
+ <dt>static</dt>
2098
+ <dd>Sinatra가 정적(static) 파일을 핸들링할 지 여부를 설정.</dd>
2099
+ <dd>이 기능이 가능한 서버를 사용하는 경우라면 비활성시킬 것.</dd>
2100
+ <dd>비활성시키면 성능이 올라감.</dd>
2101
+ <dd>
2102
+ 기본값은 전통적 방식에서는 활성, 모듈 앱에서는 비활성.
2103
+ </dd>
2104
+
2105
+ <dt>static_cache_control</dt>
2106
+ <dd>
2107
+ Sinatra가 정적 파일을 제공하는 경우, 응답에 <tt>Cache-Control</tt> 헤더를
2108
+ 추가할 때 설정. <tt>cache_control</tt> 헬퍼를 사용.
2109
+ 기본값은 비활성.
2110
+ </dd>
2111
+ <dd>
2112
+ 여러 값을 설정할 경우는 명시적으로 배열을 사용할 것:
2113
+ <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
2114
+ </dd>
2115
+
2116
+ <dt>threaded</dt>
2117
+ <dd>
2118
+ <tt>true</tt>로 설정하면, Thin이 요청을 처리하는데 있어
2119
+ <tt>EventMachine.defer</tt>를 사용하도록 함.
2120
+ </dd>
2121
+
2122
+ <dt>views</dt>
2123
+ <dd>
2124
+ 뷰 폴더 경로. 설정하지 않은 경우 <tt>app_file</tt>로부터 유추됨.
2125
+ </dd>
2126
+
2127
+ <dt>x_cascade</dt>
2128
+ <dd>
2129
+ 라우트를 찾지못했을 때의 X-Cascade 해더를 설정여부.
2130
+ 기본값은 <tt>true</tt>
2131
+ </dd>
2132
+ </dl>
2133
+
2134
+
2135
+ ## 환경(Environments)
2136
+
2137
+ 3가지의 미리 정의된 `environments` `"development"`, `"production"`, `"test"`
2138
+ 가 있습니다. 환경은 `RACK_ENV` 환경 변수를 통해서도 설정됩니다. 기본값은
2139
+ `"development"`입니다. `"development"` 모드에서는 모든 템플릿들은 요청 간에
2140
+ 리로드됩니다. 또, `"development"` 모드에서는 특별한 `not_found` 와 `error`
2141
+ 핸들러가 브라우저에서 스택 트레이스를 볼 수 있게합니다.
2142
+ `"production"`과 `"test"`에서는 기본적으로 템플릿은 캐시됩니다.
2143
+
2144
+ 다른 환경으로 실행시키려면 `RACK_ENV` 환경 변수를 사용하세요.
2145
+
2146
+ ``` shell
2147
+ RACK_ENV=production ruby my_app.rb
2148
+ ```
2149
+
2150
+ 현재 설정된 환경이 무엇인지 검사하기 위해서는 준비된 `development?`, `test?`,
2151
+ `production?` 메서드를 사용할 수 있습니다.
2152
+
2153
+ ``` ruby
2154
+ get '/' do
2155
+ if settings.development?
2156
+ "development!"
2157
+ else
2158
+ "not development!"
2159
+ end
2160
+ end
2161
+ ```
2162
+
2163
+ ## 에러 처리(Error Handling)
2164
+
2165
+ 예외 핸들러는 라우터 및 사전 필터와 동일한 맥락에서 실행됩니다.
2166
+ 이 말인즉, `haml`, `erb`, `halt`같은 이들이 제공하는 모든 것들을 사용할 수
2167
+ 있다는 뜻입니다.
2168
+
2169
+ ### 찾을 수 없음(Not Found)
2170
+
2171
+ `Sinatra::NotFound` 예외가 발생하거나 또는 응답의 상태 코드가 404라면,
2172
+ `not_found` 핸들러가 호출됩니다.
2173
+
2174
+ ``` ruby
2175
+ not_found do
2176
+ '아무 곳에도 찾을 수 없습니다.'
2177
+ end
2178
+ ```
2179
+
2180
+ ### 에러
2181
+
2182
+ `error` 핸들러는 라우터 또는 필터에서 뭐든 오류가 발생할 경우에 호출됩니다.
2183
+ 예외 객체는 Rack 변수 `sinatra.error`로부터 얻을 수 있습니다.
2184
+
2185
+ ``` ruby
2186
+ error do
2187
+ '고약한 오류가 발생했군요 - ' + env['sinatra.error'].name
2188
+ end
2189
+ ```
2190
+
2191
+ 사용자 정의 오류는 이렇게 정의한다.
2192
+
2193
+ ``` ruby
2194
+ error MyCustomError do
2195
+ '무슨 일이 생겼나면요...' + env['sinatra.error'].message
2196
+ end
2197
+ ```
2198
+
2199
+ 그런 다음, 이 오류가 발생하면 이렇게 처리한다.
2200
+
2201
+ ``` ruby
2202
+ get '/' do
2203
+ raise MyCustomError, '안좋은 일'
2204
+ end
2205
+ ```
2206
+
2207
+ 결과는 이렇습니다.
2208
+
2209
+ ```
2210
+ 무슨 일이 생겼냐면요... 안좋은 일
2211
+ ```
2212
+
2213
+ 상태 코드에 대해 오류 핸들러를 설치할 수도 있습니다.
2214
+
2215
+ ``` ruby
2216
+ error 403 do
2217
+ '액세스가 금지됨'
2218
+ end
2219
+
2220
+ get '/secret' do
2221
+ 403
2222
+ end
2223
+ ```
2224
+
2225
+ 범위로 지정할 수도 있습니다.
2226
+
2227
+ ``` ruby
2228
+ error 400..510 do
2229
+ '어이쿠'
2230
+ end
2231
+ ```
2232
+
2233
+ Sinatra는 개발 환경에서 동작할 때 브라우저에 괜찮은 스택 트레이스와 추가적인
2234
+ 디버그 정보를 보여주기 위해 특별한 `not_found` 와 `error` 핸들러를 설치합니다.
2235
+
2236
+ ## Rack 미들웨어(Rack Middleware)
2237
+
2238
+ Sinatra는 [Rack](http://rack.rubyforge.org/) 위에서 동작하며, Rack은 루비 웹
2239
+ 프레임워크를 위한 최소한의 표준 인터페이스입니다. Rack이 애플리케이션 개발자들에게
2240
+ 제공하는 가장 흥미로운 기능은 "미들웨어(middleware)"에 대한 지원입니다.
2241
+ 여기서 미들웨어란 서버와 여러분의 애플리케이션 사이에 위치하면서 HTTP 요청/응답을
2242
+ 모니터링하거나/조작함으로써 다양한 유형의 공통 기능을 제공하는 컴포넌트입니다.
2243
+
2244
+ Sinatra는 톱레벨의 `use` 메서드를 사용하여 Rack 미들웨어의 파이프라인을 만드는 일을
2245
+ 식은 죽 먹기로 만듭니다.
2246
+
2247
+ ``` ruby
2248
+ require 'sinatra'
2249
+ require 'my_custom_middleware'
2250
+
2251
+ use Rack::Lint
2252
+ use MyCustomMiddleware
2253
+
2254
+ get '/hello' do
2255
+ 'Hello World'
2256
+ end
2257
+ ```
2258
+
2259
+ `use`문법은 [Rack::Builder](http://rack.rubyforge.org/doc/classes/Rack/Builder.html]) DSL
2260
+ (rackup 파일에서 가장 많이 사용)에서 정의한 것과 동일합니다. 예를 들어, `use` 메서드는
2261
+ 블록이나 여러 개의/가변적인 인자도 받을 수 있습니다.
2262
+
2263
+ ``` ruby
2264
+ use Rack::Auth::Basic do |username, password|
2265
+ username == 'admin' && password == 'secret'
2266
+ end
2267
+ ```
2268
+
2269
+ Rack은 로깅, 디버깅, URL 라우팅, 인증, 그리고 세센 핸들링을 위한 다양한 표준
2270
+ 미들웨어로 분산되어 있습니다. Sinatra는 설정에 기반하여 이들 컴포넌트들 중
2271
+ 많은 것들을 자동으로 사용하며, 따라서 여러분은 일반적으로는 `use`를 명시적으로
2272
+ 사용할 필요가 없을 것입니다.
2273
+
2274
+ [rack](https://github.com/rack/rack/tree/master/lib/rack),
2275
+ [rack-contrib](https://github.com/rack/rack-contrib#readme),
2276
+ [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware)
2277
+ 에서 유용한 미들웨어들을 찾을 수 있습니다.
2278
+
2279
+ ## 테스팅(Testing)
2280
+
2281
+ Sinatra 테스트는 많은 Rack 기반 테스팅 라이브러리, 프레임워크를 사용하여 작성가능합니다.
2282
+ 그 중 [Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames)를 권장합니다.
2283
+
2284
+ ``` ruby
2285
+ require 'my_sinatra_app'
2286
+ require 'test/unit'
2287
+ require 'rack/test'
2288
+
2289
+ class MyAppTest < Test::Unit::TestCase
2290
+ include Rack::Test::Methods
2291
+
2292
+ def app
2293
+ Sinatra::Application
2294
+ end
2295
+
2296
+ def test_my_default
2297
+ get '/'
2298
+ assert_equal 'Hello World!', last_response.body
2299
+ end
2300
+
2301
+ def test_with_params
2302
+ get '/meet', :name => 'Frank'
2303
+ assert_equal 'Hello Frank!', last_response.body
2304
+ end
2305
+
2306
+ def test_with_rack_env
2307
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
2308
+ assert_equal "You're using Songbird!", last_response.body
2309
+ end
2310
+ end
2311
+ ```
2312
+
2313
+ 주의: Sinatra를 모듈러 방식으로 사용한다면, `Sinatra::Application`
2314
+ 를 앱에서 사용하는 클래스 이름으로 바꾸세요.
2315
+
2316
+ ## Sinatra::Base - 미들웨어(Middleware), 라이브러리(Libraries), 그리고 모듈 앱(Modular Apps)
2317
+
2318
+ 톱레벨에서 앱을 정의하는 것은 마이크로 앱(micro-app) 수준에서는 잘 동작하지만,
2319
+ Rack 미들웨어나, Rails 메탈(metal) 또는 서버 컴포넌트를 갖는 간단한 라이브러리,
2320
+ 또는 더 나아가 Sinatra 익스텐션(extension) 같은 재사용 가능한 컴포넌트들을 구축할
2321
+ 경우에는 심각한 약점이 있습니다. 톱레벨은 마이크로 앱 스타일의 설정을 가정하는 것
2322
+ 입니다. (즉, 하나의 단일 애플리케이션 파일과 `./public` 및 `./views` 디렉터리,
2323
+ 로깅, 예외 상세 페이지 등등). 이 곳에서 `Sinatra::Base`가 필요합니다.
2324
+
2325
+ ``` ruby
2326
+ require 'sinatra/base'
2327
+
2328
+ class MyApp < Sinatra::Base
2329
+ set :sessions, true
2330
+ set :foo, 'bar'
2331
+
2332
+ get '/' do
2333
+ 'Hello world!'
2334
+ end
2335
+ end
2336
+ ```
2337
+
2338
+ `Sinatra::Base` 서브클래스에서 사용가능한 메서드들은 톱레벨 DSL로 접근 가능한 것들과
2339
+ 동일합니다. 대부분의 톱레벨 앱들은 다음 두 가지만 수정하면 `Sinatra::Base` 컴포넌트로
2340
+ 변환 가능합니다.
2341
+
2342
+ * 파일은 `sinatra`가 아닌 `sinatra/base`를 require해야 합니다.
2343
+ 그렇지 않으면 모든 Sinatra의 DSL 메서드들이 메인 네임스페이스에 불러지게
2344
+ 됩니다.
2345
+ * 앱의 라우터, 예외 핸들러, 필터, 옵션은 `Sinatra::Base`의 서브클래스에 두어야
2346
+ 합니다.
2347
+
2348
+ `Sinatra::Base`는 백지상태(blank slate)입니다. 빌트인 서버를 비롯한 대부분의 옵션들이
2349
+ 기본값으로 꺼져 있습니다. 가능한 옵션들과 그 작동에 대한 상세는 [옵션과
2350
+ 설정](http://sinatra.github.com/configuration.html)을 참조하세요.
2351
+
2352
+ ### 모듈(Modular) vs. 전통적 방식(Classic Style)
2353
+
2354
+ 일반적인 믿음과는 반대로, 전통적 방식에 잘못된 부분은 없습니다. 여러분 애플리케이션에
2355
+ 맞다면, 모듈 애플리케이션으로 전환할 필요는 없습니다.
2356
+
2357
+ 모듈 방식이 아닌 전통적 방식을 사용할 경우 생기는 주된 단점은 루비 프로세스 당
2358
+ 하나의 Sinatra 애플리케이션만 사용할 수 있다는 점입니다. 만약 하나 이상을 사용할
2359
+ 계획이라면 모듈 방식으로 전환하세요. 모듈 방식과 전통적 방식을 섞어쓰지 못할
2360
+ 이유는 없습니다.
2361
+
2362
+ 방식을 전환할 경우에는, 기본값 설정의 미묘한 차이에 유의해야 합니다.
2363
+
2364
+ <table>
2365
+ <tr>
2366
+ <th>설정</th>
2367
+ <th>전통적 방식</th>
2368
+ <th>모듈</th>
2369
+ </tr>
2370
+ <tr>
2371
+ <td>app_file</td>
2372
+ <td>sinatra를 로딩하는 파일</td>
2373
+ <td>Sinatra::Base를 서브클래싱한 파일</td>
2374
+ </tr>
2375
+ <tr>
2376
+ <td>run</td>
2377
+ <td>$0 == app_file</td>
2378
+ <td>false</td>
2379
+ </tr>
2380
+ <tr>
2381
+ <td>logging</td>
2382
+ <td> true</td>
2383
+ <td>false</td>
2384
+ </tr>
2385
+ <tr>
2386
+ <td>method_override</td>
2387
+ <td>true</td>
2388
+ <td>false</td>
2389
+ </tr>
2390
+ <tr>
2391
+ <td>inline_templates</td>
2392
+ <td>true</td>
2393
+ <td>false</td>
2394
+ </tr>
2395
+ <tr>
2396
+ <td>static</td>
2397
+ <td>true</td>
2398
+ <td>false</td>
2399
+ </tr>
2400
+ </table>
2401
+
2402
+ ### 모듈 애플리케이션(Modular Application) 제공하기
2403
+
2404
+ 모듈 앱을 시작하는 두 가지 일반적인 옵션이 있습니다.
2405
+ `run!`으로 능동적으로 시작하는 방법은 이렇습니다.
2406
+
2407
+ ``` ruby
2408
+ # my_app.rb
2409
+ require 'sinatra/base'
2410
+
2411
+ class MyApp < Sinatra::Base
2412
+ # ... 여기에 앱 코드가 온다 ...
2413
+
2414
+ # 루비 파일이 직접 실행될 경우에 서버를 시작
2415
+ run! if app_file == $0
2416
+ end
2417
+ ```
2418
+
2419
+ 이렇게 시작할 수도 있습니다.
2420
+
2421
+ ``` shell
2422
+ ruby my_app.rb
2423
+ ```
2424
+
2425
+ `config.ru`와 함께 사용할수도 있습니다. 이 경우는 어떠한 Rack 핸들러도 사용할 수 있도록
2426
+ 허용 합다.
2427
+
2428
+ ``` ruby
2429
+ # config.ru
2430
+ require './my_app'
2431
+ run MyApp
2432
+ ```
2433
+
2434
+ 실행은 이렇게 합니다.
2435
+
2436
+ ``` shell
2437
+ rackup -p 4567
2438
+ ```
2439
+
2440
+ ### config.ru로 전통적 방식의 애플리케이션 사용하기
2441
+
2442
+ 앱 파일을 다음과 같이 작성합니다.
2443
+
2444
+ ``` ruby
2445
+ # app.rb
2446
+ require 'sinatra'
2447
+
2448
+ get '/' do
2449
+ 'Hello world!'
2450
+ end
2451
+ ```
2452
+
2453
+ 대응하는 `config.ru`는 다음과 같이 작성합니다.
2454
+
2455
+ ``` ruby
2456
+ require './app'
2457
+ run Sinatra::Application
2458
+ ```
2459
+
2460
+ ### 언제 config.ru를 사용할까?
2461
+
2462
+ `config.ru`는 다음 경우에 권장 됩니다.
2463
+
2464
+ * 다른 Rack 핸들러(Passenger, Unicorn, Heroku, ...)로 배포하고자 할 때.
2465
+ * 하나 이상의 `Sinatra::Base` 서브클래스를 사용하고자 할 때.
2466
+ * Sinatra를 최종점(endpoint)이 아니라, 오로지 미들웨어로만 사용하고자 할 때.
2467
+
2468
+ **모듈 방식으로 전환했다는 이유만으로 `config.ru`로 전환할 필요는 없으며,
2469
+ 또한 `config.ru`를 사용한다고 해서 모듈 방식을 사용해야 하는 것도 아닙니다.**
2470
+
2471
+ ### Sinatra를 미들웨어로 사용하기
2472
+
2473
+ Sinatra에서 다른 Rack 미들웨어를 사용할 수 있을 뿐 아니라,
2474
+ 어떤 Sinatra 애플리케이션에서도 순차로 어떠한 Rack 종착점 앞에 미들웨어로
2475
+ 추가될 수 있습니다. 이 종착점은 다른 Sinatra 애플리케이션이 될 수도 있고,
2476
+ 또는 Rack 기반의 어떠한 애플리케이션(Rails/Ramaze/Camping/...)이 될 수도
2477
+ 있습니다.
2478
+
2479
+ ``` ruby
2480
+ require 'sinatra/base'
2481
+
2482
+ class LoginScreen < Sinatra::Base
2483
+ enable :sessions
2484
+
2485
+ get('/login') { haml :login }
2486
+
2487
+ post('/login') do
2488
+ if params[:name] == 'admin' && params[:password] == 'admin'
2489
+ session['user_name'] = params[:name]
2490
+ else
2491
+ redirect '/login'
2492
+ end
2493
+ end
2494
+ end
2495
+
2496
+ class MyApp < Sinatra::Base
2497
+ # 미들웨어는 사전 필터보다 앞서 실행됨
2498
+ use LoginScreen
2499
+
2500
+ before do
2501
+ unless session['user_name']
2502
+ halt "접근 거부됨, <a href='/login'>로그인</a> 하세요."
2503
+ end
2504
+ end
2505
+
2506
+ get('/') { "Hello #{session['user_name']}." }
2507
+ end
2508
+ ```
2509
+
2510
+ ### 동적인 애플리케이션 생성(Dynamic Application Creation)
2511
+
2512
+ 어떤 상수에 할당하지 않고 런타임에서 새 애플리케이션들을 생성하려면,
2513
+ `Sinatra.new`를 쓰면 됩니다.
2514
+
2515
+ ``` ruby
2516
+ require 'sinatra/base'
2517
+ my_app = Sinatra.new { get('/') { "hi" } }
2518
+ my_app.run!
2519
+ ```
2520
+
2521
+ 선택적 인자로 상속할 애플리케이션을 받을 수 있습니다.
2522
+
2523
+ ``` ruby
2524
+ # config.ru
2525
+ require 'sinatra/base'
2526
+
2527
+ controller = Sinatra.new do
2528
+ enable :logging
2529
+ helpers MyHelpers
2530
+ end
2531
+
2532
+ map('/a') do
2533
+ run Sinatra.new(controller) { get('/') { 'a' } }
2534
+ end
2535
+
2536
+ map('/b') do
2537
+ run Sinatra.new(controller) { get('/') { 'b' } }
2538
+ end
2539
+ ```
2540
+
2541
+ 이 방법은 Sintra 익스텐션을 테스팅하거나 또는 여러분의 라이브러리에서 Sinatra를
2542
+ 사용할 경우에 특히 유용합니다.
2543
+
2544
+ 이 방법은 Sinatra를 미들웨어로 사용하는 것을 아주 쉽게 만들어 주기도 합니다.
2545
+
2546
+ ``` ruby
2547
+ require 'sinatra/base'
2548
+
2549
+ use Sinatra do
2550
+ get('/') { ... }
2551
+ end
2552
+
2553
+ run RailsProject::Application
2554
+ ```
2555
+
2556
+ ## 범위(Scopes)와 바인딩(Binding)
2557
+
2558
+ 현재 어느 범위에 있느냐가 어떤 메서드와 변수를 사용할 수 있는지를 결정합니다.
2559
+
2560
+ ### 애플리케이션/클래스 범위
2561
+
2562
+ 모든 Sinatra 애플리케이션은 `Sinatra::Base`의 서브클래스에 대응됩니다.
2563
+ 만약 톱레벨 DSL (`require 'sinatra'`)을 사용한다면, 이 클래스는
2564
+ `Sinatra::Application`이며, 그렇지 않을 경우라면 여러분이 명시적으로 생성한
2565
+ 그 서브클래스가 됩니다. 클래스 레벨에서는 `get` 이나 `before` 같은 메서드들을
2566
+ 가지나, `request` 객체나 `session` 에는 접근할 수 없습니다. 왜냐면 모든 요청에
2567
+ 대해 애플리케이션 클래스는 오직 하나이기 때문입니다.
2568
+
2569
+ `set`으로 생성한 옵션들은 클래스 레벨의 메서드들입니다.
2570
+
2571
+ ``` ruby
2572
+ class MyApp < Sinatra::Base
2573
+ # 저기요, 저는 애플리케이션 범위에 있다구요!
2574
+ set :foo, 42
2575
+ foo # => 42
2576
+
2577
+ get '/foo' do
2578
+ # 저기요, 전 이제 더 이상 애플리케이션 범위 속에 있지 않아요!
2579
+ end
2580
+ end
2581
+ ```
2582
+
2583
+ 애플리케이션 범위에는 이런 것들이 있습니다.
2584
+
2585
+ * 애플리케이션 클래스 본문
2586
+ * 확장으로 정의된 메서드
2587
+ * `helpers`로 전달된 블록
2588
+ * `set`의 값으로 사용된 Procs/blocks
2589
+ * `Sinatra.new`로 전달된 블록
2590
+
2591
+ 범위 객체 (클래스)는 다음과 같이 접근할 수 있습니다.
2592
+
2593
+ * configure 블록으로 전달된 객체를 통해(`configure { |c| ... }`)
2594
+ * 요청 범위 내에서 `settings`
2595
+
2596
+ ### 요청/인스턴스 범위
2597
+
2598
+ 매 요청마다, 애플리케이션 클래스의 새 인스턴스가 생성되고 모든 핸들러 블록은
2599
+ 그 범위 내에서 실행됩니다. 범위 내에서 여러분은 `request` 와 `session` 객체에
2600
+ 접근하거나 `erb` 나 `haml` 같은 렌더링 메서드를 호출할 수 있습니다. 요청 범위
2601
+ 내에서 `settings` 헬퍼를 통해 애플리케이션 범위에 접근 가능합니다.
2602
+
2603
+ ``` ruby
2604
+ class MyApp < Sinatra::Base
2605
+ # 이봐요, 전 애플리케이션 범위에 있다구요!
2606
+ get '/define_route/:name' do
2607
+ # '/define_route/:name'의 요청 범위
2608
+ @value = 42
2609
+
2610
+ settings.get("/#{params[:name]}") do
2611
+ # "/#{params[:name]}"의 요청 범위
2612
+ @value # => nil (동일한 요청이 아님)
2613
+ end
2614
+
2615
+ "라우터가 정의됨!"
2616
+ end
2617
+ end
2618
+ ```
2619
+
2620
+ 요청 범위에는 이런 것들이 있습니다.
2621
+
2622
+ * get/head/post/put/delete/options 블록
2623
+ * before/after 필터
2624
+ * 헬퍼(helper) 메서드
2625
+ * 템플릿/뷰
2626
+
2627
+ ### 위임 범위(Delegation Scope)
2628
+
2629
+ 위임 범위(delegation scope)는 메서드를 단순히 클래스 범위로 보냅니다(forward).
2630
+ 하지만 클래스 바인딩을 갖지 않기에 완전히 클래스 범위처럼 동작하지는 않습니다.
2631
+ 오직 명시적으로 위임(delegation) 표시된 메서드들만 사용 가능하고,
2632
+ 또한 클래스 범위와 변수/상태를 공유하지 않습니다 (유의: `self`가 다름).
2633
+ `Sinatra::Delegator.delegate :method_name`을 호출하여 메서드 위임을 명시적으로
2634
+ 추가할 수 있습니다.
2635
+
2636
+ 위임 범위에는 이런 것들이 있습니다.
2637
+
2638
+ * 톱레벨 바인딩, `require "sinatra"`를 한 경우
2639
+ * `Sinatra::Delegator` 믹스인으로 확장된 객체
2640
+
2641
+ 직접 코드를 살펴보길 바랍니다.
2642
+ [Sinatra::Delegator 믹스인](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/base.rb#L1609-1633)
2643
+ 은 [메인 객체를 확장한 것](https://github.com/sinatra/sinatra/blob/ca06364/lib/sinatra/main.rb#L28-30) 입니다.
2644
+
2645
+ ## 명령행(Command Line)
2646
+
2647
+ Sinatra 애플리케이션은 직접 실행할 수 있습니다.
2648
+
2649
+ ``` shell
2650
+ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER]
2651
+ ```
2652
+
2653
+ 옵션들은 다음과 같습니다.
2654
+
2655
+ ```
2656
+ -h # 도움말
2657
+ -p # 포트 설정 (기본값은 4567)
2658
+ -o # 호스트 설정 (기본값은 0.0.0.0)
2659
+ -e # 환경 설정 (기본값은 development)
2660
+ -s # rack 서버/핸들러 지정 (기본값은 thin)
2661
+ -x # mutex 잠금 켜기 (기본값은 off)
2662
+ ```
2663
+
2664
+ ## 요구사항(Requirement)
2665
+
2666
+ 다음의 루비 버전은 공식적으로 지원됩니다.
2667
+ <dl>
2668
+ <dt> Ruby 1.8.7 </dt>
2669
+ <dd>
2670
+ 1.8.7은 완전하게 지원되지만, 꼭 그래야할 특별한 이유가 없다면,
2671
+ 1.9.2로 업그레이드하거나 또는 JRuby나 Rubinius로 전환할 것을 권장합니다.
2672
+ 1.8.7에 대한 지원은 Sinatra 2.0 이전에는 중단되지 않을 것입니다.
2673
+ Ruby 1.8.6은 더이상 지원하지 않습니다.
2674
+ </dd>
2675
+
2676
+ <dt> Ruby 1.9.2 </dt>
2677
+ <dd>
2678
+ 1.9.2는 완전하게 지원됩니다. 1.9.2p0은, Sinatra를 실행했을 때 세그먼트 오류가
2679
+ 발생할수 있으므로 쓰지 마세요. 공식 지원은 Sinatra 1.5 이전에는 중단되지 않을
2680
+ 것입니다.
2681
+ </dd>
2682
+
2683
+ <dt> Ruby 1.9.3 </dt>
2684
+ <dd>
2685
+ 1.9.3은 완전하게 지원되고 권장합니다. 이전 버전에서 1.9.3으로 전환할 경우 모든
2686
+ 세션이 무효화되므로 주의하세요. 1.9.3에 대한 지원은 Sinatra 2.0 이전에는
2687
+ 중단되지 않을 것입니다.
2688
+ </dd>
2689
+
2690
+ <dt>Ruby 2.0.0</dt>
2691
+ <dd>
2692
+ 2.0.0은 완전하게 지원되고 권장합니다. 현재 공식 지원 중지 계획은 없습니다.
2693
+ </dd>
2694
+
2695
+ <dt>Rubinius</dt>
2696
+ <dd>
2697
+ Rubinius는 공식적으로 지원됩니다. (Rubinius >= 2.x)
2698
+ <tt>gem install puma</tt>를 권장합니다.
2699
+ </dd>
2700
+
2701
+ <dt>JRuby</dt>
2702
+ <dd>
2703
+ JRuby의 마지막 안정판은 공식적으로 지원됩니다. C 확장을 JRuby와 사용하는
2704
+ 것은 권장되지 않습니다.
2705
+ <tt>gem install trinidad</tt>를 권장합니다.
2706
+ </dd>
2707
+ </dl>
2708
+
2709
+ 새로 나오는 루비 버전도 주시하고 있습니다.
2710
+
2711
+ 다음 루비 구현체들은 공식적으로 지원하지 않지만
2712
+ 여전히 Sinatra를 실행할 수 있는 것으로 알려져 있습니다.
2713
+
2714
+ * JRuby와 Rubinius 예전 버전
2715
+ * Ruby Enterprise Edition
2716
+ * MacRuby, Maglev, IronRuby
2717
+ * Ruby 1.9.0 및 1.9.1 (이 버전들은 사용하지 말 것을 권합니다)
2718
+
2719
+ 공식적으로 지원하지 않는다는 것의 의미는 무언가가 그 플랫폼에서만 잘못되고
2720
+ 지원되는 플랫폼에서는 그러지 않을 경우, 우리의 문제가 아니라 그 플랫폼의 문제로
2721
+ 간주한다는 뜻입니다.
2722
+
2723
+ 또한 우리는 CI를 ruby-head (곧 나올 2.1.0) 브랜치에 맞춰 실행하지만,
2724
+ 계속해서 변하고 있기 때문에 아무 것도 보장할 수는 없습니다.
2725
+ 2.1.0가 완전히 지원되길 기대합시다.
2726
+
2727
+ Sinatra는 선택한 루비 구현체가 지원하는 어떠한 운영체제에서도 작동해야
2728
+ 합니다.
2729
+
2730
+ 현재 Cardinal, SmallRuby, BlueRuby 또는 1.8.7 이전의 루비 버전에서는
2731
+ Sinatra를 실행할 수 없을 것입니다.
2732
+
2733
+ ## 최신(The Bleeding Edge)
2734
+
2735
+ Sinatra의 가장 최근 코드를 사용하고자 한다면, 애플리케이션을 마스터 브랜치에 맞춰
2736
+ 실행하면 되므로 부담가지지 마세요. 하지만 덜 안정적일 것 입니다.
2737
+
2738
+ 주기적으로 사전배포(prerelease) 젬을 푸시하기 때문에, 최신 기능들을 얻기 위해
2739
+ 다음과 같이 할 수도 있습니다.
2740
+
2741
+ ``` shell
2742
+ gem install sinatra --pre
2743
+ ```
2744
+
2745
+ ### Bundler를 사용하여
2746
+
2747
+ 여러분 애플리케이션을 최신 Sinatra로 실행하고자 한다면,
2748
+ [Bundler](http://gembundler.com/)를 사용할 것을 권장합니다.
2749
+
2750
+ 우선, 아직 설치하지 않았다면 bundler를 설치합니다.
2751
+
2752
+ ``` shell
2753
+ gem install bundler
2754
+ ```
2755
+
2756
+ 그런 다음, 프로젝트 디렉터리에서, `Gemfile`을 만듭니다.
2757
+
2758
+ ``` ruby
2759
+ source 'https://rubygems.org'
2760
+ gem 'sinatra', :github => "sinatra/sinatra"
2761
+
2762
+ # 다른 의존관계들
2763
+ gem 'haml' # 예를 들어, haml을 사용한다면
2764
+ gem 'activerecord', '~> 3.0' # 아마도 ActiveRecord 3.x도 필요할 것
2765
+ ```
2766
+
2767
+ `Gemfile`안에 애플리케이션의 모든 의존성을 적어야 합니다.
2768
+ 하지만, Sinatra가 직접적인 의존관계에 있는 것들(Rack과 Tilt)은
2769
+ Bundler가 자동으로 찾아서 추가할 것입니다.
2770
+
2771
+ 이제 앱을 실행할 수 있습니다.
2772
+
2773
+ ``` shell
2774
+ bundle exec ruby myapp.rb
2775
+ ```
2776
+
2777
+ ### 직접 하기(Roll Your Own)
2778
+
2779
+ 로컬 클론(clone)을 생성한 다음 `$LOAD_PATH`에 `sinatra/lib` 디렉터리를 주고
2780
+ 여러분 앱을 실행합니다.
2781
+
2782
+ ``` shell
2783
+ cd myapp
2784
+ git clone git://github.com/sinatra/sinatra.git
2785
+ ruby -I sinatra/lib myapp.rb
2786
+ ```
2787
+
2788
+ 이후에 Sinatra 소스를 업데이트하려면 이렇게 하세요.
2789
+
2790
+ ``` shell
2791
+ cd myapp/sinatra
2792
+ git pull
2793
+ ```
2794
+
2795
+ ### 전역으로 설치(Install Globally)
2796
+
2797
+ 젬을 직접 빌드할 수 있습니다.
2798
+
2799
+ ``` shell
2800
+ git clone git://github.com/sinatra/sinatra.git
2801
+ cd sinatra
2802
+ rake sinatra.gemspec
2803
+ rake install
2804
+ ```
2805
+
2806
+ 만약 젬을 루트로 설치한다면, 마지막 단계는 다음과 같이 해야 합니다.
2807
+
2808
+ ``` shell
2809
+ sudo rake install
2810
+ ```
2811
+
2812
+ ## 버저닝(Versioning)
2813
+
2814
+ Sinatra는 [시맨틱 버저닝Semantic Versioning](http://semver.org/)
2815
+ [(번역)](http://surpreem.com/archives/380)의 SemVer,
2816
+ SemVerTag를 준수합니다.
2817
+
2818
+ ## 더 읽을 거리(Further Reading)
2819
+
2820
+ * [프로젝트 웹사이트](http://www.sinatrarb.com/) - 추가 문서들, 뉴스,
2821
+ 그리고 다른 리소스들에 대한 링크.
2822
+ * [기여하기](http://www.sinatrarb.com/contributing) - 버그를 찾았나요?
2823
+ 도움이 필요한가요? 패치를 하셨나요?
2824
+ * [이슈 트래커](http://github.com/sinatra/sinatra/issues)
2825
+ * [트위터](http://twitter.com/sinatra)
2826
+ * [메일링 리스트](http://groups.google.com/group/sinatrarb/topics)
2827
+ * IRC: [#sinatra](irc://chat.freenode.net/#sinatra) http://freenode.net
2828
+ * [Sinatra Book](http://sinatra-book.gittr.com) Cookbook 튜토리얼
2829
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) 커뮤니티가 만드는 레시피
2830
+ * http://rubydoc.info에 있는 [최종 릴리스](http://rubydoc.info/gems/sinatra)
2831
+ 또는 [current HEAD](http://rubydoc.info/github/sinatra/sinatra)에 대한 API 문서
2832
+ * [CI server](http://travis-ci.org/sinatra/sinatra)