sinatra 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/CHANGELOG +1 -8
- data/Manifest +42 -49
- data/README.rdoc +430 -0
- data/Rakefile +22 -28
- data/images/404.png +0 -0
- data/images/500.png +0 -0
- data/index.html +9 -0
- data/lib/sinatra.rb +1144 -46
- data/lib/sinatra/test/methods.rb +56 -0
- data/lib/sinatra/test/spec.rb +10 -0
- data/lib/sinatra/test/unit.rb +13 -0
- data/sinatra.gemspec +44 -40
- data/test/app_test.rb +150 -0
- data/test/application_test.rb +175 -0
- data/test/builder_test.rb +101 -0
- data/test/custom_error_test.rb +67 -0
- data/test/diddy_test.rb +41 -0
- data/test/erb_test.rb +116 -0
- data/test/event_context_test.rb +15 -0
- data/test/events_test.rb +50 -0
- data/test/haml_test.rb +181 -0
- data/test/helper.rb +3 -16
- data/test/mapped_error_test.rb +61 -0
- data/test/public/foo.xml +1 -0
- data/test/rest_test.rb +16 -0
- data/test/sass_test.rb +57 -0
- data/test/sessions_test.rb +40 -0
- data/test/streaming_test.rb +112 -0
- data/test/sym_params_test.rb +19 -0
- data/test/template_test.rb +30 -0
- data/test/use_in_file_templates_test.rb +48 -0
- data/test/views/foo.builder +1 -0
- data/test/views/foo.erb +1 -0
- data/test/views/foo.haml +1 -0
- data/test/views/foo.sass +2 -0
- data/test/views/foo_layout.erb +2 -0
- data/test/views/foo_layout.haml +2 -0
- data/test/views/layout_test/foo.builder +1 -0
- data/test/views/layout_test/foo.erb +1 -0
- data/test/views/layout_test/foo.haml +1 -0
- data/test/views/layout_test/foo.sass +2 -0
- data/test/views/layout_test/layout.builder +3 -0
- data/test/views/layout_test/layout.erb +1 -0
- data/test/views/layout_test/layout.haml +1 -0
- data/test/views/layout_test/layout.sass +2 -0
- data/test/views/no_layout/no_layout.builder +1 -0
- data/test/views/no_layout/no_layout.haml +1 -0
- metadata +122 -98
- data/LICENSE +0 -22
- data/README +0 -100
- data/RakeFile +0 -35
- data/examples/hello/hello.rb +0 -28
- data/examples/hello/views/hello.erb +0 -1
- data/examples/todo/todo.rb +0 -38
- data/files/default_index.erb +0 -42
- data/files/error.erb +0 -9
- data/files/logo.png +0 -0
- data/files/not_found.erb +0 -52
- data/lib/sinatra/context.rb +0 -88
- data/lib/sinatra/context/renderer.rb +0 -75
- data/lib/sinatra/core_ext/array.rb +0 -5
- data/lib/sinatra/core_ext/class.rb +0 -49
- data/lib/sinatra/core_ext/hash.rb +0 -7
- data/lib/sinatra/core_ext/kernel.rb +0 -16
- data/lib/sinatra/core_ext/metaid.rb +0 -18
- data/lib/sinatra/core_ext/module.rb +0 -11
- data/lib/sinatra/core_ext/symbol.rb +0 -5
- data/lib/sinatra/dispatcher.rb +0 -27
- data/lib/sinatra/dsl.rb +0 -176
- data/lib/sinatra/environment.rb +0 -15
- data/lib/sinatra/event.rb +0 -238
- data/lib/sinatra/irb.rb +0 -56
- data/lib/sinatra/loader.rb +0 -31
- data/lib/sinatra/logger.rb +0 -22
- data/lib/sinatra/options.rb +0 -49
- data/lib/sinatra/rack_ext/request.rb +0 -15
- data/lib/sinatra/route.rb +0 -65
- data/lib/sinatra/server.rb +0 -57
- data/lib/sinatra/sessions.rb +0 -21
- data/lib/sinatra/test_methods.rb +0 -55
- data/site/index.htm +0 -104
- data/site/index.html +0 -104
- data/site/logo.png +0 -0
- data/test/sinatra/dispatcher_test.rb +0 -91
- data/test/sinatra/event_test.rb +0 -46
- data/test/sinatra/renderer_test.rb +0 -47
- data/test/sinatra/request_test.rb +0 -21
- data/test/sinatra/route_test.rb +0 -21
- data/test/sinatra/static_files/foo.txt +0 -1
- data/test/sinatra/static_files_test.rb +0 -48
- data/test/sinatra/url_test.rb +0 -18
- data/vendor/erb/init.rb +0 -3
- data/vendor/erb/lib/erb.rb +0 -41
- data/vendor/haml/init.rb +0 -3
- data/vendor/haml/lib/haml.rb +0 -41
data/lib/sinatra/loader.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Sinatra
|
4
|
-
module Loader
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def reload!
|
8
|
-
silence_warnings do
|
9
|
-
EventManager.reset!
|
10
|
-
load_files loaded_files
|
11
|
-
load $0
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def load_files(*files)
|
16
|
-
files = files.flatten
|
17
|
-
files = files.first if files.first.is_a? Set
|
18
|
-
|
19
|
-
files.each do |file|
|
20
|
-
file = File.expand_path(file)
|
21
|
-
load file
|
22
|
-
loaded_files << file
|
23
|
-
end
|
24
|
-
end
|
25
|
-
alias_method :load_file, :load_files
|
26
|
-
|
27
|
-
def loaded_files
|
28
|
-
@loaded_files ||= Set.new
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/sinatra/logger.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module Sinatra
|
2
|
-
|
3
|
-
class Logger
|
4
|
-
|
5
|
-
def initialize(steam)
|
6
|
-
@stream = steam
|
7
|
-
end
|
8
|
-
|
9
|
-
%w(info debug error warn).each do |n|
|
10
|
-
define_method n do |message|
|
11
|
-
@stream.puts message
|
12
|
-
@stream.flush
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def exception(e)
|
17
|
-
error "#{e.message}:\n\t#{e.backtrace.join("\n\t")}"
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
data/lib/sinatra/options.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
|
-
module Sinatra
|
4
|
-
module Options
|
5
|
-
extend self
|
6
|
-
|
7
|
-
attr_with_default :port, 4567
|
8
|
-
attr_with_default :environment, :development
|
9
|
-
attr_with_default :console, nil
|
10
|
-
attr_with_default :use_mutex, false
|
11
|
-
|
12
|
-
alias :use_mutex? :use_mutex
|
13
|
-
|
14
|
-
def parse!(args)
|
15
|
-
return if @environment == :test
|
16
|
-
OptionParser.new do |opts|
|
17
|
-
opts.on '-p port', '--port port', 'Set the port (default is 4567)' do |port|
|
18
|
-
@port = port
|
19
|
-
end
|
20
|
-
opts.on '-e environment', 'Set the environment (default if development)' do |env|
|
21
|
-
@environment = env.intern
|
22
|
-
end
|
23
|
-
opts.on '-c', '--console', 'Run in console mode' do
|
24
|
-
@console = true
|
25
|
-
end
|
26
|
-
opts.on '-h', '--help', '-?', 'Show this message' do
|
27
|
-
puts opts
|
28
|
-
exit!
|
29
|
-
end
|
30
|
-
opts.on '-X', '--mutex', 'Use mutex lock when attending events' do
|
31
|
-
@use_mutex = true
|
32
|
-
end
|
33
|
-
end.parse!(ARGV)
|
34
|
-
end
|
35
|
-
|
36
|
-
def log_file
|
37
|
-
# TODO find a better way that this
|
38
|
-
if File.basename($0, '.rb') == 'rake_test_loader' # hack to satisfy rake
|
39
|
-
'%s.log' % environment
|
40
|
-
else
|
41
|
-
File.dirname($0) + ('/%s.log' % environment)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def set_environment(env)
|
46
|
-
@environment = env
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/sinatra/route.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
module Sinatra
|
2
|
-
|
3
|
-
class Route
|
4
|
-
|
5
|
-
SYMBOL_FIND = /:[a-z_]+/.freeze
|
6
|
-
PARENTHETICAL_SEGMENT_STRING = "([^\/.,;?]+)".freeze
|
7
|
-
|
8
|
-
attr_reader :regex, :params
|
9
|
-
|
10
|
-
def initialize(template)
|
11
|
-
@template = template.to_s.strip
|
12
|
-
@default_params = { :format => 'html' }
|
13
|
-
@params = {}
|
14
|
-
extract_keys
|
15
|
-
genereate_route
|
16
|
-
end
|
17
|
-
|
18
|
-
def recognize(path)
|
19
|
-
@params.clear
|
20
|
-
|
21
|
-
param_values = path.match(@regex).captures.compact rescue nil
|
22
|
-
|
23
|
-
if param_values
|
24
|
-
keys = @keys.size < param_values.size ? @keys.concat([:format]) : @keys
|
25
|
-
@params = @default_params.merge(@keys.zip(param_values).to_hash)
|
26
|
-
true
|
27
|
-
else
|
28
|
-
false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def extract_keys
|
35
|
-
@keys = @template.scan(SYMBOL_FIND).map { |raw| eval(raw) }
|
36
|
-
@keys
|
37
|
-
end
|
38
|
-
|
39
|
-
def genereate_route_without_format
|
40
|
-
template = @template.dup
|
41
|
-
template.gsub!(/\.:format$/, '')
|
42
|
-
to_regex_route(template)
|
43
|
-
end
|
44
|
-
|
45
|
-
def genereate_route_with_format
|
46
|
-
template = @template.dup
|
47
|
-
if template =~ /\.:format$|\.([\w\d]+)$/
|
48
|
-
@default_params[:format] = $1 if $1
|
49
|
-
else
|
50
|
-
template << '.:format'
|
51
|
-
end
|
52
|
-
to_regex_route(template)
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_regex_route(template)
|
56
|
-
/^#{template.gsub(/\./, '\.').gsub(SYMBOL_FIND, PARENTHETICAL_SEGMENT_STRING)}$/
|
57
|
-
end
|
58
|
-
|
59
|
-
def genereate_route
|
60
|
-
@regex = Regexp.union(genereate_route_without_format, genereate_route_with_format)
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
data/lib/sinatra/server.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
module Sinatra
|
4
|
-
|
5
|
-
class Server
|
6
|
-
|
7
|
-
cattr_accessor :logger
|
8
|
-
cattr_accessor :running
|
9
|
-
|
10
|
-
def start
|
11
|
-
begin
|
12
|
-
tail_thread = tail(Options.log_file)
|
13
|
-
Rack::Handler::Mongrel.run(Sinatra::Session::Cookie.new(Dispatcher.new), :Port => Options.port) do |server|
|
14
|
-
puts "== Sinatra has taken the stage on port #{server.port}!"
|
15
|
-
trap("INT") do
|
16
|
-
server.stop
|
17
|
-
self.class.running = false
|
18
|
-
puts "\n== Sinatra has ended his set (crowd applauds)"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
self.class.running = true
|
22
|
-
rescue Errno::EADDRINUSE => e
|
23
|
-
puts "== Someone is already performing on port #{Options.port}!"
|
24
|
-
logger.exception e
|
25
|
-
rescue => e
|
26
|
-
logger.exception e
|
27
|
-
ensure
|
28
|
-
tail_thread.kill if tail_thread
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def tail(log_file)
|
35
|
-
FileUtils.touch(log_file)
|
36
|
-
cursor = File.size(log_file)
|
37
|
-
last_checked = Time.now
|
38
|
-
tail_thread = Thread.new do
|
39
|
-
File.open(log_file, 'r') do |f|
|
40
|
-
loop do
|
41
|
-
f.seek cursor
|
42
|
-
if f.mtime > last_checked
|
43
|
-
last_checked = f.mtime
|
44
|
-
contents = f.read
|
45
|
-
cursor += contents.length
|
46
|
-
print contents
|
47
|
-
end
|
48
|
-
sleep 1
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
tail_thread
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
data/lib/sinatra/sessions.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Sinatra
|
2
|
-
module Session
|
3
|
-
class Cookie
|
4
|
-
def self.use=(v)
|
5
|
-
@@use = v unless Sinatra::Server.running # keep is thread-safe!
|
6
|
-
end
|
7
|
-
|
8
|
-
def initialize(app, options = {})
|
9
|
-
@app = if (@@use ||= :on) == :off
|
10
|
-
app
|
11
|
-
else
|
12
|
-
Rack::Session::Cookie.new(app)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
@app.call(env)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/sinatra/test_methods.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
|
3
|
-
module Sinatra
|
4
|
-
|
5
|
-
# These methods are for integration testing without an internet connection. They are available in Test::Unit::TestCase and when in Irb.
|
6
|
-
|
7
|
-
module TestMethods
|
8
|
-
|
9
|
-
# get_it, post_it, put_it, delete_it
|
10
|
-
# Executes the method and returns the result of the body
|
11
|
-
#
|
12
|
-
# options:
|
13
|
-
# +:params+ a hash of name parameters
|
14
|
-
#
|
15
|
-
# Example:
|
16
|
-
# get_it '/', :name => 'Blake' # => 'Hello Blake!'
|
17
|
-
#
|
18
|
-
%w(get post put delete).each do |verb|
|
19
|
-
module_eval <<-end_eval
|
20
|
-
def #{verb}_it(path, params = {})
|
21
|
-
request = Rack::MockRequest.new(Sinatra::Dispatcher.new)
|
22
|
-
@response = request.#{verb} path, :input => generate_input(params)
|
23
|
-
body
|
24
|
-
end
|
25
|
-
end_eval
|
26
|
-
end
|
27
|
-
|
28
|
-
def response
|
29
|
-
@response || Rack::MockResponse.new(404, {}, '')
|
30
|
-
end
|
31
|
-
|
32
|
-
def status
|
33
|
-
response.status
|
34
|
-
end
|
35
|
-
|
36
|
-
def text
|
37
|
-
response.body
|
38
|
-
end
|
39
|
-
alias :xml :text
|
40
|
-
alias :html :text
|
41
|
-
alias :body :text
|
42
|
-
|
43
|
-
def headers
|
44
|
-
response.headers
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def generate_input(params)
|
50
|
-
params.map { |k,v| "#{k}=#{URI.escape(v)}" }.join('&')
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
data/site/index.htm
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
-
|
4
|
-
<html>
|
5
|
-
<head>
|
6
|
-
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
7
|
-
<title>Sinatra : Classy web-development dressed in a DSL</title>
|
8
|
-
</head>
|
9
|
-
|
10
|
-
<body>
|
11
|
-
<style type="text/css" media="screen">
|
12
|
-
body {
|
13
|
-
background-color: #fff;
|
14
|
-
color: #333;
|
15
|
-
font-size: 0.75em;
|
16
|
-
}
|
17
|
-
|
18
|
-
#container {
|
19
|
-
width: 600px;
|
20
|
-
margin: 0 auto;
|
21
|
-
font-size: 1.5em;
|
22
|
-
}
|
23
|
-
|
24
|
-
#container pre {
|
25
|
-
font-size: .8em;
|
26
|
-
background-color: #F5F6C9;
|
27
|
-
width: 100%;
|
28
|
-
}
|
29
|
-
|
30
|
-
#container note {
|
31
|
-
font-size: .7em;
|
32
|
-
}
|
33
|
-
|
34
|
-
#banner {
|
35
|
-
width: 600px;
|
36
|
-
text-align: center;
|
37
|
-
}
|
38
|
-
|
39
|
-
pre {
|
40
|
-
padding: 10px;
|
41
|
-
}
|
42
|
-
|
43
|
-
.clear {
|
44
|
-
clear: both;
|
45
|
-
}
|
46
|
-
</style>
|
47
|
-
|
48
|
-
<div id="container">
|
49
|
-
<div id="banner">
|
50
|
-
<img src='logo.png' />
|
51
|
-
<h2><em>Classy web-development dressed in a DSL</em></h2>
|
52
|
-
</div>
|
53
|
-
<div class="clear"></div>
|
54
|
-
<div>
|
55
|
-
<div>
|
56
|
-
<p>
|
57
|
-
<strong>Install!</strong><br/>
|
58
|
-
<pre>gem install sinatra -y</pre>
|
59
|
-
</p>
|
60
|
-
<p>
|
61
|
-
<strong>Require!</strong> (any filename you wish)<br/>
|
62
|
-
<pre>
|
63
|
-
# lyrics.rb
|
64
|
-
require 'rubygems'
|
65
|
-
require 'sinatra'</pre>
|
66
|
-
<note>yup.. that's it for a sec</note><br />
|
67
|
-
</p>
|
68
|
-
<p>
|
69
|
-
<strong>Run!</strong><br />
|
70
|
-
<pre>ruby lyrics.rb</pre>
|
71
|
-
</p>
|
72
|
-
<p>
|
73
|
-
<strong>Bask!</strong><br />
|
74
|
-
<pre>http://localhost:4567</pre>
|
75
|
-
</p>
|
76
|
-
<p>
|
77
|
-
<strong>Write!</strong>
|
78
|
-
<pre>
|
79
|
-
get '/' do
|
80
|
-
"Now that's a fine looking dame!"
|
81
|
-
end</pre>
|
82
|
-
</p>
|
83
|
-
<p>
|
84
|
-
<strong>Examples!</strong><br />
|
85
|
-
<pre><a href="http://repo.or.cz/w/sinatra.git?a=tree;f=examples;h=fd7513e49762738ad945adbb2e15bb31528b4207;hb=HEAD">here</a></pre>
|
86
|
-
</p>
|
87
|
-
<p>
|
88
|
-
<strong>Docs!</strong><br />
|
89
|
-
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
90
|
-
</p>
|
91
|
-
<p>
|
92
|
-
<strong>Can you <a href="http://digg.com/programming/Sinatra_Classy_web_development_dressed_in_a_DSL">digg</a> it cats?</strong><br />
|
93
|
-
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
94
|
-
</p>
|
95
|
-
<p>
|
96
|
-
<strong>Contribute!</strong><br />
|
97
|
-
<pre><a href="http://repo.or.cz/w/sinatra.git">using git</a></pre>
|
98
|
-
</p>
|
99
|
-
|
100
|
-
</div>
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
</body>
|
104
|
-
</html>
|
data/site/index.html
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
-
|
4
|
-
<html>
|
5
|
-
<head>
|
6
|
-
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
7
|
-
<title>Sinatra : Classy web-development dressed in a DSL</title>
|
8
|
-
</head>
|
9
|
-
|
10
|
-
<body>
|
11
|
-
<style type="text/css" media="screen">
|
12
|
-
body {
|
13
|
-
background-color: #fff;
|
14
|
-
color: #333;
|
15
|
-
font-size: 0.75em;
|
16
|
-
}
|
17
|
-
|
18
|
-
#container {
|
19
|
-
width: 600px;
|
20
|
-
margin: 0 auto;
|
21
|
-
font-size: 1.5em;
|
22
|
-
}
|
23
|
-
|
24
|
-
#container pre {
|
25
|
-
font-size: .8em;
|
26
|
-
background-color: #F5F6C9;
|
27
|
-
width: 100%;
|
28
|
-
}
|
29
|
-
|
30
|
-
#container note {
|
31
|
-
font-size: .7em;
|
32
|
-
}
|
33
|
-
|
34
|
-
#banner {
|
35
|
-
width: 600px;
|
36
|
-
text-align: center;
|
37
|
-
}
|
38
|
-
|
39
|
-
pre {
|
40
|
-
padding: 10px;
|
41
|
-
}
|
42
|
-
|
43
|
-
.clear {
|
44
|
-
clear: both;
|
45
|
-
}
|
46
|
-
</style>
|
47
|
-
|
48
|
-
<div id="container">
|
49
|
-
<div id="banner">
|
50
|
-
<img src='logo.png' />
|
51
|
-
<h2><em>Classy web-development dressed in a DSL</em></h2>
|
52
|
-
</div>
|
53
|
-
<div class="clear"></div>
|
54
|
-
<div>
|
55
|
-
<div>
|
56
|
-
<p>
|
57
|
-
<strong>Install!</strong><br/>
|
58
|
-
<pre>gem install sinatra -y</pre>
|
59
|
-
</p>
|
60
|
-
<p>
|
61
|
-
<strong>Require!</strong> (any filename you wish)<br/>
|
62
|
-
<pre>
|
63
|
-
# lyrics.rb
|
64
|
-
require 'rubygems'
|
65
|
-
require 'sinatra'</pre>
|
66
|
-
<note>yup.. that's it for a sec</note><br />
|
67
|
-
</p>
|
68
|
-
<p>
|
69
|
-
<strong>Run!</strong><br />
|
70
|
-
<pre>ruby lyrics.rb</pre>
|
71
|
-
</p>
|
72
|
-
<p>
|
73
|
-
<strong>Bask!</strong><br />
|
74
|
-
<pre>http://localhost:4567</pre>
|
75
|
-
</p>
|
76
|
-
<p>
|
77
|
-
<strong>Write!</strong>
|
78
|
-
<pre>
|
79
|
-
get '/' do
|
80
|
-
"Now that's a fine looking dame!"
|
81
|
-
end</pre>
|
82
|
-
</p>
|
83
|
-
<p>
|
84
|
-
<strong>Examples!</strong><br />
|
85
|
-
<pre><a href="http://repo.or.cz/w/sinatra.git?a=tree;f=examples;h=fd7513e49762738ad945adbb2e15bb31528b4207;hb=HEAD">here</a></pre>
|
86
|
-
</p>
|
87
|
-
<p>
|
88
|
-
<strong>Docs!</strong><br />
|
89
|
-
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
90
|
-
</p>
|
91
|
-
<p>
|
92
|
-
<strong>Can you <a href="http://digg.com/programming/Sinatra_Classy_web_development_dressed_in_a_DSL">digg</a> it cats?</strong><br />
|
93
|
-
<pre><a href="http://sinatra.rubyforge.org/doc/">here</a></pre>
|
94
|
-
</p>
|
95
|
-
<p>
|
96
|
-
<strong>Contribute!</strong><br />
|
97
|
-
<pre><a href="http://repo.or.cz/w/sinatra.git">using git</a></pre>
|
98
|
-
</p>
|
99
|
-
|
100
|
-
</div>
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
</body>
|
104
|
-
</html>
|