thin 0.5.3-x86-mswin32-60 → 0.5.4-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of thin might be problematic. Click here for more details.
- data/CHANGELOG +8 -0
- data/benchmark/previous.rb +14 -0
- data/benchmark/simple.rb +3 -38
- data/benchmark/utils.rb +51 -0
- data/bin/thin +1 -1
- data/example/config.ru +9 -2
- data/lib/thin.rb +1 -1
- data/lib/thin/connection.rb +4 -2
- data/lib/thin/response.rb +22 -14
- data/lib/thin/version.rb +2 -2
- data/lib/thin_parser.so +0 -0
- data/spec/response_spec.rb +22 -9
- data/spec/server_spec.rb +8 -3
- metadata +5 -56
- data/doc/rdoc/classes/Process.html +0 -181
- data/doc/rdoc/classes/Rack.html +0 -156
- data/doc/rdoc/classes/Rack/Adapter.html +0 -155
- data/doc/rdoc/classes/Rack/Adapter/Rails.html +0 -289
- data/doc/rdoc/classes/Rack/Adapter/Rails/CGIWrapper.html +0 -359
- data/doc/rdoc/classes/Rack/Handler.html +0 -155
- data/doc/rdoc/classes/Rack/Handler/Thin.html +0 -175
- data/doc/rdoc/classes/Thin.html +0 -164
- data/doc/rdoc/classes/Thin/Cluster.html +0 -399
- data/doc/rdoc/classes/Thin/Connection.html +0 -223
- data/doc/rdoc/classes/Thin/Daemonizable.html +0 -260
- data/doc/rdoc/classes/Thin/Daemonizable/ClassMethods.html +0 -197
- data/doc/rdoc/classes/Thin/Headers.html +0 -238
- data/doc/rdoc/classes/Thin/InvalidRequest.html +0 -144
- data/doc/rdoc/classes/Thin/Logging.html +0 -201
- data/doc/rdoc/classes/Thin/Request.html +0 -231
- data/doc/rdoc/classes/Thin/Response.html +0 -271
- data/doc/rdoc/classes/Thin/Server.html +0 -295
- data/doc/rdoc/classes/Thin/StopServer.html +0 -143
- data/doc/rdoc/created.rid +0 -1
- data/doc/rdoc/files/README.html +0 -226
- data/doc/rdoc/files/bin/thin.html +0 -245
- data/doc/rdoc/files/lib/rack/adapter/rails_rb.html +0 -146
- data/doc/rdoc/files/lib/rack/handler/thin_rb.html +0 -146
- data/doc/rdoc/files/lib/thin/cluster_rb.html +0 -146
- data/doc/rdoc/files/lib/thin/connection_rb.html +0 -145
- data/doc/rdoc/files/lib/thin/daemonizing_rb.html +0 -146
- data/doc/rdoc/files/lib/thin/headers_rb.html +0 -146
- data/doc/rdoc/files/lib/thin/logging_rb.html +0 -146
- data/doc/rdoc/files/lib/thin/request_rb.html +0 -145
- data/doc/rdoc/files/lib/thin/response_rb.html +0 -145
- data/doc/rdoc/files/lib/thin/server_rb.html +0 -145
- data/doc/rdoc/files/lib/thin/statuses_rb.html +0 -145
- data/doc/rdoc/files/lib/thin/version_rb.html +0 -145
- data/doc/rdoc/files/lib/thin_rb.html +0 -152
- data/doc/rdoc/index.html +0 -10
- data/doc/rdoc/logo.gif +0 -0
- data/doc/rdoc/rdoc-style.css +0 -55
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.5.4 Flying Mustard release
|
2
|
+
* Don't read the full body, use direct streaming when sending response.
|
3
|
+
See: Response#each
|
4
|
+
As a result, the Content-Length can not be calculated any more.
|
5
|
+
You have to do set it in your adapter. All frameworks do it anyway.
|
6
|
+
* Add Server response header
|
7
|
+
* Fix --user and --group option not changing daemon process privileges
|
8
|
+
|
1
9
|
== 0.5.3 Purple Yogurt release
|
2
10
|
* win32 pre-compiled gem now available
|
3
11
|
* change rake task configuration to allow win32 gem build
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Benchmark to compare Thin performance against
|
2
|
+
# previous Thin version (the one installed as a gem).
|
3
|
+
#
|
4
|
+
# Run with:
|
5
|
+
#
|
6
|
+
# ruby previous.rb [num of request]
|
7
|
+
#
|
8
|
+
require 'rubygems'
|
9
|
+
require 'rack'
|
10
|
+
require File.dirname(__FILE__) + '/utils'
|
11
|
+
|
12
|
+
request = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
|
13
|
+
|
14
|
+
benchmark %w(current gem), request
|
data/benchmark/simple.rb
CHANGED
@@ -6,43 +6,8 @@
|
|
6
6
|
# ruby simple.rb [num of request]
|
7
7
|
#
|
8
8
|
require File.dirname(__FILE__) + '/../lib/thin'
|
9
|
-
require '
|
9
|
+
require File.dirname(__FILE__) + '/utils'
|
10
10
|
|
11
|
-
|
11
|
+
request = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
|
12
12
|
|
13
|
-
|
14
|
-
server = fork do
|
15
|
-
[STDOUT, STDERR].each { |o| o.reopen "/dev/null" }
|
16
|
-
|
17
|
-
app = Rack::Lobster.new
|
18
|
-
|
19
|
-
if handler_name == 'EMongrel'
|
20
|
-
require 'swiftcore/evented_mongrel'
|
21
|
-
handler_name = 'Mongrel'
|
22
|
-
end
|
23
|
-
handler = Rack::Handler.const_get(handler_name)
|
24
|
-
handler.run app, :Host => '0.0.0.0', :Port => 7000
|
25
|
-
end
|
26
|
-
|
27
|
-
sleep 2
|
28
|
-
|
29
|
-
out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:7000/ 2> /dev/null`
|
30
|
-
|
31
|
-
Process.kill('SIGKILL', server)
|
32
|
-
Process.wait
|
33
|
-
|
34
|
-
if requests = out.match(/^Requests.+?(\d+\.\d+)/)
|
35
|
-
failed = out.match(/^Failed requests.+?(\d+)$/)[1]
|
36
|
-
"#{requests[1].to_s.ljust(9)} #{failed}"
|
37
|
-
else
|
38
|
-
'ERROR'
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
puts 'server request concurrency req/s failures'
|
43
|
-
puts '=' * 53
|
44
|
-
[1, 10, 100].each do |c|
|
45
|
-
%w(WEBrick Mongrel EMongrel Thin).each do |server|
|
46
|
-
puts "#{server.ljust(8)} #{REQUEST} #{c.to_s.ljust(4)} #{run(server, c)}"
|
47
|
-
end
|
48
|
-
end
|
13
|
+
benchmark %w(WEBrick Mongrel EMongrel Thin), request
|
data/benchmark/utils.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rack/lobster'
|
2
|
+
|
3
|
+
def run(handler_name, n=1000, c=1)
|
4
|
+
server = fork do
|
5
|
+
[STDOUT, STDERR].each { |o| o.reopen "/dev/null" }
|
6
|
+
|
7
|
+
case handler_name
|
8
|
+
when 'EMongrel'
|
9
|
+
require 'swiftcore/evented_mongrel'
|
10
|
+
handler_name = 'Mongrel'
|
11
|
+
|
12
|
+
when 'gem' # Load the current Thin gem
|
13
|
+
require 'thin'
|
14
|
+
handler_name = 'Thin'
|
15
|
+
|
16
|
+
when 'current' # Load the current Thin version under /lib
|
17
|
+
require File.dirname(__FILE__) + '/../lib/thin'
|
18
|
+
handler_name = 'Thin'
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
app = Rack::Lobster.new
|
23
|
+
|
24
|
+
handler = Rack::Handler.const_get(handler_name)
|
25
|
+
handler.run app, :Host => '0.0.0.0', :Port => 7000
|
26
|
+
end
|
27
|
+
|
28
|
+
sleep 2
|
29
|
+
|
30
|
+
out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:7000/ 2> /dev/null`
|
31
|
+
|
32
|
+
Process.kill('SIGKILL', server)
|
33
|
+
Process.wait
|
34
|
+
|
35
|
+
if requests = out.match(/^Requests.+?(\d+\.\d+)/)
|
36
|
+
failed = out.match(/^Failed requests.+?(\d+)$/)[1]
|
37
|
+
"#{requests[1].to_s.ljust(9)} #{failed}"
|
38
|
+
else
|
39
|
+
'ERROR'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def benchmark(servers, request, concurrency_levels=[1, 10, 100])
|
44
|
+
puts 'server request concurrency req/s failures'
|
45
|
+
puts '=' * 53
|
46
|
+
concurrency_levels.each do |c|
|
47
|
+
servers.each do |server|
|
48
|
+
puts "#{server.ljust(8)} #{request} #{c.to_s.ljust(4)} #{run(server, request, c)}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/bin/thin
CHANGED
@@ -73,8 +73,8 @@ def start(options)
|
|
73
73
|
server.timeout = options[:timeout]
|
74
74
|
|
75
75
|
if options[:daemonize]
|
76
|
-
server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
|
77
76
|
server.daemonize
|
77
|
+
server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
|
78
78
|
end
|
79
79
|
|
80
80
|
server.app = Rack::Adapter::Rails.new(options.merge(:root => options[:chdir]))
|
data/example/config.ru
CHANGED
@@ -4,6 +4,13 @@
|
|
4
4
|
# http://rack.rubyforge.org/doc/classes/Rack/Builder.html
|
5
5
|
|
6
6
|
require File.dirname(__FILE__) + '/../lib/thin'
|
7
|
-
require 'rack/lobster'
|
8
7
|
|
9
|
-
|
8
|
+
app = proc do |env|
|
9
|
+
[
|
10
|
+
200,
|
11
|
+
{'Content-Type' => 'text/html'},
|
12
|
+
['hi!']
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
run app
|
data/lib/thin.rb
CHANGED
data/lib/thin/connection.rb
CHANGED
@@ -30,8 +30,10 @@ module Thin
|
|
30
30
|
@response.status, @response.headers, @response.body = @app.call(env)
|
31
31
|
|
32
32
|
# Send the response
|
33
|
-
|
34
|
-
|
33
|
+
@response.each do |chunk|
|
34
|
+
trace { chunk }
|
35
|
+
send_data chunk
|
36
|
+
end
|
35
37
|
|
36
38
|
close_connection_after_writing
|
37
39
|
|
data/lib/thin/response.rb
CHANGED
@@ -1,25 +1,35 @@
|
|
1
1
|
module Thin
|
2
2
|
# A response sent to the client.
|
3
3
|
class Response
|
4
|
-
CONTENT_LENGTH = 'Content-Length'.freeze
|
5
4
|
CONNECTION = 'Connection'.freeze
|
5
|
+
SERVER = 'Server'.freeze
|
6
6
|
CLOSE = 'close'.freeze
|
7
7
|
|
8
|
+
# Status code
|
8
9
|
attr_accessor :status
|
9
|
-
|
10
|
+
|
11
|
+
# Response body, must respond to +each+.
|
12
|
+
attr_accessor :body
|
13
|
+
|
14
|
+
# Headers key-value hash
|
15
|
+
attr_reader :headers
|
10
16
|
|
11
17
|
def initialize
|
12
18
|
@headers = Headers.new
|
13
|
-
@body = StringIO.new
|
14
19
|
@status = 200
|
15
20
|
end
|
16
21
|
|
22
|
+
# String representation of the headers
|
23
|
+
# to be sent in the response.
|
17
24
|
def headers_output
|
18
|
-
@headers[CONTENT_LENGTH] = @body.size
|
19
25
|
@headers[CONNECTION] = CLOSE
|
26
|
+
@headers[SERVER] = Thin::SERVER
|
27
|
+
|
20
28
|
@headers.to_s
|
21
29
|
end
|
22
30
|
|
31
|
+
# Top header of the response,
|
32
|
+
# containing the status code and response headers.
|
23
33
|
def head
|
24
34
|
"HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status.to_i]}\r\n#{headers_output}\r\n"
|
25
35
|
end
|
@@ -30,19 +40,17 @@ module Thin
|
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
33
|
-
|
34
|
-
stream.each do |part|
|
35
|
-
@body << part
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
43
|
+
# Close any resource used by the response
|
39
44
|
def close
|
40
|
-
@body.close
|
45
|
+
@body.close if @body.respond_to?(:close)
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
head
|
48
|
+
# Yields each chunk of the response
|
49
|
+
def each
|
50
|
+
yield head
|
51
|
+
@body.each do |chunk|
|
52
|
+
yield chunk
|
53
|
+
end
|
46
54
|
end
|
47
55
|
end
|
48
56
|
end
|
data/lib/thin/version.rb
CHANGED
data/lib/thin_parser.so
CHANGED
Binary file
|
data/spec/response_spec.rb
CHANGED
@@ -4,21 +4,28 @@ describe Response do
|
|
4
4
|
before do
|
5
5
|
@response = Response.new
|
6
6
|
@response.headers['Content-Type'] = 'text/html'
|
7
|
+
@response.headers['Content-Length'] = '0'
|
8
|
+
@response.body = ''
|
7
9
|
end
|
8
10
|
|
9
11
|
it 'should output headers' do
|
10
|
-
@response.headers_output.should
|
12
|
+
@response.headers_output.should include("Content-Type: text/html", "Content-Length: 0", "Connection: close")
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should include server name header' do
|
16
|
+
@response.headers_output.should include("Server: thin")
|
11
17
|
end
|
12
18
|
|
13
19
|
it 'should output head' do
|
14
|
-
@response.head.should
|
20
|
+
@response.head.should include("HTTP/1.1 200 OK", "Content-Type: text/html", "Content-Length: 0",
|
21
|
+
"Connection: close", "\r\n\r\n")
|
15
22
|
end
|
16
23
|
|
17
24
|
it 'should allow duplicates in headers' do
|
18
25
|
@response.headers['Set-Cookie'] = 'mium=7'
|
19
26
|
@response.headers['Set-Cookie'] = 'hi=there'
|
20
27
|
|
21
|
-
@response.head.should
|
28
|
+
@response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
|
22
29
|
end
|
23
30
|
|
24
31
|
it 'should parse simple header values' do
|
@@ -26,7 +33,7 @@ describe Response do
|
|
26
33
|
'Host' => 'localhost'
|
27
34
|
}
|
28
35
|
|
29
|
-
@response.head.should
|
36
|
+
@response.head.should include("Host: localhost")
|
30
37
|
end
|
31
38
|
|
32
39
|
it 'should parse multiline header values in several headers' do
|
@@ -34,16 +41,18 @@ describe Response do
|
|
34
41
|
'Set-Cookie' => "mium=7\nhi=there"
|
35
42
|
}
|
36
43
|
|
37
|
-
@response.head.should
|
44
|
+
@response.head.should include("Set-Cookie: mium=7", "Set-Cookie: hi=there")
|
38
45
|
end
|
39
46
|
|
40
47
|
it 'should output body' do
|
41
|
-
@response.body
|
48
|
+
@response.body = '<html></html>'
|
42
49
|
|
43
|
-
|
50
|
+
out = ''
|
51
|
+
@response.each { |l| out << l }
|
52
|
+
out.should include("\r\n\r\n<html></html>")
|
44
53
|
end
|
45
54
|
|
46
|
-
it "should be faster then #{max_parsing_time = 0.
|
55
|
+
it "should be faster then #{max_parsing_time = 0.07} ms" do
|
47
56
|
@response.body << <<-EOS
|
48
57
|
<html><head><title>Dir listing</title></head>
|
49
58
|
<body><h1>Listing stuff</h1><ul>
|
@@ -51,6 +60,10 @@ describe Response do
|
|
51
60
|
</ul></body></html>
|
52
61
|
EOS
|
53
62
|
|
54
|
-
proc { @response.
|
63
|
+
proc { @response.each { |l| l } }.should be_faster_then(max_parsing_time)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should be closeable" do
|
67
|
+
@response.close
|
55
68
|
end
|
56
69
|
end
|
data/spec/server_spec.rb
CHANGED
@@ -5,8 +5,10 @@ require 'socket'
|
|
5
5
|
describe Server do
|
6
6
|
before do
|
7
7
|
app = proc do |env|
|
8
|
-
body =
|
9
|
-
|
8
|
+
body = ''
|
9
|
+
body << env['QUERY_STRING'].to_s
|
10
|
+
body << env['rack.input'].read.to_s
|
11
|
+
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
|
10
12
|
end
|
11
13
|
server = Thin::Server.new('0.0.0.0', 3333, app)
|
12
14
|
server.timeout = 3
|
@@ -24,7 +26,10 @@ describe Server do
|
|
24
26
|
end
|
25
27
|
|
26
28
|
it 'should GET from TCPSocket' do
|
27
|
-
raw('0.0.0.0', 3333, "GET /?this HTTP/1.1\r\n\r\n").
|
29
|
+
raw('0.0.0.0', 3333, "GET /?this HTTP/1.1\r\n\r\n").
|
30
|
+
should include("HTTP/1.1 200 OK",
|
31
|
+
"Content-Type: text/html", "Content-Length: 4",
|
32
|
+
"Connection: close", "\r\n\r\nthis")
|
28
33
|
end
|
29
34
|
|
30
35
|
it 'should return empty string on incomplete headers' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: x86-mswin32-60
|
6
6
|
authors:
|
7
7
|
- Marc-Andre Cournoyer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-01-
|
12
|
+
date: 2008-01-19 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -43,62 +43,11 @@ files:
|
|
43
43
|
- CHANGELOG
|
44
44
|
- README
|
45
45
|
- Rakefile
|
46
|
+
- benchmark/previous.rb
|
46
47
|
- benchmark/simple.rb
|
48
|
+
- benchmark/utils.rb
|
47
49
|
- bin/thin
|
48
50
|
- doc/benchmarks.txt
|
49
|
-
- doc/rdoc
|
50
|
-
- doc/rdoc/classes
|
51
|
-
- doc/rdoc/classes/Process.html
|
52
|
-
- doc/rdoc/classes/Rack
|
53
|
-
- doc/rdoc/classes/Rack/Adapter
|
54
|
-
- doc/rdoc/classes/Rack/Adapter/Rails
|
55
|
-
- doc/rdoc/classes/Rack/Adapter/Rails/CGIWrapper.html
|
56
|
-
- doc/rdoc/classes/Rack/Adapter/Rails.html
|
57
|
-
- doc/rdoc/classes/Rack/Adapter.html
|
58
|
-
- doc/rdoc/classes/Rack/Handler
|
59
|
-
- doc/rdoc/classes/Rack/Handler/Thin.html
|
60
|
-
- doc/rdoc/classes/Rack/Handler.html
|
61
|
-
- doc/rdoc/classes/Rack.html
|
62
|
-
- doc/rdoc/classes/Thin
|
63
|
-
- doc/rdoc/classes/Thin/Cluster.html
|
64
|
-
- doc/rdoc/classes/Thin/Connection.html
|
65
|
-
- doc/rdoc/classes/Thin/Daemonizable
|
66
|
-
- doc/rdoc/classes/Thin/Daemonizable/ClassMethods.html
|
67
|
-
- doc/rdoc/classes/Thin/Daemonizable.html
|
68
|
-
- doc/rdoc/classes/Thin/Headers.html
|
69
|
-
- doc/rdoc/classes/Thin/InvalidRequest.html
|
70
|
-
- doc/rdoc/classes/Thin/Logging.html
|
71
|
-
- doc/rdoc/classes/Thin/Request.html
|
72
|
-
- doc/rdoc/classes/Thin/Response.html
|
73
|
-
- doc/rdoc/classes/Thin/Server.html
|
74
|
-
- doc/rdoc/classes/Thin/StopServer.html
|
75
|
-
- doc/rdoc/classes/Thin.html
|
76
|
-
- doc/rdoc/created.rid
|
77
|
-
- doc/rdoc/files
|
78
|
-
- doc/rdoc/files/bin
|
79
|
-
- doc/rdoc/files/bin/thin.html
|
80
|
-
- doc/rdoc/files/lib
|
81
|
-
- doc/rdoc/files/lib/rack
|
82
|
-
- doc/rdoc/files/lib/rack/adapter
|
83
|
-
- doc/rdoc/files/lib/rack/adapter/rails_rb.html
|
84
|
-
- doc/rdoc/files/lib/rack/handler
|
85
|
-
- doc/rdoc/files/lib/rack/handler/thin_rb.html
|
86
|
-
- doc/rdoc/files/lib/thin
|
87
|
-
- doc/rdoc/files/lib/thin/cluster_rb.html
|
88
|
-
- doc/rdoc/files/lib/thin/connection_rb.html
|
89
|
-
- doc/rdoc/files/lib/thin/daemonizing_rb.html
|
90
|
-
- doc/rdoc/files/lib/thin/headers_rb.html
|
91
|
-
- doc/rdoc/files/lib/thin/logging_rb.html
|
92
|
-
- doc/rdoc/files/lib/thin/request_rb.html
|
93
|
-
- doc/rdoc/files/lib/thin/response_rb.html
|
94
|
-
- doc/rdoc/files/lib/thin/server_rb.html
|
95
|
-
- doc/rdoc/files/lib/thin/statuses_rb.html
|
96
|
-
- doc/rdoc/files/lib/thin/version_rb.html
|
97
|
-
- doc/rdoc/files/lib/thin_rb.html
|
98
|
-
- doc/rdoc/files/README.html
|
99
|
-
- doc/rdoc/index.html
|
100
|
-
- doc/rdoc/logo.gif
|
101
|
-
- doc/rdoc/rdoc-style.css
|
102
51
|
- example/config.ru
|
103
52
|
- example/thin.god
|
104
53
|
- lib/rack
|
@@ -118,6 +67,7 @@ files:
|
|
118
67
|
- lib/thin/statuses.rb
|
119
68
|
- lib/thin/version.rb
|
120
69
|
- lib/thin.rb
|
70
|
+
- lib/thin_parser.so
|
121
71
|
- spec/cluster_spec.rb
|
122
72
|
- spec/daemonizing_spec.rb
|
123
73
|
- spec/headers_spec.rb
|
@@ -188,7 +138,6 @@ files:
|
|
188
138
|
- ext/thin_parser/extconf.rb
|
189
139
|
- ext/thin_parser/common.rl
|
190
140
|
- ext/thin_parser/parser.rl
|
191
|
-
- lib/thin_parser.so
|
192
141
|
has_rdoc: false
|
193
142
|
homepage: http://code.macournoyer.com/thin/
|
194
143
|
post_install_message:
|