vintage 0.0.1 → 0.0.5

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.
@@ -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