sinatra-bundles 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/Rakefile +2 -1
  2. data/VERSION +1 -1
  3. data/lib/sinatra/bundles/bundle.rb +36 -0
  4. data/lib/sinatra/bundles/helpers.rb +22 -0
  5. data/lib/sinatra/bundles/javascript_bundle.rb +37 -0
  6. data/lib/sinatra/bundles/stylesheet_bundle.rb +36 -0
  7. data/lib/sinatra/bundles.rb +4 -114
  8. data/sinatra-bundles.gemspec +11 -58
  9. data/spec/app.rb +1 -1
  10. data/spec/production_app.rb +1 -1
  11. data/spec/public/javascripts/eval.js +5 -0
  12. data/spec/sinatra-bundles_spec.rb +10 -1
  13. data/spec/spec_helper.rb +5 -6
  14. metadata +17 -57
  15. data/vendor/cache/sinatra-0.10.1.gem +0 -0
  16. data/vendor/gems/sinatra-0.10.1/AUTHORS +0 -43
  17. data/vendor/gems/sinatra-0.10.1/CHANGES +0 -467
  18. data/vendor/gems/sinatra-0.10.1/LICENSE +0 -22
  19. data/vendor/gems/sinatra-0.10.1/README.jp.rdoc +0 -552
  20. data/vendor/gems/sinatra-0.10.1/README.rdoc +0 -622
  21. data/vendor/gems/sinatra-0.10.1/Rakefile +0 -129
  22. data/vendor/gems/sinatra-0.10.1/lib/sinatra/base.rb +0 -1143
  23. data/vendor/gems/sinatra-0.10.1/lib/sinatra/images/404.png +0 -0
  24. data/vendor/gems/sinatra-0.10.1/lib/sinatra/images/500.png +0 -0
  25. data/vendor/gems/sinatra-0.10.1/lib/sinatra/main.rb +0 -28
  26. data/vendor/gems/sinatra-0.10.1/lib/sinatra/showexceptions.rb +0 -303
  27. data/vendor/gems/sinatra-0.10.1/lib/sinatra/tilt.rb +0 -509
  28. data/vendor/gems/sinatra-0.10.1/lib/sinatra.rb +0 -7
  29. data/vendor/gems/sinatra-0.10.1/sinatra.gemspec +0 -86
  30. data/vendor/gems/sinatra-0.10.1/test/base_test.rb +0 -160
  31. data/vendor/gems/sinatra-0.10.1/test/builder_test.rb +0 -65
  32. data/vendor/gems/sinatra-0.10.1/test/contest.rb +0 -64
  33. data/vendor/gems/sinatra-0.10.1/test/erb_test.rb +0 -81
  34. data/vendor/gems/sinatra-0.10.1/test/erubis_test.rb +0 -82
  35. data/vendor/gems/sinatra-0.10.1/test/extensions_test.rb +0 -100
  36. data/vendor/gems/sinatra-0.10.1/test/filter_test.rb +0 -195
  37. data/vendor/gems/sinatra-0.10.1/test/haml_test.rb +0 -90
  38. data/vendor/gems/sinatra-0.10.1/test/helper.rb +0 -76
  39. data/vendor/gems/sinatra-0.10.1/test/helpers_test.rb +0 -573
  40. data/vendor/gems/sinatra-0.10.1/test/mapped_error_test.rb +0 -186
  41. data/vendor/gems/sinatra-0.10.1/test/middleware_test.rb +0 -68
  42. data/vendor/gems/sinatra-0.10.1/test/request_test.rb +0 -33
  43. data/vendor/gems/sinatra-0.10.1/test/response_test.rb +0 -42
  44. data/vendor/gems/sinatra-0.10.1/test/result_test.rb +0 -98
  45. data/vendor/gems/sinatra-0.10.1/test/route_added_hook_test.rb +0 -59
  46. data/vendor/gems/sinatra-0.10.1/test/routing_test.rb +0 -878
  47. data/vendor/gems/sinatra-0.10.1/test/sass_test.rb +0 -79
  48. data/vendor/gems/sinatra-0.10.1/test/server_test.rb +0 -47
  49. data/vendor/gems/sinatra-0.10.1/test/sinatra_test.rb +0 -13
  50. data/vendor/gems/sinatra-0.10.1/test/static_test.rb +0 -87
  51. data/vendor/gems/sinatra-0.10.1/test/templates_test.rb +0 -155
  52. data/vendor/gems/sinatra-0.10.1/test/views/error.builder +0 -3
  53. data/vendor/gems/sinatra-0.10.1/test/views/error.erb +0 -3
  54. data/vendor/gems/sinatra-0.10.1/test/views/error.erubis +0 -3
  55. data/vendor/gems/sinatra-0.10.1/test/views/error.haml +0 -3
  56. data/vendor/gems/sinatra-0.10.1/test/views/error.sass +0 -2
  57. data/vendor/gems/sinatra-0.10.1/test/views/foo/hello.test +0 -1
  58. data/vendor/gems/sinatra-0.10.1/test/views/hello.builder +0 -1
  59. data/vendor/gems/sinatra-0.10.1/test/views/hello.erb +0 -1
  60. data/vendor/gems/sinatra-0.10.1/test/views/hello.erubis +0 -1
  61. data/vendor/gems/sinatra-0.10.1/test/views/hello.haml +0 -1
  62. data/vendor/gems/sinatra-0.10.1/test/views/hello.sass +0 -2
  63. data/vendor/gems/sinatra-0.10.1/test/views/hello.test +0 -1
  64. data/vendor/gems/sinatra-0.10.1/test/views/layout2.builder +0 -3
  65. data/vendor/gems/sinatra-0.10.1/test/views/layout2.erb +0 -2
  66. data/vendor/gems/sinatra-0.10.1/test/views/layout2.erubis +0 -2
  67. data/vendor/gems/sinatra-0.10.1/test/views/layout2.haml +0 -2
  68. data/vendor/gems/sinatra-0.10.1/test/views/layout2.test +0 -1
  69. data/vendor/specifications/sinatra-0.10.1.gemspec +0 -40
@@ -1,622 +0,0 @@
1
- = Sinatra
2
-
3
- Sinatra is a DSL for quickly creating web applications in Ruby with minimal
4
- effort:
5
-
6
- # myapp.rb
7
- require 'rubygems'
8
- require 'sinatra'
9
- get '/' do
10
- 'Hello world!'
11
- end
12
-
13
- Install the gem and run with:
14
-
15
- sudo gem install sinatra
16
- ruby myapp.rb
17
-
18
- View at: http://localhost:4567
19
-
20
- == Routes
21
-
22
- In Sinatra, a route is an HTTP method paired with an URL matching pattern.
23
- Each route is associated with a block:
24
-
25
- get '/' do
26
- .. show something ..
27
- end
28
-
29
- post '/' do
30
- .. create something ..
31
- end
32
-
33
- put '/' do
34
- .. update something ..
35
- end
36
-
37
- delete '/' do
38
- .. annihilate something ..
39
- end
40
-
41
- Routes are matched in the order they are defined. The first route that
42
- matches the request is invoked.
43
-
44
- Route patterns may include named parameters, accessible via the
45
- <tt>params</tt> hash:
46
-
47
- get '/hello/:name' do
48
- # matches "GET /hello/foo" and "GET /hello/bar"
49
- # params[:name] is 'foo' or 'bar'
50
- "Hello #{params[:name]}!"
51
- end
52
-
53
- You can also access named parameters via block parameters:
54
-
55
- get '/hello/:name' do |n|
56
- "Hello #{n}!"
57
- end
58
-
59
- Route patterns may also include splat (or wildcard) parameters, accessible
60
- via the <tt>params[:splat]</tt> array.
61
-
62
- get '/say/*/to/*' do
63
- # matches /say/hello/to/world
64
- params[:splat] # => ["hello", "world"]
65
- end
66
-
67
- get '/download/*.*' do
68
- # matches /download/path/to/file.xml
69
- params[:splat] # => ["path/to/file", "xml"]
70
- end
71
-
72
- Route matching with Regular Expressions:
73
-
74
- get %r{/hello/([\w]+)} do
75
- "Hello, #{params[:captures].first}!"
76
- end
77
-
78
- Or with a block parameter:
79
-
80
- get %r{/hello/([\w]+)} do |c|
81
- "Hello, #{c}!"
82
- end
83
-
84
- Routes may include a variety of matching conditions, such as the user agent:
85
-
86
- get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
87
- "You're using Songbird version #{params[:agent][0]}"
88
- end
89
-
90
- get '/foo' do
91
- # Matches non-songbird browsers
92
- end
93
-
94
- == Static Files
95
-
96
- Static files are served from the <tt>./public</tt> directory. You can specify
97
- a different location by setting the <tt>:public</tt> option:
98
-
99
- set :public, File.dirname(__FILE__) + '/static'
100
-
101
- Note that the public directory name is not included in the URL. A file
102
- <tt>./public/css/style.css</tt> is made available as
103
- <tt>http://example.com/css/style.css</tt>.
104
-
105
- == Views / Templates
106
-
107
- Templates are assumed to be located directly under the <tt>./views</tt>
108
- directory. To use a different views directory:
109
-
110
- set :views, File.dirname(__FILE__) + '/templates'
111
-
112
- One important thing to remember is that you always have to reference
113
- templates with symbols, even if they're in a subdirectory (in this
114
- case use <tt>:'subdir/template'</tt>). Rendering methods will render
115
- any strings passed to them directly.
116
-
117
- === Haml Templates
118
-
119
- The haml gem/library is required to render HAML templates:
120
-
121
- ## You'll need to require haml in your app
122
- require 'haml'
123
-
124
- get '/' do
125
- haml :index
126
- end
127
-
128
- Renders <tt>./views/index.haml</tt>.
129
-
130
- {Haml's options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html]
131
- can be set globally through Sinatra's configurations,
132
- see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
133
- and overridden on an individual basis.
134
-
135
- set :haml, {:format => :html5 } # default Haml format is :xhtml
136
-
137
- get '/' do
138
- haml :index, :haml_options => {:format => :html4 } # overridden
139
- end
140
-
141
-
142
- === Erb Templates
143
-
144
- ## You'll need to require erb in your app
145
- require 'erb'
146
-
147
- get '/' do
148
- erb :index
149
- end
150
-
151
- Renders <tt>./views/index.erb</tt>
152
-
153
- === Erubis
154
-
155
- The erubis gem/library is required to render builder templates:
156
-
157
- ## You'll need to require erubis in your app
158
- require 'erubis'
159
-
160
- get '/' do
161
- erubis :index
162
- end
163
-
164
- Renders <tt>./views/index.erubis</tt>
165
-
166
- === Builder Templates
167
-
168
- The builder gem/library is required to render builder templates:
169
-
170
- ## You'll need to require builder in your app
171
- require 'builder'
172
-
173
- get '/' do
174
- content_type 'application/xml', :charset => 'utf-8'
175
- builder :index
176
- end
177
-
178
- Renders <tt>./views/index.builder</tt>.
179
-
180
- === Sass Templates
181
-
182
- The sass gem/library is required to render Sass templates:
183
-
184
- ## You'll need to require haml or sass in your app
185
- require 'sass'
186
-
187
- get '/stylesheet.css' do
188
- content_type 'text/css', :charset => 'utf-8'
189
- sass :stylesheet
190
- end
191
-
192
- Renders <tt>./views/stylesheet.sass</tt>.
193
-
194
- {Sass' options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html]
195
- can be set globally through Sinatra's configurations,
196
- see {Options and Configurations}[http://www.sinatrarb.com/configuration.html],
197
- and overridden on an individual basis.
198
-
199
- set :sass, {:style => :compact } # default Sass style is :nested
200
-
201
- get '/stylesheet.css' do
202
- content_type 'text/css', :charset => 'utf-8'
203
- sass :stylesheet, :style => :expanded # overridden
204
- end
205
-
206
- === Inline Templates
207
-
208
- get '/' do
209
- haml '%div.title Hello World'
210
- end
211
-
212
- Renders the inlined template string.
213
-
214
- === Accessing Variables in Templates
215
-
216
- Templates are evaluated within the same context as route handlers. Instance
217
- variables set in route handlers are direcly accessible by templates:
218
-
219
- get '/:id' do
220
- @foo = Foo.find(params[:id])
221
- haml '%h1= @foo.name'
222
- end
223
-
224
- Or, specify an explicit Hash of local variables:
225
-
226
- get '/:id' do
227
- foo = Foo.find(params[:id])
228
- haml '%h1= foo.name', :locals => { :foo => foo }
229
- end
230
-
231
- This is typically used when rendering templates as partials from within
232
- other templates.
233
-
234
- === Inline Templates
235
-
236
- Templates may be defined at the end of the source file:
237
-
238
- require 'rubygems'
239
- require 'sinatra'
240
-
241
- get '/' do
242
- haml :index
243
- end
244
-
245
- __END__
246
-
247
- @@ layout
248
- %html
249
- = yield
250
-
251
- @@ index
252
- %div.title Hello world!!!!!
253
-
254
- NOTE: Inline templates defined in the source file that requires sinatra
255
- are automatically loaded. Call `enable :inline_templates` explicitly if you
256
- have inline templates in other source files.
257
-
258
- === Named Templates
259
-
260
- Templates may also be defined using the top-level <tt>template</tt> method:
261
-
262
- template :layout do
263
- "%html\n =yield\n"
264
- end
265
-
266
- template :index do
267
- '%div.title Hello World!'
268
- end
269
-
270
- get '/' do
271
- haml :index
272
- end
273
-
274
- If a template named "layout" exists, it will be used each time a template
275
- is rendered. You can disable layouts by passing <tt>:layout => false</tt>.
276
-
277
- get '/' do
278
- haml :index, :layout => !request.xhr?
279
- end
280
-
281
- == Helpers
282
-
283
- Use the top-level <tt>helpers</tt> method to define helper methods for use in
284
- route handlers and templates:
285
-
286
- helpers do
287
- def bar(name)
288
- "#{name}bar"
289
- end
290
- end
291
-
292
- get '/:name' do
293
- bar(params[:name])
294
- end
295
-
296
- == Filters
297
-
298
- Before filters are evaluated before each request within the context of the
299
- request and can modify the request and response. Instance variables set in
300
- filters are accessible by routes and templates:
301
-
302
- before do
303
- @note = 'Hi!'
304
- request.path_info = '/foo/bar/baz'
305
- end
306
-
307
- get '/foo/*' do
308
- @note #=> 'Hi!'
309
- params[:splat] #=> 'bar/baz'
310
- end
311
-
312
- After filter are evaluated after each request within the context of the
313
- request and can also modify the request and response. Instance variables
314
- set in before filters and routes are accessible by after filters:
315
-
316
- after do
317
- puts response.status
318
- end
319
-
320
- == Halting
321
-
322
- To immediately stop a request within a filter or route use:
323
-
324
- halt
325
-
326
- You can also specify the status when halting ...
327
-
328
- halt 410
329
-
330
- Or the body ...
331
-
332
- halt 'this will be the body'
333
-
334
- Or both ...
335
-
336
- halt 401, 'go away!'
337
-
338
- With headers ...
339
-
340
- halt 402, {'Content-Type' => 'text/plain'}, 'revenge'
341
-
342
- == Passing
343
-
344
- A route can punt processing to the next matching route using <tt>pass</tt>:
345
-
346
- get '/guess/:who' do
347
- pass unless params[:who] == 'Frank'
348
- 'You got me!'
349
- end
350
-
351
- get '/guess/*' do
352
- 'You missed!'
353
- end
354
-
355
- The route block is immediately exited and control continues with the next
356
- matching route. If no matching route is found, a 404 is returned.
357
-
358
- == Configuration
359
-
360
- Run once, at startup, in any environment:
361
-
362
- configure do
363
- ...
364
- end
365
-
366
- Run only when the environment (RACK_ENV environment variable) is set to
367
- <tt>:production</tt>:
368
-
369
- configure :production do
370
- ...
371
- end
372
-
373
- Run when the environment is set to either <tt>:production</tt> or
374
- <tt>:test</tt>:
375
-
376
- configure :production, :test do
377
- ...
378
- end
379
-
380
- == Error handling
381
-
382
- Error handlers run within the same context as routes and before filters, which
383
- means you get all the goodies it has to offer, like <tt>haml</tt>, <tt>erb</tt>,
384
- <tt>halt</tt>, etc.
385
-
386
- === Not Found
387
-
388
- When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
389
- code is 404, the <tt>not_found</tt> handler is invoked:
390
-
391
- not_found do
392
- 'This is nowhere to be found'
393
- end
394
-
395
- === Error
396
-
397
- The +error+ handler is invoked any time an exception is raised from a route
398
- block or a filter. The exception object can be obtained from the
399
- <tt>sinatra.error</tt> Rack variable:
400
-
401
- error do
402
- 'Sorry there was a nasty error - ' + env['sinatra.error'].name
403
- end
404
-
405
- Custom errors:
406
-
407
- error MyCustomError do
408
- 'So what happened was...' + request.env['sinatra.error'].message
409
- end
410
-
411
- Then, if this happens:
412
-
413
- get '/' do
414
- raise MyCustomError, 'something bad'
415
- end
416
-
417
- You get this:
418
-
419
- So what happened was... something bad
420
-
421
- Alternatively, you can install error handler for a status code:
422
-
423
- error 403 do
424
- 'Access forbidden'
425
- end
426
-
427
- get '/secret' do
428
- 403
429
- end
430
-
431
- Or a range:
432
-
433
- error 400..510 do
434
- 'Boom'
435
- end
436
-
437
- Sinatra installs special <tt>not_found</tt> and <tt>error</tt> handlers when
438
- running under the development environment.
439
-
440
- == Mime types
441
-
442
- When using <tt>send_file</tt> or static files you may have mime types Sinatra
443
- doesn't understand. Use +mime_type+ to register them by file extension:
444
-
445
- mime_type :foo, 'text/foo'
446
-
447
- You can also use it with the +content_type+ helper:
448
-
449
- content_type :foo
450
-
451
- == Rack Middleware
452
-
453
- Sinatra rides on Rack[http://rack.rubyforge.org/], a minimal standard
454
- interface for Ruby web frameworks. One of Rack's most interesting capabilities
455
- for application developers is support for "middleware" -- components that sit
456
- between the server and your application monitoring and/or manipulating the
457
- HTTP request/response to provide various types of common functionality.
458
-
459
- Sinatra makes building Rack middleware pipelines a cinch via a top-level
460
- +use+ method:
461
-
462
- require 'sinatra'
463
- require 'my_custom_middleware'
464
-
465
- use Rack::Lint
466
- use MyCustomMiddleware
467
-
468
- get '/hello' do
469
- 'Hello World'
470
- end
471
-
472
- The semantics of +use+ are identical to those defined for the
473
- Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
474
- (most frequently used from rackup files). For example, the +use+ method
475
- accepts multiple/variable args as well as blocks:
476
-
477
- use Rack::Auth::Basic do |username, password|
478
- username == 'admin' && password == 'secret'
479
- end
480
-
481
- Rack is distributed with a variety of standard middleware for logging,
482
- debugging, URL routing, authentication, and session handling. Sinatra uses
483
- many of of these components automatically based on configuration so you
484
- typically don't have to +use+ them explicitly.
485
-
486
- == Testing
487
-
488
- Sinatra tests can be written using any Rack-based testing library
489
- or framework. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] is
490
- recommended:
491
-
492
- require 'my_sinatra_app'
493
- require 'rack/test'
494
-
495
- class MyAppTest < Test::Unit::TestCase
496
- include Rack::Test::Methods
497
-
498
- def app
499
- Sinatra::Application
500
- end
501
-
502
- def test_my_default
503
- get '/'
504
- assert_equal 'Hello World!', last_response.body
505
- end
506
-
507
- def test_with_params
508
- get '/meet', :name => 'Frank'
509
- assert_equal 'Hello Frank!', last_response.body
510
- end
511
-
512
- def test_with_rack_env
513
- get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
514
- assert_equal "You're using Songbird!", last_response.body
515
- end
516
- end
517
-
518
- NOTE: The built-in Sinatra::Test module and Sinatra::TestHarness class
519
- are deprecated as of the 0.9.2 release.
520
-
521
- == Sinatra::Base - Middleware, Libraries, and Modular Apps
522
-
523
- Defining your app at the top-level works well for micro-apps but has
524
- considerable drawbacks when building reuseable components such as Rack
525
- middleware, Rails metal, simple libraries with a server component, or
526
- even Sinatra extensions. The top-level DSL pollutes the Object namespace
527
- and assumes a micro-app style configuration (e.g., a single application
528
- file, ./public and ./views directories, logging, exception detail page,
529
- etc.). That's where Sinatra::Base comes into play:
530
-
531
- require 'sinatra/base'
532
-
533
- class MyApp < Sinatra::Base
534
- set :sessions, true
535
- set :foo, 'bar'
536
-
537
- get '/' do
538
- 'Hello world!'
539
- end
540
- end
541
-
542
- The MyApp class is an independent Rack component that can act as
543
- Rack middleware, a Rack application, or Rails metal. You can +use+ or
544
- +run+ this class from a rackup +config.ru+ file; or, control a server
545
- component shipped as a library:
546
-
547
- MyApp.run! :host => 'localhost', :port => 9090
548
-
549
- The methods available to Sinatra::Base subclasses are exactly as those
550
- available via the top-level DSL. Most top-level apps can be converted to
551
- Sinatra::Base components with two modifications:
552
-
553
- * Your file should require +sinatra/base+ instead of +sinatra+;
554
- otherwise, all of Sinatra's DSL methods are imported into the main
555
- namespace.
556
- * Put your app's routes, error handlers, filters, and options in a subclass
557
- of Sinatra::Base.
558
-
559
- +Sinatra::Base+ is a blank slate. Most options are disabled by default,
560
- including the built-in server. See {Options and Configuration}[http://sinatra.github.com/configuration.html]
561
- for details on available options and their behavior.
562
-
563
- SIDEBAR: Sinatra's top-level DSL is implemented using a simple delegation
564
- system. The +Sinatra::Application+ class -- a special subclass of
565
- Sinatra::Base -- receives all :get, :put, :post, :delete, :before,
566
- :error, :not_found, :configure, and :set messages sent to the
567
- top-level. Have a look at the code for yourself: here's the
568
- {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064]
569
- being {included into the main namespace}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25].
570
-
571
- == Command line
572
-
573
- Sinatra applications can be run directly:
574
-
575
- ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
576
-
577
- Options are:
578
-
579
- -h # help
580
- -p # set the port (default is 4567)
581
- -h # set the host (default is 0.0.0.0)
582
- -e # set the environment (default is development)
583
- -s # specify rack server/handler (default is thin)
584
- -x # turn on the mutex lock (default is off)
585
-
586
- == The Bleeding Edge
587
-
588
- If you would like to use Sinatra's latest bleeding code, create a local
589
- clone and run your app with the <tt>sinatra/lib</tt> directory on the
590
- <tt>LOAD_PATH</tt>:
591
-
592
- cd myapp
593
- git clone git://github.com/sinatra/sinatra.git
594
- ruby -Isinatra/lib myapp.rb
595
-
596
- Alternatively, you can add the <tt>sinatra/lib</tt> directory to the
597
- <tt>LOAD_PATH</tt> in your application:
598
-
599
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
600
- require 'rubygems'
601
- require 'sinatra'
602
-
603
- get '/about' do
604
- "I'm running version " + Sinatra::VERSION
605
- end
606
-
607
- To update the Sinatra sources in the future:
608
-
609
- cd myproject/sinatra
610
- git pull
611
-
612
- == More
613
-
614
- * {Project Website}[http://sinatra.github.com/] - Additional documentation,
615
- news, and links to other resources.
616
- * {Contributing}[http://sinatra.github.com/contributing.html] - Find a bug? Need
617
- help? Have a patch?
618
- * {Lighthouse}[http://sinatra.lighthouseapp.com] - Issue tracking and release
619
- planning.
620
- * {Twitter}[http://twitter.com/sinatra]
621
- * {Mailing List}[http://groups.google.com/group/sinatrarb]
622
- * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net