vintage 0.0.1
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.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +33 -0
- data/README.txt +40 -0
- data/Rakefile +4 -0
- data/app_generators/vintage_application/USAGE +5 -0
- data/app_generators/vintage_application/templates/README +6 -0
- data/app_generators/vintage_application/templates/configuration.yml +17 -0
- data/app_generators/vintage_application/templates/index.erb +29 -0
- data/app_generators/vintage_application/templates/style.css +8 -0
- data/app_generators/vintage_application/templates/vintage.png +0 -0
- data/app_generators/vintage_application/vintage_application_generator.rb +71 -0
- data/bin/vintage +76 -0
- data/config/hoe.rb +72 -0
- data/config/requirements.rb +17 -0
- data/lib/vintage/errors.rb +76 -0
- data/lib/vintage/handler.rb +121 -0
- data/lib/vintage/helpers.rb +110 -0
- data/lib/vintage/log.rb +16 -0
- data/lib/vintage/renderer.rb +62 -0
- data/lib/vintage/request_context.rb +37 -0
- data/lib/vintage/server.rb +37 -0
- data/lib/vintage/version.rb +9 -0
- data/lib/vintage.rb +8 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +9 -0
- data/test/test_generator_helper.rb +20 -0
- data/test/test_helper.rb +2 -0
- data/test/test_vintage.rb +11 -0
- data/test/test_vintage_application_generator.rb +43 -0
- metadata +92 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Jeremy McAnally
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/vintage
|
7
|
+
config/hoe.rb
|
8
|
+
config/requirements.rb
|
9
|
+
lib/vintage.rb
|
10
|
+
lib/vintage/version.rb
|
11
|
+
lib/vintage/errors.rb
|
12
|
+
lib/vintage/handler.rb
|
13
|
+
lib/vintage/helpers.rb
|
14
|
+
lib/vintage/log.rb
|
15
|
+
lib/vintage/renderer.rb
|
16
|
+
lib/vintage/request_context.rb
|
17
|
+
lib/vintage/server.rb
|
18
|
+
log/debug.log
|
19
|
+
script/destroy
|
20
|
+
script/generate
|
21
|
+
setup.rb
|
22
|
+
tasks/deployment.rake
|
23
|
+
tasks/environment.rake
|
24
|
+
tasks/website.rake
|
25
|
+
test/test_helper.rb
|
26
|
+
test/test_vintage.rb
|
27
|
+
app_generators/vintage_application/USAGE
|
28
|
+
app_generators/vintage_application/vintage_application_generator.rb
|
29
|
+
app_generators/vintage_application/templates/configuration.yml
|
30
|
+
app_generators/vintage_application/templates/index.erb
|
31
|
+
app_generators/vintage_application/templates/README
|
32
|
+
app_generators/vintage_application/templates/style.css
|
33
|
+
app_generators/vintage_application/templates/vintage.png
|
data/README.txt
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
= Vintage - The super slim, microwebframework of doom!
|
2
|
+
|
3
|
+
Vintage is a very small web framework based on the original idea of Merb: Mongrel serving up
|
4
|
+
ERb (Embedded Ruby) templates. The idea has been expanded and now Vintage helps you serve up
|
5
|
+
ERb, HAML, Textile, Markdown, and Markaby templates.
|
6
|
+
|
7
|
+
== Basic Usage
|
8
|
+
|
9
|
+
To use Vintage, you have two options. You can use it in standard mode or application mode. In
|
10
|
+
standard mode, there is no configuration and Vintage will serve up templates and static files
|
11
|
+
from the current folder. To get this mode, then simply type <tt>vintage start</tt> in any folder.
|
12
|
+
|
13
|
+
$ vintage start
|
14
|
+
- vintage version 0.0.1
|
15
|
+
starting server on port 5000
|
16
|
+
|
17
|
+
Now navigating to a URL will look in the current folder for the file or template. For example, going
|
18
|
+
to <tt>http://localhost:5000/my_template</tt> will look for <tt>my_template.erb</tt> (or whatever template
|
19
|
+
engine you are using) in the current folder and render it if available. If a static file is requested, then
|
20
|
+
it is served up. If you request <tt>http://localhost:5000/my_folder/my_template</tt>, then the application
|
21
|
+
will look in <tt>my_folder</tt> for the <tt>my_template</tt> template.
|
22
|
+
|
23
|
+
=== Vintage as an application server
|
24
|
+
|
25
|
+
Vintage can also be configured to be used as an application server. To do so, you can either generate an
|
26
|
+
application or hand create a <tt>configuration.yml</tt> file (see one from a generated project for an example).
|
27
|
+
To generate an application, simple run +vintage+ with a project name as the argument.
|
28
|
+
|
29
|
+
vintage my_project
|
30
|
+
|
31
|
+
This command will generate a number of files. Chief among these is <tt>configuration.yml</tt> which tells
|
32
|
+
Vintage how you'd like to run it. Other files include a sample template and the proper folder structure
|
33
|
+
for the generated configuration to work properly. This setup allows you to more easily segment your code
|
34
|
+
for easier maintenance.
|
35
|
+
|
36
|
+
== Helpers
|
37
|
+
|
38
|
+
Vintage comes with a few helpers that live in Vintage::Helpers. You can add your own helpers by creating a
|
39
|
+
<tt>helpers</tt> folder and stashing modules in there. As of right now, helpers must live in the Vintage::Helpers
|
40
|
+
module, but this will hopefully be changing very soon.
|
data/Rakefile
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
Vintage - The super slim web framework for men and women
|
2
|
+
========================================================
|
3
|
+
|
4
|
+
Vintage is a very small web framework based on the original idea of Merb: Mongrel serving up
|
5
|
+
ERb (Embedded Ruby) templates. The idea has been expanded and now Vintage helps you serve up
|
6
|
+
ERb, HAML, Textile, Markdown, and Markaby templates.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
# Path for static files
|
3
|
+
:static_path: static/
|
4
|
+
# Path for application templates
|
5
|
+
:path: app/
|
6
|
+
# Templating engine to use
|
7
|
+
:templates: erb
|
8
|
+
# Port to launch server on
|
9
|
+
:port: 5000
|
10
|
+
# Relative URL to mount application on
|
11
|
+
:mount: /
|
12
|
+
# Default template to render on root
|
13
|
+
:root: index
|
14
|
+
# You can also define error templates
|
15
|
+
# :errors:
|
16
|
+
# :not_found: not_found
|
17
|
+
# :internal_error: internal_error
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>
|
4
|
+
Welcome to Vintage
|
5
|
+
</title>
|
6
|
+
<link rel="stylesheet" href="style.css" />
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<img src="vintage.png" />
|
10
|
+
<h1>Welcome to Vintage</h1>
|
11
|
+
<p>
|
12
|
+
Come on in and relax. Actually, don't relax. Build something.
|
13
|
+
</p>
|
14
|
+
<div>
|
15
|
+
<h2>Request Information</h2>
|
16
|
+
<ul>
|
17
|
+
<li>Remote IP: <%= request.remote_ip %></li>
|
18
|
+
<li>Referer: <%= request.referer %></li>
|
19
|
+
<li>Requested URI: <%= request.uri %></li>
|
20
|
+
<li>Request method: <%= request.method %></li>
|
21
|
+
<li>User agent: <%= request.user_agent %></li>
|
22
|
+
<li>Query string: <%= request.query_string %></li>
|
23
|
+
<li>Parameters: <%= request.params == {} ? "None" : request.params.to_a.map{|k,v| "#{k} = #{v}"}.join(", ") %></li>
|
24
|
+
</ul>
|
25
|
+
</div>
|
26
|
+
<br />
|
27
|
+
<%= link_to "Vintage homepage", "http://vintage.rubyforge.org" %>
|
28
|
+
</body>
|
29
|
+
</html>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
BODY { background: #3E2B09; text-align: center; font-family: sans-serif; }
|
2
|
+
h1 { color: white; }
|
3
|
+
p { color: #ccd69f; }
|
4
|
+
div { background: #ccd69f; color: black; width: 450px; padding: 10px; margin: auto; border: 2px solid #aab47d;}
|
5
|
+
div h2 { font-size: 14pt; color: #33400a; margin: 0px; }
|
6
|
+
div ul { list-style-type: none; }
|
7
|
+
div ul li { padding: 0px; margin: 8px 0px; text-align: left; }
|
8
|
+
A { color: white; }
|
Binary file
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class VintageApplicationGenerator < RubiGen::Base
|
2
|
+
|
3
|
+
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
4
|
+
Config::CONFIG['ruby_install_name'])
|
5
|
+
|
6
|
+
default_options :author => nil
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
def initialize(runtime_args, runtime_options = {})
|
11
|
+
super
|
12
|
+
usage if args.empty?
|
13
|
+
@destination_root = File.expand_path(args.shift)
|
14
|
+
@name = base_name
|
15
|
+
extract_options
|
16
|
+
end
|
17
|
+
|
18
|
+
def manifest
|
19
|
+
record do |m|
|
20
|
+
# Ensure appropriate folder(s) exists
|
21
|
+
m.directory ''
|
22
|
+
BASEDIRS.each { |path| m.directory path }
|
23
|
+
|
24
|
+
m.file "configuration.yml", "configuration.yml"
|
25
|
+
m.file "README", "README"
|
26
|
+
m.file "index.erb", "app/index.erb"
|
27
|
+
m.file "vintage.png", "static/vintage.png"
|
28
|
+
m.file "style.css", "static/style.css"
|
29
|
+
|
30
|
+
# m.dependency "install_rubigen_scripts", [destination_root, 'vintage_application'],
|
31
|
+
# :shebang => options[:shebang], :collision => :force
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def banner
|
37
|
+
<<-EOS
|
38
|
+
Creates a ...
|
39
|
+
|
40
|
+
USAGE: #{spec.name} name"
|
41
|
+
EOS
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_options!(opts)
|
45
|
+
opts.separator ''
|
46
|
+
opts.separator 'Options:'
|
47
|
+
# For each option below, place the default
|
48
|
+
# at the top of the file next to "default_options"
|
49
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
50
|
+
# "Some comment about this option",
|
51
|
+
# "Default: none") { |options[:author]| }
|
52
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
53
|
+
end
|
54
|
+
|
55
|
+
def extract_options
|
56
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
57
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
58
|
+
# raw instance variable value.
|
59
|
+
# @author = options[:author]
|
60
|
+
end
|
61
|
+
|
62
|
+
# Installation skeleton. Intermediate directories are automatically
|
63
|
+
# created so don't sweat their absence here.
|
64
|
+
BASEDIRS = %w(
|
65
|
+
app
|
66
|
+
static
|
67
|
+
helpers
|
68
|
+
test
|
69
|
+
tmp
|
70
|
+
)
|
71
|
+
end
|
data/bin/vintage
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Jeremy McAnally on 2008-1-1.
|
4
|
+
# Copyright (c) 2008. All rights reserved.
|
5
|
+
|
6
|
+
$:.unshift File.dirname(__FILE__)
|
7
|
+
require File.dirname(__FILE__) + '/../lib/vintage'
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'optparse'
|
11
|
+
require 'rubigen'
|
12
|
+
|
13
|
+
# NOTE: the option -p/--path= is given as an example, and should probably be replaced in your application.
|
14
|
+
|
15
|
+
OPTIONS = {
|
16
|
+
:path => Dir.pwd,
|
17
|
+
:static_path => Dir.pwd,
|
18
|
+
:port => 5000,
|
19
|
+
:config => 'configuration.yml',
|
20
|
+
:templates => 'erb',
|
21
|
+
:mount => '/',
|
22
|
+
:root => 'index'
|
23
|
+
}
|
24
|
+
MANDATORY_OPTIONS = %w( )
|
25
|
+
|
26
|
+
parser = OptionParser.new do |opts|
|
27
|
+
opts.banner = <<BANNER
|
28
|
+
|
29
|
+
Vintage - v.#{Vintage::VERSION::STRING}
|
30
|
+
=================
|
31
|
+
The super-micro web framework. If a project name is provided,
|
32
|
+
a new project is generated. Otherwise, Vintage will start serving
|
33
|
+
given the defaults and/or any provided options.
|
34
|
+
|
35
|
+
Usage: #{File.basename($0)} [options]
|
36
|
+
#{File.basename($0)} [project name]
|
37
|
+
|
38
|
+
Options are:
|
39
|
+
BANNER
|
40
|
+
opts.separator ""
|
41
|
+
opts.on("-p", "--path=PATH", String,
|
42
|
+
"The root path for selecting files",
|
43
|
+
"Default: ~") { |OPTIONS[:path]| }
|
44
|
+
opts.on("-P", "--port=PORT", Integer,
|
45
|
+
"The port to serve up your Vintage application on",
|
46
|
+
"Default: 5000") { |OPTIONS[:port]| }
|
47
|
+
opts.on("-c", "--config=FILE", String,
|
48
|
+
"The configuration file to use when launching this Vintage application",
|
49
|
+
"Default: configuration.rb") { |OPTIONS[:config]| }
|
50
|
+
opts.on("-t", "--template=TYPE", String,
|
51
|
+
"The parser used for templates (can be erb, haml, mab, markdown, or textile)",
|
52
|
+
"Default: erb") { |OPTIONS[:templates]| }
|
53
|
+
opts.on("-m", "--mount-at=url", String,
|
54
|
+
"The relative URL to mount this application at (e.g., vintage -m myapp will mount at http://localhost/myapp)",
|
55
|
+
"Default: none (mounted at /)") { |OPTIONS[:mount]| }
|
56
|
+
opts.on("-r", "--root=template", String,
|
57
|
+
"The template to render at the root URL",
|
58
|
+
"Default: index") { |OPTIONS[:root]| }
|
59
|
+
opts.on("-h", "--help",
|
60
|
+
"Show this help message.") { puts opts; exit }
|
61
|
+
opts.parse!(ARGV)
|
62
|
+
end
|
63
|
+
|
64
|
+
if ARGV.empty?
|
65
|
+
puts parser
|
66
|
+
puts
|
67
|
+
elsif ARGV[0] == "start"
|
68
|
+
OPTIONS.merge!(YAML::load_file(OPTIONS[:config])) if File.exists?(OPTIONS[:config])
|
69
|
+
Vintage::Server.run(OPTIONS)
|
70
|
+
else
|
71
|
+
require 'rubigen/scripts/generate'
|
72
|
+
source = RubiGen::PathSource.new(:application, File.join(File.dirname(__FILE__), "../app_generators"))
|
73
|
+
RubiGen::Base.reset_sources
|
74
|
+
RubiGen::Base.append_sources source
|
75
|
+
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'vintage_application')
|
76
|
+
end
|
data/config/hoe.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'vintage/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Jeremy McAnally' # can also be an array of Authors
|
4
|
+
EMAIL = "jeremymcanally@gmail.com"
|
5
|
+
DESCRIPTION = "A super simple web framework"
|
6
|
+
GEM_NAME = 'vintage' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'vintage' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = Vintage::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
VERSION = VERS
|
36
|
+
RDOC_OPTS = ['--quiet', '--title', 'vintage documentation',
|
37
|
+
"--opname", "index.html",
|
38
|
+
"--line-numbers",
|
39
|
+
"--main", "README",
|
40
|
+
"--inline-source"]
|
41
|
+
|
42
|
+
class Hoe
|
43
|
+
def extra_deps
|
44
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
45
|
+
@extra_deps
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generate all the Rake tasks
|
50
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
51
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
52
|
+
p.author = AUTHOR
|
53
|
+
p.description = DESCRIPTION
|
54
|
+
p.email = EMAIL
|
55
|
+
p.summary = DESCRIPTION
|
56
|
+
p.url = HOMEPATH
|
57
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
58
|
+
p.test_globs = ["test/**/test_*.rb"]
|
59
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
60
|
+
|
61
|
+
# == Optional
|
62
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
63
|
+
#p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
64
|
+
|
65
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
70
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
71
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
72
|
+
hoe.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'vintage'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Vintage
|
2
|
+
# A class to render the default error pages. These will
|
3
|
+
# not render if error pages are specified in the configuration.
|
4
|
+
class ErrorReporter
|
5
|
+
# Standard template to render for a <tt>500 Internal Server Error</tt>
|
6
|
+
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
|
+
"""
|
40
|
+
end
|
41
|
+
|
42
|
+
# Standard template to render for a <tt>404 Page Not Found</tt> error
|
43
|
+
def self.not_found(url, remote_ip, params)
|
44
|
+
"""
|
45
|
+
<html>
|
46
|
+
<head>
|
47
|
+
<title>Vintage Error: 404 Page Not Found</title>
|
48
|
+
<style>
|
49
|
+
body { margin: 0px; padding: 0px; font-family: sans-serif; }
|
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; }
|
58
|
+
</style>
|
59
|
+
</head>
|
60
|
+
|
61
|
+
<body>
|
62
|
+
<h1><span class='error'>Page Not Found</span> 404 Not Found</h1>
|
63
|
+
<h2>Request for #{url} <span class='where'>from #{remote_ip}</span></h2>
|
64
|
+
<div>
|
65
|
+
<h3>Parameters</h3>
|
66
|
+
<ul>
|
67
|
+
#{params == {} ? "None" : params.to_a.map{|key, val| "<li><b>" + key.to_s + "<b> = " + val.to_s + "</li>"}.join("\n") }
|
68
|
+
</ul>
|
69
|
+
</div>
|
70
|
+
</body>
|
71
|
+
</html>
|
72
|
+
|
73
|
+
"""
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mongrel'
|
3
|
+
require 'erubis'
|
4
|
+
require 'erb'
|
5
|
+
require 'mime/types'
|
6
|
+
|
7
|
+
require 'vintage/renderer'
|
8
|
+
require 'vintage/request_context'
|
9
|
+
require 'vintage/errors'
|
10
|
+
|
11
|
+
module Vintage
|
12
|
+
# The Mongrel HTTP Handler. Handles all operations with requests.
|
13
|
+
class Handler < Mongrel::HttpHandler
|
14
|
+
def initialize(options)
|
15
|
+
# Make our configuration options avialable to the handler
|
16
|
+
@options = options
|
17
|
+
|
18
|
+
# Setup a DirHandler for sending static files securely
|
19
|
+
@static_handler = Mongrel::DirHandler.new(@options[:static_path], false, nil)
|
20
|
+
|
21
|
+
# Inject our helpers in the RequestContext class to make them
|
22
|
+
# available on each request.
|
23
|
+
include_helpers
|
24
|
+
end
|
25
|
+
|
26
|
+
# Main request handler for Mongrel.
|
27
|
+
def process(request, response)
|
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
|
+
|
34
|
+
# Setup up the request's context (response and request information)
|
35
|
+
context = RequestContext.new(request, @params, {})
|
36
|
+
|
37
|
+
# Initialize the buffered log entry
|
38
|
+
log_entry = ""
|
39
|
+
log_entry << "*** request for [#{request.params['REQUEST_URI']}] from [#{request.params['REMOTE_ADDR']}]\n"
|
40
|
+
|
41
|
+
# If it's a root request, we want to render the template we configured
|
42
|
+
@request_path = @options[:root] if @request_path == '/'
|
43
|
+
|
44
|
+
# If it's a static file we don't need to append a file extension
|
45
|
+
filename = (@request_path =~ /\.(.*)$/) ? "#{@options[:static_path]}/#{@request_path}" : "#{@options[:path]}/#{@request_path}.#{@options[:templates]}"
|
46
|
+
|
47
|
+
# Does the file exist...?
|
48
|
+
if File.exists?(filename)
|
49
|
+
# It's found! Let's add to our log entry...
|
50
|
+
log_entry << " response: [200]\n"
|
51
|
+
log_entry << " rendering [#{@request_path}]\n"
|
52
|
+
|
53
|
+
# Is it a static file?
|
54
|
+
if (@request_path =~ /\.(.*)$/)
|
55
|
+
# Yes? Let our static handler take it away!
|
56
|
+
@static_handler.process(request, response)
|
57
|
+
else
|
58
|
+
# No! Render a template...
|
59
|
+
content = Renderer.send(@options[:templates].to_sym, File.open("#{@options[:path]}#{@request_path}.#{@options[:templates]}", "r").read, context)
|
60
|
+
end
|
61
|
+
|
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
|
+
# Set the content type if we're responding with a render
|
70
|
+
head["Content-Type"] = "text/html" if context.response.code == 200
|
71
|
+
|
72
|
+
# Write out to the response
|
73
|
+
out.write content
|
74
|
+
end
|
75
|
+
else
|
76
|
+
# Page not found
|
77
|
+
response.start(404) do |head, out|
|
78
|
+
# Log the 404
|
79
|
+
log_entry << " response: [404]\n"
|
80
|
+
log_entry << " rendering 'page not found'\n"
|
81
|
+
|
82
|
+
# Send back the default or a custom template
|
83
|
+
head["Content-Type"] = "text/html"
|
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
|
86
|
+
end
|
87
|
+
rescue StandardError => err
|
88
|
+
# OOPS! Something broke.
|
89
|
+
response.start(500) do |head, out|
|
90
|
+
# Log it and send an error page...
|
91
|
+
log_entry << "\t!!! [500] #{err}\n"
|
92
|
+
head["Content-Type"] = "text/html"
|
93
|
+
out.write @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)
|
94
|
+
end
|
95
|
+
ensure
|
96
|
+
# After every request push the buffered log entry out to the logger
|
97
|
+
Log.enter log_entry.to_s + "\n"
|
98
|
+
end
|
99
|
+
|
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
|
+
# Inject the default helpers and helpers from the
|
115
|
+
# +helpers/+ directory (if available) into the
|
116
|
+
# RequestContext class.
|
117
|
+
def include_helpers
|
118
|
+
RequestContext.send(:include, Vintage::Helpers)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|