sinatra-sinatra 0.8.9

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 (80) hide show
  1. data/AUTHORS +40 -0
  2. data/CHANGES +174 -0
  3. data/LICENSE +22 -0
  4. data/README.rdoc +545 -0
  5. data/Rakefile +180 -0
  6. data/compat/app_test.rb +300 -0
  7. data/compat/application_test.rb +334 -0
  8. data/compat/builder_test.rb +101 -0
  9. data/compat/custom_error_test.rb +62 -0
  10. data/compat/erb_test.rb +136 -0
  11. data/compat/events_test.rb +78 -0
  12. data/compat/filter_test.rb +30 -0
  13. data/compat/haml_test.rb +233 -0
  14. data/compat/helper.rb +30 -0
  15. data/compat/mapped_error_test.rb +72 -0
  16. data/compat/pipeline_test.rb +71 -0
  17. data/compat/public/foo.xml +1 -0
  18. data/compat/sass_test.rb +57 -0
  19. data/compat/sessions_test.rb +39 -0
  20. data/compat/streaming_test.rb +121 -0
  21. data/compat/sym_params_test.rb +19 -0
  22. data/compat/template_test.rb +30 -0
  23. data/compat/use_in_file_templates_test.rb +47 -0
  24. data/compat/views/foo.builder +1 -0
  25. data/compat/views/foo.erb +1 -0
  26. data/compat/views/foo.haml +1 -0
  27. data/compat/views/foo.sass +2 -0
  28. data/compat/views/foo_layout.erb +2 -0
  29. data/compat/views/foo_layout.haml +2 -0
  30. data/compat/views/layout_test/foo.builder +1 -0
  31. data/compat/views/layout_test/foo.erb +1 -0
  32. data/compat/views/layout_test/foo.haml +1 -0
  33. data/compat/views/layout_test/foo.sass +2 -0
  34. data/compat/views/layout_test/layout.builder +3 -0
  35. data/compat/views/layout_test/layout.erb +1 -0
  36. data/compat/views/layout_test/layout.haml +1 -0
  37. data/compat/views/layout_test/layout.sass +2 -0
  38. data/compat/views/no_layout/no_layout.builder +1 -0
  39. data/compat/views/no_layout/no_layout.haml +1 -0
  40. data/lib/sinatra/base.rb +818 -0
  41. data/lib/sinatra/compat.rb +239 -0
  42. data/lib/sinatra/images/404.png +0 -0
  43. data/lib/sinatra/images/500.png +0 -0
  44. data/lib/sinatra/main.rb +48 -0
  45. data/lib/sinatra/test/bacon.rb +17 -0
  46. data/lib/sinatra/test/rspec.rb +9 -0
  47. data/lib/sinatra/test/spec.rb +9 -0
  48. data/lib/sinatra/test/unit.rb +11 -0
  49. data/lib/sinatra/test.rb +109 -0
  50. data/lib/sinatra.rb +4 -0
  51. data/sinatra.gemspec +109 -0
  52. data/test/base_test.rb +68 -0
  53. data/test/builder_test.rb +64 -0
  54. data/test/data/reload_app_file.rb +3 -0
  55. data/test/erb_test.rb +50 -0
  56. data/test/filter_test.rb +35 -0
  57. data/test/haml_test.rb +68 -0
  58. data/test/helper.rb +20 -0
  59. data/test/helpers_test.rb +361 -0
  60. data/test/mapped_error_test.rb +160 -0
  61. data/test/middleware_test.rb +58 -0
  62. data/test/options_test.rb +97 -0
  63. data/test/reload_test.rb +61 -0
  64. data/test/request_test.rb +9 -0
  65. data/test/result_test.rb +88 -0
  66. data/test/routing_test.rb +334 -0
  67. data/test/sass_test.rb +36 -0
  68. data/test/sinatra_test.rb +13 -0
  69. data/test/static_test.rb +57 -0
  70. data/test/templates_test.rb +88 -0
  71. data/test/views/hello.builder +1 -0
  72. data/test/views/hello.erb +1 -0
  73. data/test/views/hello.haml +1 -0
  74. data/test/views/hello.sass +2 -0
  75. data/test/views/hello.test +1 -0
  76. data/test/views/layout2.builder +3 -0
  77. data/test/views/layout2.erb +2 -0
  78. data/test/views/layout2.haml +2 -0
  79. data/test/views/layout2.test +1 -0
  80. metadata +161 -0
data/README.rdoc ADDED
@@ -0,0 +1,545 @@
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
+ Run with <tt>ruby myapp.rb</tt> and view at <tt>http://localhost:4567</tt>
14
+
15
+ == HTTP Methods
16
+
17
+ get '/' do
18
+ .. show things ..
19
+ end
20
+
21
+ post '/' do
22
+ .. create something ..
23
+ end
24
+
25
+ put '/' do
26
+ .. update something ..
27
+ end
28
+
29
+ delete '/' do
30
+ .. annihilate something ..
31
+ end
32
+
33
+ == Routes
34
+
35
+ Routes are matched based on the order of declaration. The first route that
36
+ matches the request is invoked.
37
+
38
+ Basic routes:
39
+
40
+ get '/hi' do
41
+ ...
42
+ end
43
+
44
+ Route patterns may include named parameters, accessible via the
45
+ <tt>params</tt> hash:
46
+
47
+ get '/:name' do
48
+ # matches "GET /foo" and "GET /bar"
49
+ # params[:name] is 'foo' or 'bar'
50
+ "Hello #{params[:name]}!"
51
+ end
52
+
53
+ Route patterns may also include splat (or wildcard) parameters, accessible
54
+ via the <tt>params[:splat]</tt> array.
55
+
56
+ get '/say/*/to/*' do
57
+ # matches /say/hello/to/world
58
+ params[:splat] # => ["hello", "world"]
59
+ end
60
+
61
+ get '/download/*.*' do
62
+ # matches /download/path/to/file.xml
63
+ params[:splat] # => ["path/to/file", "xml"]
64
+ end
65
+
66
+ Route matching with Regular Expressions:
67
+
68
+ get %r{/hello/([\w]+)} do
69
+ "Hello, #{params[:captures].first}!"
70
+ end
71
+
72
+ Routes may include a variety of matching conditions, such as the user agent:
73
+
74
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
75
+ "You're using Songbird version #{params[:agent][0]}"
76
+ end
77
+
78
+ get '/foo' do
79
+ # Matches non-songbird browsers
80
+ end
81
+
82
+ == Static Files
83
+
84
+ Static files are served from the <tt>./public</tt> directory. You can specify
85
+ a different location by setting the <tt>:public</tt> option:
86
+
87
+ set :public, File.dirname(__FILE__) + '/static'
88
+
89
+ == Views / Templates
90
+
91
+ Templates are assumed to be located directly under a <tt>./views</tt>
92
+ directory. To use a different views directory:
93
+
94
+ set :views, File.dirname(__FILE__) + '/templates'
95
+
96
+ === Haml Templates
97
+
98
+ The haml gem/library is required to render HAML templates:
99
+
100
+ get '/' do
101
+ haml :index
102
+ end
103
+
104
+ Renders <tt>./views/index.haml</tt>.
105
+
106
+ === Erb Templates
107
+
108
+ get '/' do
109
+ erb :index
110
+ end
111
+
112
+ Renders <tt>./views/index.erb</tt>
113
+
114
+ === Builder Templates
115
+
116
+ The builder gem/library is required to render builder templates:
117
+
118
+ get '/' do
119
+ content_type 'application/xml', :charset => 'utf-8'
120
+ builder :index
121
+ end
122
+
123
+ Renders <tt>./views/index.builder</tt>.
124
+
125
+ === Sass Templates
126
+
127
+ The sass gem/library is required to render Sass templates:
128
+
129
+ get '/stylesheet.css' do
130
+ content_type 'text/css', :charset => 'utf-8'
131
+ sass :stylesheet
132
+ end
133
+
134
+ Renders <tt>./views/stylesheet.sass</tt>.
135
+
136
+ === Inline Templates
137
+
138
+ get '/' do
139
+ haml '%div.title Hello World'
140
+ end
141
+
142
+ Renders the inlined template string.
143
+
144
+ === Accessing Variables
145
+
146
+ Templates are evaluated within the same context as the route blocks. Instance
147
+ variables set in route blocks are available in templates:
148
+
149
+ get '/:id' do
150
+ @foo = Foo.find(params[:id])
151
+ haml '%h1= @foo.name'
152
+ end
153
+
154
+ Or, specify an explicit Hash of local variables:
155
+
156
+ get '/:id' do
157
+ foo = Foo.find(params[:id])
158
+ haml '%h1= foo.name', :locals => { :foo => foo }
159
+ end
160
+
161
+ This is typically used when rendering templates as partials from within
162
+ other templates.
163
+
164
+ === In-file Templates
165
+
166
+ Templates may be defined at the end of the source file:
167
+
168
+ get '/' do
169
+ haml :index
170
+ end
171
+
172
+ use_in_file_templates!
173
+
174
+ __END__
175
+
176
+ @@ layout
177
+ %html
178
+ = yield
179
+
180
+ @@ index
181
+ %div.title Hello world!!!!!
182
+
183
+ It's also possible to define named templates using the top-level template
184
+ method:
185
+
186
+ template :layout do
187
+ "%html\n =yield\n"
188
+ end
189
+
190
+ template :index do
191
+ '%div.title Hello World!'
192
+ end
193
+
194
+ get '/' do
195
+ haml :index
196
+ end
197
+
198
+ If a template named "layout" exists, it will be used each time a template
199
+ is rendered. You can disable layouts by passing <tt>:layout => false</tt>.
200
+
201
+ get '/' do
202
+ haml :index, :layout => !request.xhr?
203
+ end
204
+
205
+ == Helpers
206
+
207
+ Use the top-level <tt>helpers</tt> method to define helper methods for use in
208
+ route blocks and templates:
209
+
210
+ helpers do
211
+ def bar(name)
212
+ "#{name}bar"
213
+ end
214
+ end
215
+
216
+ get '/:name' do
217
+ bar(params[:name])
218
+ end
219
+
220
+ == Filters
221
+
222
+ Before filters are evaluated before each request within the context of the
223
+ request and can modify the request and response. Instance variables set in
224
+ filters are accessible by routes and templates.
225
+
226
+ before do
227
+ @note = 'Hi!'
228
+ request.path_info = '/foo/bar/baz'
229
+ end
230
+
231
+ get '/foo/*' do
232
+ @note #=> 'Hi!'
233
+ params[:splat] #=> 'bar/baz'
234
+ end
235
+
236
+ == Halting
237
+
238
+ To immediately stop a request during a before filter or route use:
239
+
240
+ halt
241
+
242
+ You can also specify a body when halting ...
243
+
244
+ halt 'this will be the body'
245
+
246
+ Set the status and body ...
247
+
248
+ halt 401, 'go away!'
249
+
250
+ == Passing
251
+
252
+ A route can punt processing to the next matching route using the <tt>pass</tt>
253
+ statement:
254
+
255
+ get '/guess/:who' do
256
+ pass unless params[:who] == 'Frank'
257
+ "You got me!"
258
+ end
259
+
260
+ get '/guess/*' do
261
+ "You missed!"
262
+ end
263
+
264
+ The route block is immediately exited and control continues with the next
265
+ matching route. If no matching route is found, a 404 is returned.
266
+
267
+ == Configuration and Reloading
268
+
269
+ Sinatra supports multiple environments and reloading. Reloading happens
270
+ before each request when running under the <tt>:development</tt>
271
+ environment. Wrap your configurations (e.g., database connections, constants,
272
+ etc.) in <tt>configure</tt> blocks to protect them from reloading or to
273
+ target specific environments.
274
+
275
+ Run once, at startup, in any environment:
276
+
277
+ configure do
278
+ ...
279
+ end
280
+
281
+ Run only when the environment (RACK_ENV environment variable) is set to
282
+ <tt>:production</tt>.
283
+
284
+ configure :production do
285
+ ...
286
+ end
287
+
288
+ Run when the environment (RACK_ENV environment variable) is set to
289
+ either <tt>:production</tt> or <tt>:test</tt>.
290
+
291
+ configure :production, :test do
292
+ ...
293
+ end
294
+
295
+ == Error handling
296
+
297
+ Error handlers run within the same context as routes and before filters, which
298
+ means you get all the goodies it has to offer, like <tt>haml</tt>, <tt>erb</tt>,
299
+ <tt>halt</tt>, etc.
300
+
301
+ === Not Found
302
+
303
+ When a <tt>Sinatra::NotFound</tt> exception is raised, or the response's status
304
+ code is 404, the <tt>not_found</tt> handler is invoked:
305
+
306
+ not_found do
307
+ 'This is nowhere to be found'
308
+ end
309
+
310
+ === Error
311
+
312
+ The +error+ handler is invoked any time an exception is raised from a route
313
+ block or before filter. The exception object can be obtained from the
314
+ 'sinatra.error' Rack variable:
315
+
316
+ error do
317
+ 'Sorry there was a nasty error - ' + env['sinatra.error'].name
318
+ end
319
+
320
+ Custom errors:
321
+
322
+ error MyCustomError do
323
+ 'So what happened was...' + request.env['sinatra.error'].message
324
+ end
325
+
326
+ Then, if this happens:
327
+
328
+ get '/' do
329
+ raise MyCustomError, 'something bad'
330
+ end
331
+
332
+ You get this:
333
+
334
+ So what happened was... something bad
335
+
336
+ Sinatra installs special not_found and error handlers when running under
337
+ the development environment.
338
+
339
+ == Mime types
340
+
341
+ When using <tt>send_file</tt> or static files you may have mime types Sinatra
342
+ doesn't understand. Use +mime+ to register them by file extension:
343
+
344
+ mime :foo, 'text/foo'
345
+
346
+ == Rack Middleware
347
+
348
+ Sinatra rides on Rack[http://rack.rubyforge.org/], a minimal standard
349
+ interface for Ruby web frameworks. One of Rack's most interesting capabilities
350
+ for application developers is support for "middleware" -- components that sit
351
+ between the server and your application monitoring and/or manipulating the
352
+ HTTP request/response to provide various types of common functionality.
353
+
354
+ Sinatra makes building Rack middleware pipelines a cinch via a top-level
355
+ +use+ method:
356
+
357
+ require 'sinatra'
358
+ require 'my_custom_middleware'
359
+
360
+ use Rack::Lint
361
+ use MyCustomMiddleware
362
+
363
+ get '/hello' do
364
+ 'Hello World'
365
+ end
366
+
367
+ The semantics of +use+ are identical to those defined for the
368
+ Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
369
+ (most frequently used from rackup files). For example, the +use+ method
370
+ accepts multiple/variable args as well as blocks:
371
+
372
+ use Rack::Auth::Basic do |username, password|
373
+ username == 'admin' && password == 'secret'
374
+ end
375
+
376
+ Rack is distributed with a variety of standard middleware for logging,
377
+ debugging, URL routing, authentication, and session handling. Sinatra uses
378
+ many of of these components automatically based on configuration so you
379
+ typically don't have to +use+ them explicitly.
380
+
381
+ == Testing
382
+
383
+ The Sinatra::Test module includes a variety of helper methods for testing
384
+ your Sinatra app. Sinatra includes support for Test::Unit, test-spec, RSpec,
385
+ and Bacon through separate source files.
386
+
387
+ === Test::Unit
388
+
389
+ require 'sinatra'
390
+ require 'sinatra/test/unit'
391
+ require 'my_sinatra_app'
392
+
393
+ class MyAppTest < Test::Unit::TestCase
394
+ def test_my_default
395
+ get '/'
396
+ assert_equal 'My Default Page!', @response.body
397
+ end
398
+
399
+ def test_with_agent
400
+ get '/', :agent => 'Songbird'
401
+ assert_equal 'You're in Songbird!', @response.body
402
+ end
403
+
404
+ ...
405
+ end
406
+
407
+ === Test::Spec
408
+
409
+ Install the test-spec gem and require <tt>'sinatra/test/spec'</tt> before
410
+ your app:
411
+
412
+ require 'sinatra'
413
+ require 'sinatra/test/spec'
414
+ require 'my_sinatra_app'
415
+
416
+ describe 'My app' do
417
+ it "should show a default page" do
418
+ get '/'
419
+ should.be.ok
420
+ body.should.equal 'My Default Page!'
421
+ end
422
+
423
+ ...
424
+ end
425
+
426
+ === RSpec
427
+
428
+ Install the rspec gem and require <tt>'sinatra/test/rspec'</tt> before
429
+ your app:
430
+
431
+ require 'sinatra'
432
+ require 'sinatra/test/rspec'
433
+ require 'my_sinatra_app'
434
+
435
+ describe 'My app' do
436
+ it 'should show a default page' do
437
+ get '/'
438
+ @response.should be_ok
439
+ @response.body.should == 'My Default Page!'
440
+ end
441
+
442
+ ...
443
+
444
+ end
445
+
446
+ === Bacon
447
+
448
+ require 'sinatra'
449
+ require 'sinatra/test/bacon'
450
+ require 'my_sinatra_app'
451
+
452
+ describe 'My app' do
453
+ it 'should be ok' do
454
+ get '/'
455
+ should.be.ok
456
+ body.should == 'Im OK'
457
+ end
458
+ end
459
+
460
+ See Sinatra::Test for more information on +get+, +post+, +put+, and
461
+ friends.
462
+
463
+ == Command line
464
+
465
+ Sinatra applications can be run directly:
466
+
467
+ ruby myapp.rb [-h] [-x] [-p PORT] [-e ENVIRONMENT]
468
+
469
+ Options are:
470
+
471
+ -h # help
472
+ -p # set the port (default is 4567)
473
+ -e # set the environment (default is development)
474
+ -x # turn on the mutex lock (default is off)
475
+
476
+ == Contributing
477
+
478
+ === Tools
479
+
480
+ Besides Ruby itself, you only need a text editor, preferably one that supports
481
+ Ruby syntax hilighting. VIM and Emacs are a fine choice on any platform, but
482
+ feel free to use whatever you're familiar with.
483
+
484
+ Sinatra uses the Git source code management system. If you're unfamiliar with
485
+ Git, you can find more information and tutorials on http://git.or.cz/ as well
486
+ as http://git-scm.com/. Scott Chacon created a great series of introductory
487
+ screencasts about Git, which you can find here: http://www.gitcasts.com/
488
+
489
+ === First Time: Cloning The Sinatra Repo
490
+
491
+ cd where/you/keep/your/projects
492
+ git clone git://github.com/bmizerany/sinatra.git
493
+ cd sinatra
494
+ cd path/to/your_project
495
+ ln -s ../sinatra/
496
+
497
+ === Updating Your Existing Sinatra Clone
498
+
499
+ cd where/you/keep/sinatra
500
+ git pull
501
+
502
+ === Using Edge Sinatra in Your App
503
+
504
+ at the top of your sinatra_app.rb file:
505
+
506
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
507
+ require 'sinatra'
508
+
509
+ get '/about' do
510
+ "I'm running on Version " + Sinatra::VERSION
511
+ end
512
+
513
+ === Contributing a Patch
514
+
515
+ There are several ways to do this. Probably the easiest (and preferred) way is
516
+ to fork Sinatra on GitHub (http://github.com/bmizerany/sinatra), push your
517
+ changes to your Sinatra repo, and then send Blake Mizerany (bmizerany on
518
+ GitHub) a pull request.
519
+
520
+ You can also create a patch file and attach it to a feature request or bug fix
521
+ on the issue tracker (see below) or send it to the mailing list (see Community
522
+ section).
523
+
524
+ === Issue Tracking and Feature Requests
525
+
526
+ http://sinatra.lighthouseapp.com/
527
+
528
+ == Community
529
+
530
+ === Mailing List
531
+
532
+ http://groups.google.com/group/sinatrarb
533
+
534
+ If you have a problem or question, please make sure to include all the
535
+ relevant information in your mail, like the Sinatra version you're using, what
536
+ version of Ruby you have, and so on.
537
+
538
+ === IRC Channel
539
+
540
+ You can find us on the Freenode network in the channel #sinatra
541
+ (irc://chat.freenode.net/#sinatra)
542
+
543
+ There's usually someone online at any given time, but we cannot pay attention
544
+ to the channel all the time, so please stick around for a while after asking a
545
+ question.
data/Rakefile ADDED
@@ -0,0 +1,180 @@
1
+ require 'rubygems'
2
+ require 'rake/clean'
3
+ require 'fileutils'
4
+
5
+ task :default => :test
6
+
7
+ # SPECS ===============================================================
8
+
9
+ desc 'Run specs with story style output'
10
+ task :spec do
11
+ pattern = ENV['TEST'] || '.*'
12
+ sh "specrb --testcase '#{pattern}' --specdox -Ilib:test test/*_test.rb"
13
+ end
14
+
15
+ desc 'Run specs with unit test style output'
16
+ task :test do |t|
17
+ sh "specrb -Ilib:test test/*_test.rb"
18
+ end
19
+
20
+ desc 'Run compatibility specs'
21
+ task :compat do |t|
22
+ pattern = ENV['TEST'] || '.*'
23
+ sh "specrb --testcase '#{pattern}' -Ilib:test compat/*_test.rb"
24
+ end
25
+
26
+ # PACKAGING ============================================================
27
+
28
+ # Load the gemspec using the same limitations as github
29
+ def spec
30
+ @spec ||=
31
+ begin
32
+ require 'rubygems/specification'
33
+ data = File.read('sinatra.gemspec')
34
+ spec = nil
35
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
36
+ spec
37
+ end
38
+ end
39
+
40
+ def package(ext='')
41
+ "dist/sinatra-#{spec.version}" + ext
42
+ end
43
+
44
+ desc 'Build packages'
45
+ task :package => %w[.gem .tar.gz].map {|e| package(e)}
46
+
47
+ desc 'Build and install as local gem'
48
+ task :install => package('.gem') do
49
+ sh "gem install #{package('.gem')}"
50
+ end
51
+
52
+ directory 'dist/'
53
+
54
+ file package('.gem') => %w[dist/ sinatra.gemspec] + spec.files do |f|
55
+ sh "gem build sinatra.gemspec"
56
+ mv File.basename(f.name), f.name
57
+ end
58
+
59
+ file package('.tar.gz') => %w[dist/] + spec.files do |f|
60
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
61
+ end
62
+
63
+ # Rubyforge Release / Publish Tasks ==================================
64
+
65
+ desc 'Publish website to rubyforge'
66
+ task 'publish:doc' => 'doc/api/index.html' do
67
+ sh 'scp -rp doc/* rubyforge.org:/var/www/gforge-projects/sinatra/'
68
+ end
69
+
70
+ task 'publish:gem' => [package('.gem'), package('.tar.gz')] do |t|
71
+ sh <<-end
72
+ rubyforge add_release sinatra sinatra #{spec.version} #{package('.gem')} &&
73
+ rubyforge add_file sinatra sinatra #{spec.version} #{package('.tar.gz')}
74
+ end
75
+ end
76
+
77
+ # Website ============================================================
78
+ # Building docs requires HAML and the hanna gem:
79
+ # gem install mislav-hanna --source=http://gems.github.com
80
+
81
+ task 'doc' => ['doc:api','doc:site']
82
+
83
+ desc 'Generate Hanna RDoc under doc/api'
84
+ task 'doc:api' => ['doc/api/index.html']
85
+
86
+ file 'doc/api/index.html' => FileList['lib/**/*.rb','README.rdoc'] do |f|
87
+ rb_files = f.prerequisites
88
+ sh((<<-end).gsub(/\s+/, ' '))
89
+ hanna --charset utf8 \
90
+ --fmt html \
91
+ --inline-source \
92
+ --line-numbers \
93
+ --main README.rdoc \
94
+ --op doc/api \
95
+ --title 'Sinatra API Documentation' \
96
+ #{rb_files.join(' ')}
97
+ end
98
+ end
99
+ CLEAN.include 'doc/api'
100
+
101
+ def rdoc_to_html(file_name)
102
+ require 'rdoc/markup/to_html'
103
+ rdoc = RDoc::Markup::ToHtml.new
104
+ rdoc.convert(File.read(file_name))
105
+ end
106
+
107
+ def haml(locals={})
108
+ require 'haml'
109
+ template = File.read('doc/template.haml')
110
+ haml = Haml::Engine.new(template, :format => :html4, :attr_wrapper => '"')
111
+ haml.render(Object.new, locals)
112
+ end
113
+
114
+ desc 'Build website HTML and stuff'
115
+ task 'doc:site' => ['doc/index.html', 'doc/book.html']
116
+
117
+ file 'doc/index.html' => %w[README.rdoc doc/template.haml] do |file|
118
+ File.open(file.name, 'w') do |file|
119
+ file << haml(:title => 'Sinatra', :content => rdoc_to_html('README.rdoc'))
120
+ end
121
+ end
122
+ CLEAN.include 'doc/index.html'
123
+
124
+ file 'doc/book.html' => ['book/output/sinatra-book.html'] do |file|
125
+ File.open(file.name, 'w') do |file|
126
+ book_content = File.read('book/output/sinatra-book.html')
127
+ file << haml(:title => 'Sinatra Book', :content => book_content)
128
+ end
129
+ end
130
+ CLEAN.include 'doc/book.html'
131
+
132
+ file 'book/output/sinatra-book.html' => FileList['book/**'] do |f|
133
+ unless File.directory?('book')
134
+ sh 'git clone git://github.com/cschneid/sinatra-book.git book'
135
+ end
136
+ sh((<<-SH).strip.gsub(/\s+/, ' '))
137
+ cd book &&
138
+ git fetch origin &&
139
+ git rebase origin/master &&
140
+ thor book:build
141
+ SH
142
+ end
143
+ CLEAN.include 'book/output/sinatra-book.html'
144
+
145
+ desc 'Build the Sinatra book'
146
+ task 'doc:book' => ['book/output/sinatra-book.html']
147
+
148
+ # Gemspec Helpers ====================================================
149
+
150
+ def source_version
151
+ line = File.read('lib/sinatra/base.rb')[/^\s*VERSION = .*/]
152
+ line.match(/.*VERSION = '(.*)'/)[1]
153
+ end
154
+
155
+ project_files =
156
+ FileList[
157
+ '{lib,test,compat,images}/**',
158
+ 'Rakefile', 'CHANGES', 'README.rdoc'
159
+ ]
160
+ file 'sinatra.gemspec' => project_files do |f|
161
+ # read spec file and split out manifest section
162
+ spec = File.read(f.name)
163
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
164
+ # replace version and date
165
+ head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
166
+ head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
167
+ # determine file list from git ls-files
168
+ files = `git ls-files`.
169
+ split("\n").
170
+ sort.
171
+ reject{ |file| file =~ /^\./ }.
172
+ reject { |file| file =~ /^doc/ }.
173
+ map{ |file| " #{file}" }.
174
+ join("\n")
175
+ # piece file back together and write...
176
+ manifest = " s.files = %w[\n#{files}\n ]\n"
177
+ spec = [head,manifest,tail].join(" # = MANIFEST =\n")
178
+ File.open(f.name, 'w') { |io| io.write(spec) }
179
+ puts "updated #{f.name}"
180
+ end