vintage 0.0.1 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,3 +2,12 @@
2
2
 
3
3
  * 1 major enhancement:
4
4
  * Initial release
5
+
6
+ == 0.0.5 2008-01-11
7
+
8
+ * 2 major enhancements:
9
+ * Support for Thin web server
10
+ * Cookies support
11
+ * 2 bug fixes
12
+ * Fixed initial content
13
+ * Various minor issues...
@@ -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.uri %></li>
20
- <li>Request method: <%= request.method %></li>
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>
@@ -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
@@ -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 = "A super simple web framework"
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
- #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
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
 
@@ -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: 404 Page Not Found</title>
34
+ <title>Vintage Error: #{title}</title>
48
35
  <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; }
36
+ #{CSS}
58
37
  </style>
59
38
  </head>
60
39
 
61
40
  <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>
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
@@ -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 < Mongrel::HttpHandler
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 = Mongrel::DirHandler.new(@options[:static_path], false, nil)
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 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
-
28
+ def call(env)
34
29
  # Setup up the request's context (response and request information)
35
- context = RequestContext.new(request, @params, {})
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.params['REQUEST_URI']}] from [#{request.params['REMOTE_ADDR']}]\n"
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.process(request, response)
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
- head["Content-Type"] = "text/html" if context.response.code == 200
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
- # Write out to the response
73
- out.write content
72
+ response.finish
74
73
  end
75
74
  else
76
75
  # 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
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.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
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
- # Class that encapsulates information about the request.
2
- class Request
3
- attr_accessor :remote_ip, :method, :params, :query_string, :uri, :referer, :user_agent
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
- def initialize(request, param_hash)
6
- self.remote_ip = request.params['REMOTE_ADDR']
7
- self.referer = request.params['HTTP_REFERER']
8
- self.uri = request.params['REQUEST_URI']
9
- self.method = request.params['REQUEST_METHOD']
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
- # Class that encapsulates the response's headers and
17
- # response code.
18
- class Response
19
- attr_accessor :headers, :code
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
- def initialize(headers)
22
- self.headers = headers
23
- self.code = 200
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
- # A class that creates a context for template
28
- # rendering. Helpers are mixed in here to give
29
- # templates access to them.
30
- class RequestContext
31
- attr_accessor :request, :response
32
-
33
- def initialize(incoming_request, params, headers)
34
- self.request = Request.new(incoming_request, params)
35
- self.response = Response.new(headers)
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
@@ -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
- h = Mongrel::HttpServer.new("0.0.0.0", options[:port])
27
- h.register(options[:mount], Handler.new(options))
28
- h.run.join
29
- rescue Interrupt
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"
@@ -2,7 +2,7 @@ module Vintage #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 1
5
+ TINY = 5
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
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.1
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-05 00:00:00 -05:00
12
+ date: 2008-01-11 00:00:00 -05:00
13
13
  default_executable:
14
- dependencies: []
15
-
16
- description: A super simple web framework
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: A super simple web framework
95
+ summary: The super slim web framework
88
96
  test_files:
89
97
  - test/test_generator_helper.rb
90
98
  - test/test_helper.rb