vintage 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -0
- data/app_generators/vintage_application/templates/index.erb +2 -2
- data/bin/vintage +14 -1
- data/config/hoe.rb +2 -3
- data/lib/vintage/errors.rb +26 -46
- data/lib/vintage/handler.rb +36 -53
- data/lib/vintage/request_context.rb +43 -28
- data/lib/vintage/server.rb +35 -6
- data/lib/vintage/version.rb +1 -1
- metadata +14 -6
data/History.txt
CHANGED
@@ -16,8 +16,8 @@
|
|
16
16
|
<ul>
|
17
17
|
<li>Remote IP: <%= request.remote_ip %></li>
|
18
18
|
<li>Referer: <%= request.referer %></li>
|
19
|
-
<li>Requested URI: <%= request.
|
20
|
-
<li>Request method: <%= request.
|
19
|
+
<li>Requested URI: <%= request.url %></li>
|
20
|
+
<li>Request method: <%= request.request_method %></li>
|
21
21
|
<li>User agent: <%= request.user_agent %></li>
|
22
22
|
<li>Query string: <%= request.query_string %></li>
|
23
23
|
<li>Parameters: <%= request.params == {} ? "None" : request.params.to_a.map{|k,v| "#{k} = #{v}"}.join(", ") %></li>
|
data/bin/vintage
CHANGED
@@ -19,7 +19,8 @@ OPTIONS = {
|
|
19
19
|
:config => 'configuration.yml',
|
20
20
|
:templates => 'erb',
|
21
21
|
:mount => '/',
|
22
|
-
:root => 'index'
|
22
|
+
:root => 'index',
|
23
|
+
:server => 'mongrel'
|
23
24
|
}
|
24
25
|
MANDATORY_OPTIONS = %w( )
|
25
26
|
|
@@ -33,7 +34,12 @@ a new project is generated. Otherwise, Vintage will start serving
|
|
33
34
|
given the defaults and/or any provided options.
|
34
35
|
|
35
36
|
Usage: #{File.basename($0)} [options]
|
37
|
+
|
38
|
+
To generate an application:
|
36
39
|
#{File.basename($0)} [project name]
|
40
|
+
|
41
|
+
To start your application:
|
42
|
+
#{File.basename($0)} start
|
37
43
|
|
38
44
|
Options are:
|
39
45
|
BANNER
|
@@ -56,6 +62,9 @@ BANNER
|
|
56
62
|
opts.on("-r", "--root=template", String,
|
57
63
|
"The template to render at the root URL",
|
58
64
|
"Default: index") { |OPTIONS[:root]| }
|
65
|
+
opts.on("-s", "--server=server", String,
|
66
|
+
"The server daemon to use (can be mongrel, webrick, cgi, or fastcgi)",
|
67
|
+
"Default: mongrel") { |OPTIONS[:server]| }
|
59
68
|
opts.on("-h", "--help",
|
60
69
|
"Show this help message.") { puts opts; exit }
|
61
70
|
opts.parse!(ARGV)
|
@@ -65,6 +74,10 @@ if ARGV.empty?
|
|
65
74
|
puts parser
|
66
75
|
puts
|
67
76
|
elsif ARGV[0] == "start"
|
77
|
+
if OPTIONS[:server] == 'swift'
|
78
|
+
require 'swiftcore/swiftiplied_mongrel'
|
79
|
+
end
|
80
|
+
|
68
81
|
OPTIONS.merge!(YAML::load_file(OPTIONS[:config])) if File.exists?(OPTIONS[:config])
|
69
82
|
Vintage::Server.run(OPTIONS)
|
70
83
|
else
|
data/config/hoe.rb
CHANGED
@@ -2,7 +2,7 @@ require 'vintage/version'
|
|
2
2
|
|
3
3
|
AUTHOR = 'Jeremy McAnally' # can also be an array of Authors
|
4
4
|
EMAIL = "jeremymcanally@gmail.com"
|
5
|
-
DESCRIPTION = "
|
5
|
+
DESCRIPTION = "The super slim web framework"
|
6
6
|
GEM_NAME = 'vintage' # what ppl will type to install your gem
|
7
7
|
RUBYFORGE_PROJECT = 'vintage' # The unix name for your project
|
8
8
|
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
@@ -32,7 +32,6 @@ REV = nil
|
|
32
32
|
# UNCOMMENT IF REQUIRED:
|
33
33
|
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
34
|
VERS = Vintage::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
-
VERSION = VERS
|
36
35
|
RDOC_OPTS = ['--quiet', '--title', 'vintage documentation',
|
37
36
|
"--opname", "index.html",
|
38
37
|
"--line-numbers",
|
@@ -60,7 +59,7 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
|
60
59
|
|
61
60
|
# == Optional
|
62
61
|
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
63
|
-
|
62
|
+
p.extra_deps = [['rubigen', '>= 0.0.0']] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
64
63
|
|
65
64
|
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
66
65
|
|
data/lib/vintage/errors.rb
CHANGED
@@ -2,74 +2,54 @@ module Vintage
|
|
2
2
|
# A class to render the default error pages. These will
|
3
3
|
# not render if error pages are specified in the configuration.
|
4
4
|
class ErrorReporter
|
5
|
+
# CSS shared among error templates
|
6
|
+
CSS = """
|
7
|
+
body { margin: 0px; padding: 0px; font-family: sans-serif; }
|
8
|
+
h1 { background: #3E2B09; padding: 45px 10px 10px 10px; color: #6F5E3C; border: 0px; border-bottom: 2px solid #1C0907; margin: 0px; }
|
9
|
+
h1 span.error { text-shadow: 0.1em 0.1em #333; color: white; }
|
10
|
+
h2 { margin: 0px; padding: 5px 5px 10px 10px; font-size: 14pt !important; }
|
11
|
+
h2 span.where { color: #999; }
|
12
|
+
h3 { margin: 0px; padding: 10px 10px; color: #999;}
|
13
|
+
ul { margin: 0px; }
|
14
|
+
li { margin: 0px; padding: 0px 30px; }
|
15
|
+
pre { padding: 0 30px; margin: 0px; }
|
16
|
+
"""
|
17
|
+
|
5
18
|
# Standard template to render for a <tt>500 Internal Server Error</tt>
|
6
19
|
def self.internal_error(error, params)
|
7
|
-
"""
|
8
|
-
<html>
|
9
|
-
<head>
|
10
|
-
<title>Vintage Error: 500 Internal Server Error</title>
|
11
|
-
<style>
|
12
|
-
body { margin: 0px; padding: 0px; font-family: sans-serif; }
|
13
|
-
h1 { background: #3E2B09; padding: 45px 10px 10px 10px; color: #6F5E3C; border: 0px; border-bottom: 2px solid #1C0907; margin: 0px; }
|
14
|
-
h1 span.error { text-shadow: 0.1em 0.1em #333; color: white; }
|
15
|
-
h2 { margin: 0px; padding: 5px 5px 10px 10px; font-size: 14pt !important; }
|
16
|
-
h2 span.where { color: #999; }
|
17
|
-
h3 { margin: 0px; padding: 10px 10px; color: #999;}
|
18
|
-
ul { margin: 0px; }
|
19
|
-
li { margin: 0px; padding: 0px 30px; }
|
20
|
-
pre { padding: 0 30px; margin: 0px; }
|
21
|
-
</style>
|
22
|
-
</head>
|
23
|
-
|
24
|
-
<body>
|
25
|
-
<h1><span class='error'>#{error.class}</span> 500 Internal Server Error</h1>
|
26
|
-
<h2>#{error.message} <span class='where'>at #{error.backtrace[0]}</span></h2>
|
27
|
-
<div>
|
28
|
-
<h3>Parameters</h3>
|
29
|
-
<ul>
|
30
|
-
#{params == {} ? "None" : params.to_a.map{|key, val| "<li><b>" + key.to_s + "<b> = " + val.to_s + "</li>"}.join("\n") }
|
31
|
-
</ul>
|
32
|
-
<br />
|
33
|
-
<h3>Backtrace</h3>
|
34
|
-
<pre>#{error.backtrace.join("\n")}</pre>
|
35
|
-
</div>
|
36
|
-
</body>
|
37
|
-
</html>
|
38
|
-
|
39
|
-
"""
|
20
|
+
error_page("500 Internal Server Error", error.class.to_s, "500 Internal Server Error", error.message.to_s, "at #{error.backtrace[0]}", "<h3>Backtrace</h3>\n\t<pre>#{error.backtrace.join('\n')}</pre>", params)
|
40
21
|
end
|
41
22
|
|
42
23
|
# Standard template to render for a <tt>404 Page Not Found</tt> error
|
43
24
|
def self.not_found(url, remote_ip, params)
|
25
|
+
error_page("404 Not Found", "Page Not Found", "404 Not Found", "Request for #{url}", "from #{remote_ip}", params)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
# Standard template to render for a <tt>404 Page Not Found</tt> error
|
30
|
+
def self.error_page(title, h1_primary, h1_secondary, h2_primary, h2_secondary, extra_content = "", params = {})
|
44
31
|
"""
|
45
32
|
<html>
|
46
33
|
<head>
|
47
|
-
<title>Vintage Error:
|
34
|
+
<title>Vintage Error: #{title}</title>
|
48
35
|
<style>
|
49
|
-
|
50
|
-
h1 { background: #3E2B09; padding: 45px 10px 10px 10px; color: #6F5E3C; border: 0px; border-bottom: 2px solid #1C0907; margin: 0px; }
|
51
|
-
h1 span.error { text-shadow: 0.1em 0.1em #333; color: white; }
|
52
|
-
h2 { margin: 0px; padding: 5px 5px 10px 10px; font-size: 14pt !important; }
|
53
|
-
h2 span.where { color: #999; }
|
54
|
-
h3 { margin: 0px; padding: 10px 10px; color: #999;}
|
55
|
-
ul { margin: 0px; }
|
56
|
-
li { margin: 0px; padding: 0px 30px; }
|
57
|
-
pre { padding: 0 30px; margin: 0px; }
|
36
|
+
#{CSS}
|
58
37
|
</style>
|
59
38
|
</head>
|
60
39
|
|
61
40
|
<body>
|
62
|
-
<h1><span class='error'
|
63
|
-
<h2
|
41
|
+
<h1><span class='error'>#{h1_primary}</span> #{h1_secondary}</h1>
|
42
|
+
<h2>#{h2_primary} <span class='where'>#{h2_secondary}</span></h2>
|
64
43
|
<div>
|
65
44
|
<h3>Parameters</h3>
|
66
45
|
<ul>
|
67
46
|
#{params == {} ? "None" : params.to_a.map{|key, val| "<li><b>" + key.to_s + "<b> = " + val.to_s + "</li>"}.join("\n") }
|
68
47
|
</ul>
|
48
|
+
<br />
|
49
|
+
#{extra_content}
|
69
50
|
</div>
|
70
51
|
</body>
|
71
52
|
</html>
|
72
|
-
|
73
53
|
"""
|
74
54
|
end
|
75
55
|
end
|
data/lib/vintage/handler.rb
CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'mongrel'
|
3
3
|
require 'erubis'
|
4
4
|
require 'erb'
|
5
|
+
|
5
6
|
require 'mime/types'
|
6
7
|
|
7
8
|
require 'vintage/renderer'
|
@@ -10,13 +11,13 @@ require 'vintage/errors'
|
|
10
11
|
|
11
12
|
module Vintage
|
12
13
|
# The Mongrel HTTP Handler. Handles all operations with requests.
|
13
|
-
class Handler
|
14
|
+
class Handler
|
14
15
|
def initialize(options)
|
15
16
|
# Make our configuration options avialable to the handler
|
16
17
|
@options = options
|
17
18
|
|
18
19
|
# Setup a DirHandler for sending static files securely
|
19
|
-
@static_handler =
|
20
|
+
@static_handler = Rack::File.new(@options[:static_path])
|
20
21
|
|
21
22
|
# Inject our helpers in the RequestContext class to make them
|
22
23
|
# available on each request.
|
@@ -24,19 +25,17 @@ module Vintage
|
|
24
25
|
end
|
25
26
|
|
26
27
|
# Main request handler for Mongrel.
|
27
|
-
def
|
28
|
-
# Parse params into a nice Hash
|
29
|
-
handle_params(request.params["QUERY_STRING"])
|
30
|
-
|
31
|
-
# Setup our request's path
|
32
|
-
@request_path = request.params["PATH_INFO"]
|
33
|
-
|
28
|
+
def call(env)
|
34
29
|
# Setup up the request's context (response and request information)
|
35
|
-
|
36
|
-
|
30
|
+
request = Rack::Request.new(env)
|
31
|
+
context = RequestContext.new(request)
|
32
|
+
|
33
|
+
# Setup our request's path
|
34
|
+
@request_path = request.path_info
|
35
|
+
|
37
36
|
# Initialize the buffered log entry
|
38
37
|
log_entry = ""
|
39
|
-
log_entry << "*** request for [#{request.
|
38
|
+
log_entry << "*** request for [#{request.url}] from [#{env['REMOTE_ADDR']}]\n"
|
40
39
|
|
41
40
|
# If it's a root request, we want to render the template we configured
|
42
41
|
@request_path = @options[:root] if @request_path == '/'
|
@@ -53,64 +52,48 @@ module Vintage
|
|
53
52
|
# Is it a static file?
|
54
53
|
if (@request_path =~ /\.(.*)$/)
|
55
54
|
# Yes? Let our static handler take it away!
|
56
|
-
@static_handler.
|
55
|
+
@static_handler.call(env)
|
57
56
|
else
|
58
57
|
# No! Render a template...
|
59
58
|
content = Renderer.send(@options[:templates].to_sym, File.open("#{@options[:path]}#{@request_path}.#{@options[:templates]}", "r").read, context)
|
60
|
-
end
|
61
59
|
|
62
|
-
# Render (if response is 200) or redirect
|
63
|
-
response.start(context.response.code) do |head, out|
|
64
|
-
# Add any custom headers (e.g., from redirect_to)
|
65
|
-
context.response.headers.each do |k,v|
|
66
|
-
head[k] = v
|
67
|
-
end
|
68
|
-
|
69
60
|
# Set the content type if we're responding with a render
|
70
|
-
|
61
|
+
context.response.headers["Content-Type"] = "text/html" if context.response.code == 200
|
62
|
+
response = Rack::Response.new(content, context.response.code, {}.merge!(context.response.headers))
|
63
|
+
|
64
|
+
# Render (if response is 200) or redirect
|
65
|
+
# Set cookies
|
66
|
+
if context.response.cookies != {}
|
67
|
+
context.response.cookies.each do |key, value|
|
68
|
+
response.set_cookie(key, value)
|
69
|
+
end
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
out.write content
|
72
|
+
response.finish
|
74
73
|
end
|
75
74
|
else
|
76
75
|
# Page not found
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
out.write @options[:errors] && @options[:errors][:not_found] ? Renderer.send(@options[:templates].to_sym, File.open("#{@options[:path]}#{@options[:errors][:not_found]}.#{@options[:templates]}", "r").read, context) : ErrorReporter.not_found(@request_path, request.params['REMOTE_ADDR'], @params)
|
85
|
-
end
|
76
|
+
# Log the 404
|
77
|
+
log_entry << " response: [404]\n"
|
78
|
+
log_entry << " rendering 'page not found'\n"
|
79
|
+
|
80
|
+
# Send back the default or a custom template
|
81
|
+
content = @options[:errors] && @options[:errors][:not_found] ? Renderer.send(@options[:templates].to_sym, File.open("#{@options[:path]}#{@options[:errors][:not_found]}.#{@options[:templates]}", "r").read, context) : ErrorReporter.not_found(@request_path, request.params['REMOTE_ADDR'], @params)
|
82
|
+
[context.response.code, {}.merge!(context.response.headers), content]
|
86
83
|
end
|
87
84
|
rescue StandardError => err
|
88
85
|
# OOPS! Something broke.
|
89
|
-
response.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
86
|
+
context.response.code = 500
|
87
|
+
|
88
|
+
# Log it and send an error page...
|
89
|
+
log_entry << "\t!!! [500] #{err}\n"
|
90
|
+
content = @options[:errors] && @options[:errors][:internal_error] ? Renderer.send(@options[:templates].to_sym, File.open("#{@options[:path]}#{@options[:errors][:internal_error]}.#{@options[:templates]}", "r").read, context) : ErrorReporter.internal_error(err, @params)
|
91
|
+
[context.response.code, {}.merge!(context.response.headers), content]
|
95
92
|
ensure
|
96
93
|
# After every request push the buffered log entry out to the logger
|
97
94
|
Log.enter log_entry.to_s + "\n"
|
98
95
|
end
|
99
96
|
|
100
|
-
# Parse HTTP params into a +Hash+.
|
101
|
-
def handle_params(params)
|
102
|
-
@params = {}
|
103
|
-
|
104
|
-
unless params == nil || params == ''
|
105
|
-
# Split the query string and hack it up
|
106
|
-
params.split('&').each do |param|
|
107
|
-
key, val = param.split('=')
|
108
|
-
|
109
|
-
@params[key.to_sym] = val
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
97
|
# Inject the default helpers and helpers from the
|
115
98
|
# +helpers/+ directory (if available) into the
|
116
99
|
# RequestContext class.
|
@@ -1,37 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/file'
|
3
|
+
|
4
|
+
module Vintage
|
5
|
+
# Class that encapsulates the response's headers and
|
6
|
+
# response code.
|
7
|
+
class Response
|
8
|
+
attr_accessor :headers, :code, :cookies
|
4
9
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
self.user_agent = request.params['HTTP_USER_AGENT']
|
11
|
-
self.query_string = request.params['QUERY_STRING']
|
12
|
-
self.params = param_hash
|
10
|
+
def initialize
|
11
|
+
self.headers = {}
|
12
|
+
self.code = 200
|
13
|
+
self.cookies = {}
|
14
|
+
end
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
17
|
+
# A class that creates a context for template
|
18
|
+
# rendering. Helpers are mixed in here to give
|
19
|
+
# templates access to them.
|
20
|
+
class RequestContext
|
21
|
+
attr_accessor :request, :response
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
def initialize(incoming_request)
|
24
|
+
self.request = incoming_request
|
25
|
+
self.response = Vintage::Response.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def cookies
|
29
|
+
self.request.cookies
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_cookie(key, val)
|
33
|
+
self.response.cookies[key] = val
|
34
|
+
end
|
35
|
+
|
36
|
+
# def session
|
37
|
+
# @env["rack.session"]
|
38
|
+
# end
|
24
39
|
end
|
25
40
|
end
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
42
|
+
module Rack
|
43
|
+
class Request
|
44
|
+
def remote_ip
|
45
|
+
@env['REMOTE_ADDR']
|
46
|
+
end
|
47
|
+
|
48
|
+
def user_agent
|
49
|
+
@env['HTTP_USER_AGENT']
|
50
|
+
end
|
36
51
|
end
|
37
52
|
end
|
data/lib/vintage/server.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'mongrel'
|
3
2
|
|
4
3
|
require 'erubis'
|
5
4
|
|
@@ -7,6 +6,15 @@ require 'vintage/version'
|
|
7
6
|
require 'vintage/log'
|
8
7
|
require 'vintage/helpers'
|
9
8
|
|
9
|
+
begin
|
10
|
+
require 'swiftcore/evented_mongrel'
|
11
|
+
rescue
|
12
|
+
# Don't have it? No problem!
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'rack'
|
16
|
+
require 'rack/file'
|
17
|
+
|
10
18
|
begin
|
11
19
|
Dir.entries("helpers/").select{|entry| entry =~ /(.*).rb$/}.each do |helper_file|
|
12
20
|
Vintage::Helpers.module_eval(File.open(helper_file).read)
|
@@ -22,11 +30,32 @@ module Vintage
|
|
22
30
|
Log.enter "- vintage version #{VERSION::STRING}"
|
23
31
|
Log.enter "\t starting server on port #{options[:port]}"
|
24
32
|
Log.enter
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
|
34
|
+
application = Handler.new(options)
|
35
|
+
|
36
|
+
server = Rack::Handler::Mongrel
|
37
|
+
|
38
|
+
case options[:server]
|
39
|
+
when "mongrel"
|
40
|
+
server = Rack::Handler::Mongrel
|
41
|
+
when "thin"
|
42
|
+
begin
|
43
|
+
require 'thin'
|
44
|
+
server = Rack::Handler::Thin
|
45
|
+
rescue LoadError
|
46
|
+
puts "You don't have Thin installed!"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
when "webrick"
|
50
|
+
server = Rack::Handler::WEBrick
|
51
|
+
when "cgi"
|
52
|
+
server = Rack::Handler::CGI
|
53
|
+
when "fastcgi"
|
54
|
+
server = Rack::Handler::FastCGI
|
55
|
+
end
|
56
|
+
|
57
|
+
server.run application, {:Port => options[:port], :Host => "0.0.0.0", :AccessLog => []}
|
58
|
+
rescue Interrupt, Mongrel::StopServer
|
30
59
|
Log.enter
|
31
60
|
Log.enter "- interrupt signal caught"
|
32
61
|
Log.enter "\tshutting server down"
|
data/lib/vintage/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vintage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy McAnally
|
@@ -9,11 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-01-
|
12
|
+
date: 2008-01-11 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rubigen
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.0
|
23
|
+
version:
|
24
|
+
description: The super slim web framework
|
17
25
|
email: jeremymcanally@gmail.com
|
18
26
|
executables:
|
19
27
|
- vintage
|
@@ -84,7 +92,7 @@ rubyforge_project: vintage
|
|
84
92
|
rubygems_version: 1.0.1
|
85
93
|
signing_key:
|
86
94
|
specification_version: 2
|
87
|
-
summary:
|
95
|
+
summary: The super slim web framework
|
88
96
|
test_files:
|
89
97
|
- test/test_generator_helper.rb
|
90
98
|
- test/test_helper.rb
|