rambo 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +32 -0
- data/lib/rambo.rb +4 -0
- data/lib/rambo/application_context.rb +52 -0
- data/lib/rambo/application_request.rb +25 -0
- data/lib/rambo/controller.rb +36 -0
- data/lib/rambo/controller/cache.rb +17 -0
- data/lib/rambo/controller/params.rb +26 -0
- data/lib/rambo/controller/redirect.rb +14 -0
- data/lib/rambo/controller/template.rb +80 -0
- data/lib/rambo/env.rb +43 -0
- data/lib/rambo/middleware.rb +3 -0
- data/lib/rambo/middleware/lock.rb +18 -0
- data/lib/rambo/middleware/proxy.rb +48 -0
- data/lib/rambo/middleware/upload.rb +16 -0
- data/lib/rambo/request.rb +61 -0
- data/lib/rambo/response.rb +29 -0
- data/lib/rambo/server.rb +67 -0
- data/lib/rambo/time.rb +11 -0
- metadata +73 -0
data/README
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
To install the gem:
|
2
|
+
|
3
|
+
gem sources -a http://gems.github.com
|
4
|
+
sudo gem install moomerman-rambo
|
5
|
+
|
6
|
+
Smallest example (see the hello app in the example folder)
|
7
|
+
|
8
|
+
class HomeController < Rambo::Controller
|
9
|
+
def index
|
10
|
+
"hello world"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
To run the Blog example:
|
15
|
+
|
16
|
+
git clone git://github.com/moomerman/rambo.git
|
17
|
+
cd rambo/example/blog/
|
18
|
+
rake db:setup # check config.yml for your specific db settings
|
19
|
+
rake server
|
20
|
+
|
21
|
+
head over to http://localhost:4000/
|
22
|
+
|
23
|
+
Features:
|
24
|
+
= No Ruby object base class modifications
|
25
|
+
= Lightweight and fast
|
26
|
+
= Rack-based so works with most web servers (thin, mongrel, passenger)
|
27
|
+
= Ability to proxy request to n backend app servers [experimental]
|
28
|
+
= Request caching built in
|
29
|
+
= fast static file serving
|
30
|
+
= works with erb or haml templates (more to come)
|
31
|
+
= DataMapper integration
|
32
|
+
= Library only 60k
|
data/lib/rambo.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rambo
|
2
|
+
class ApplicationContext
|
3
|
+
attr_accessor :application_name
|
4
|
+
|
5
|
+
def initialize(application_name = nil)
|
6
|
+
@application_name = application_name
|
7
|
+
puts "Initializing application: #{application_name || 'default'}"
|
8
|
+
@prefix = "#{self.application_name}/" if self.application_name
|
9
|
+
@prefix ||= ''
|
10
|
+
load_classes
|
11
|
+
end
|
12
|
+
|
13
|
+
def load_classes
|
14
|
+
Dir["#{@prefix}controller/*.rb"].each { |x| funkyload x; }
|
15
|
+
Dir["#{@prefix}model/*.rb"].each { |x| funkyload x }
|
16
|
+
Dir["#{@prefix}lib/*.rb"].each { |x| funkyload x }
|
17
|
+
Dir["#{@prefix}*.rb"].each { |x| funkyload x unless x == 'Rakefile.rb' }
|
18
|
+
end
|
19
|
+
|
20
|
+
def reload
|
21
|
+
load_classes
|
22
|
+
end
|
23
|
+
|
24
|
+
def view_path
|
25
|
+
"./#{@prefix}view"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def funkyload(file)
|
30
|
+
@@loadcache ||= {}
|
31
|
+
begin
|
32
|
+
if cache = @@loadcache[file]
|
33
|
+
return if Env.config['rambo'] and Env.config['rambo']['reload_classes'] == false
|
34
|
+
if (mtime = File.mtime(file)) > cache
|
35
|
+
puts "rambo: reloading: #{file}"
|
36
|
+
load file
|
37
|
+
@@loadcache[file] = mtime
|
38
|
+
end
|
39
|
+
else
|
40
|
+
puts " -> loading: #{file}"
|
41
|
+
load file
|
42
|
+
@@loadcache[file] = File.mtime(file)
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
puts "Exception loading class [#{file}]: #{e.message}"
|
46
|
+
puts e.backtrace.join("\n")
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rambo
|
2
|
+
class ApplicationRequest < Rambo::Request
|
3
|
+
|
4
|
+
def initialize(env)
|
5
|
+
super
|
6
|
+
end
|
7
|
+
|
8
|
+
def application
|
9
|
+
path_components[1]
|
10
|
+
end
|
11
|
+
|
12
|
+
def controller
|
13
|
+
path_components[2] || default_controller
|
14
|
+
end
|
15
|
+
|
16
|
+
def action
|
17
|
+
path_components[3] || 'index'
|
18
|
+
end
|
19
|
+
|
20
|
+
def controller_class
|
21
|
+
self.application.gsub(/^[a-z]|\s+[a-z]/) { |a| a.upcase } + '::' + super
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rambo/controller/template'
|
2
|
+
require 'rambo/controller/cache'
|
3
|
+
require 'rambo/controller/params'
|
4
|
+
require 'rambo/controller/redirect'
|
5
|
+
|
6
|
+
module Rambo
|
7
|
+
class Controller
|
8
|
+
attr_accessor :request, :response
|
9
|
+
|
10
|
+
include Template
|
11
|
+
include Cache
|
12
|
+
include Params
|
13
|
+
include Redirect
|
14
|
+
|
15
|
+
def already_rendered?
|
16
|
+
@rendered
|
17
|
+
end
|
18
|
+
|
19
|
+
def controller
|
20
|
+
self.request.controller
|
21
|
+
end
|
22
|
+
|
23
|
+
def action
|
24
|
+
self.request.action
|
25
|
+
end
|
26
|
+
|
27
|
+
def session
|
28
|
+
request.env['rack.session'] ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def host
|
32
|
+
self.request.env['HTTP_HOST']
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Cache
|
2
|
+
def fresh?(model, options={})
|
3
|
+
@@etags ||= {}
|
4
|
+
etag = Digest::SHA1.hexdigest(model.inspect)
|
5
|
+
response.header['ETag'] = "\"#{etag}\""
|
6
|
+
response.header['Expires'] = (MooTime.now + options[:expires_in]).httpdate if options[:expires_in]
|
7
|
+
response.header['Cache-Control'] = 'public'
|
8
|
+
if @@etags[request.uri] == etag
|
9
|
+
response.status = 304
|
10
|
+
response.body = ''
|
11
|
+
return true
|
12
|
+
else
|
13
|
+
@@etags[request.uri] = etag
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Params
|
2
|
+
def params
|
3
|
+
if !self.request.params.keys.join.include?('[')
|
4
|
+
@params ||= indifferent_hash.merge(self.request.params)
|
5
|
+
else
|
6
|
+
@params ||= self.request.params.inject indifferent_hash do |res, (key,val)|
|
7
|
+
if key.include?('[')
|
8
|
+
head = key.split(/[\]\[]+/)
|
9
|
+
last = head.pop
|
10
|
+
head.inject(res){ |hash,k| hash[k] ||= indifferent_hash }[last] = val
|
11
|
+
else
|
12
|
+
res[key] = val
|
13
|
+
end
|
14
|
+
res
|
15
|
+
end
|
16
|
+
end
|
17
|
+
if request.path_components.size() > 2
|
18
|
+
@params.merge!(:id => request.path_components[3])
|
19
|
+
end
|
20
|
+
@params
|
21
|
+
end
|
22
|
+
|
23
|
+
def indifferent_hash
|
24
|
+
Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Redirect
|
2
|
+
def redirect(destination, options={})
|
3
|
+
destination = destination.to_s if destination.is_a? Symbol
|
4
|
+
unless destination[0,1] == "/" or destination =~ /^http:\/\// or destination =~ /^file:\/\//
|
5
|
+
destination = "/#{self.controller}/#{destination}"
|
6
|
+
end
|
7
|
+
puts "redirecting to #{destination}"
|
8
|
+
|
9
|
+
@rendered = true
|
10
|
+
response.status = 302
|
11
|
+
response.header['Location'] = destination
|
12
|
+
return ""
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Template
|
2
|
+
|
3
|
+
@@template_cache = {}
|
4
|
+
|
5
|
+
def erb(template, options={}, locals={})
|
6
|
+
require 'erb' unless defined? ::ERB
|
7
|
+
render :erb, template, options, locals
|
8
|
+
end
|
9
|
+
|
10
|
+
def haml(template, options={}, locals={})
|
11
|
+
require 'haml' unless defined? ::Haml
|
12
|
+
render :haml, template, options, locals
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def render(engine, template, options={}, locals={})
|
17
|
+
# extract generic options
|
18
|
+
layout = options.delete(:layout)
|
19
|
+
layout = :layout if layout.nil? || layout == true
|
20
|
+
views = options.delete(:views) || self.request.application_context.view_path
|
21
|
+
locals = options.delete(:locals) || locals || {}
|
22
|
+
|
23
|
+
# render template
|
24
|
+
data, options[:filename], options[:line] = lookup_template(engine, template, views)
|
25
|
+
output = __send__("render_#{engine}", data, options, locals)
|
26
|
+
|
27
|
+
# render layout
|
28
|
+
if layout
|
29
|
+
data, options[:filename], options[:line] = lookup_layout(engine, layout, views)
|
30
|
+
if data
|
31
|
+
output = __send__("render_#{engine}", data, options, locals) { output }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
output
|
36
|
+
end
|
37
|
+
|
38
|
+
def lookup_template(engine, template, views_dir)
|
39
|
+
case template
|
40
|
+
when Symbol
|
41
|
+
# if cached = @@template_cache[template]
|
42
|
+
# cached
|
43
|
+
# else
|
44
|
+
path = ::File.join(views_dir, "#{template}.#{engine}")
|
45
|
+
[ ::File.read(path), path, 1 ]
|
46
|
+
# @@template_cache[template] = res
|
47
|
+
# res
|
48
|
+
#end
|
49
|
+
when Proc
|
50
|
+
[template.call, template, 1]
|
51
|
+
when String
|
52
|
+
[template, template, 1]
|
53
|
+
else
|
54
|
+
raise ArgumentError
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def lookup_layout(engine, template, views_dir)
|
59
|
+
lookup_template(engine, template, views_dir)
|
60
|
+
rescue Errno::ENOENT
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_erb(data, options, locals, &block)
|
65
|
+
original_out_buf = @_out_buf
|
66
|
+
data = data.call if data.kind_of? Proc
|
67
|
+
|
68
|
+
instance = ::ERB.new(data, nil, nil, '@_out_buf')
|
69
|
+
locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
|
70
|
+
|
71
|
+
src = "#{locals_assigns.join("\n")}\n#{instance.src}"
|
72
|
+
eval src, binding, '(__ERB__)', locals_assigns.length + 1
|
73
|
+
@_out_buf, result = original_out_buf, @_out_buf
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
def render_haml(data, options, locals, &block)
|
78
|
+
::Haml::Engine.new(data, options).render(self, locals, &block)
|
79
|
+
end
|
80
|
+
end
|
data/lib/rambo/env.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Env handles all the configuration loading, database initialization and class (re)loading
|
2
|
+
# would be nice to allow the user to specify their own init though if they want
|
3
|
+
# Env.new can be called anywhere in any application and therefore acts as a global config
|
4
|
+
module Rambo
|
5
|
+
class Env
|
6
|
+
def self.config
|
7
|
+
@@config ||= YAML.load_file("config.yml") rescue nil
|
8
|
+
@@config ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
begin
|
13
|
+
# TODO: config reload
|
14
|
+
|
15
|
+
if dbconf = Env.config['mongodb']
|
16
|
+
require 'mongomapper'
|
17
|
+
@@database ||= MongoMapper.database = dbconf['database']
|
18
|
+
end
|
19
|
+
|
20
|
+
if dbconf = Env.config['datamapper']
|
21
|
+
require 'dm-core'
|
22
|
+
require 'dm-validations'
|
23
|
+
require 'dm-timestamps'
|
24
|
+
@@connection ||= DataMapper.setup(
|
25
|
+
:default,
|
26
|
+
:adapter => :mysql,
|
27
|
+
:host => dbconf['host'],
|
28
|
+
:database => dbconf['database'],
|
29
|
+
:username => dbconf['username'],
|
30
|
+
:password => dbconf['password']
|
31
|
+
)
|
32
|
+
@@dblogger ||= DataObjects::Mysql.logger = DataObjects::Logger.new(STDOUT, dbconf['logging']) if dbconf['logging']
|
33
|
+
end
|
34
|
+
rescue Exception => e
|
35
|
+
puts "Exception initializing environment: #{e.message}"
|
36
|
+
puts e.backtrace.join("\n")
|
37
|
+
raise e
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rack
|
2
|
+
class Lock
|
3
|
+
FLAG = 'rack.multithread'.freeze unless defined? FLAG
|
4
|
+
|
5
|
+
def initialize(app, lock = Mutex.new)
|
6
|
+
@app, @lock = app, lock
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
old, env[FLAG] = env[FLAG], false
|
11
|
+
@lock.synchronize { @app.call(env) }
|
12
|
+
ensure
|
13
|
+
env[FLAG] = old
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
#require 'right_http_connection'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Proxy
|
6
|
+
def initialize(app, options={})
|
7
|
+
@app = app
|
8
|
+
@options = options
|
9
|
+
@@conn = Rightscale::HttpConnection.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
|
14
|
+
request = Request.new(env)
|
15
|
+
|
16
|
+
# tey out persistent connections using right http conn (need to make params aware?)
|
17
|
+
|
18
|
+
begin
|
19
|
+
|
20
|
+
backend = rand(@options[:backend].size+1)
|
21
|
+
|
22
|
+
if backend == @options[:backend].size
|
23
|
+
@app.call(env)
|
24
|
+
else
|
25
|
+
host = URI.parse("http://#{env['HTTP_HOST']}").host
|
26
|
+
port = @options[:backend][backend]
|
27
|
+
|
28
|
+
req = Net::HTTP::Get.new(env['REQUEST_URI'])
|
29
|
+
res = Net::HTTP.start(host, port) {|http|
|
30
|
+
http.request(req, request.params)
|
31
|
+
}
|
32
|
+
|
33
|
+
# need to be able to pass params into request below
|
34
|
+
#res = @@conn.req(:server => host, :port => port, :protocol => 'http', :request => request)
|
35
|
+
|
36
|
+
body = res.body || ''
|
37
|
+
|
38
|
+
[res.code.to_i, {'ETag' => res['ETag'], 'Cache-Control' => res['Cache-Control'], 'Content-Type' => res['Content-Type'], 'Location' => res['Location']}, body]
|
39
|
+
end
|
40
|
+
rescue Exception => e
|
41
|
+
puts e.message
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rambo
|
4
|
+
class Request < Rack::Request
|
5
|
+
def user_agent
|
6
|
+
@env['HTTP_USER_AGENT']
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns an array of acceptable media types for the response
|
10
|
+
def accept
|
11
|
+
@env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.strip }
|
12
|
+
end
|
13
|
+
|
14
|
+
def path
|
15
|
+
@env["REQUEST_PATH"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def uri
|
19
|
+
@env["REQUEST_URI"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def path_components
|
23
|
+
@path_components ||= path.split('/')
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_controller
|
27
|
+
if rambo_conf = Rambo::Env.config['rambo']
|
28
|
+
rambo_conf['default_controller'] || 'home'
|
29
|
+
else
|
30
|
+
'home'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def application_context
|
35
|
+
@application_context
|
36
|
+
end
|
37
|
+
|
38
|
+
def application_context=(ctx)
|
39
|
+
@application_context = ctx
|
40
|
+
end
|
41
|
+
|
42
|
+
def controller
|
43
|
+
path_components[1] || default_controller
|
44
|
+
end
|
45
|
+
|
46
|
+
def action
|
47
|
+
path_components[2] || 'index'
|
48
|
+
end
|
49
|
+
|
50
|
+
def controller_class
|
51
|
+
self.controller.downcase.gsub(/^[a-z]|\s+[a-z]/) { |a| a.upcase } + 'Controller'
|
52
|
+
end
|
53
|
+
|
54
|
+
# Override Rack 0.9.x's #params implementation (see #72 in lighthouse)
|
55
|
+
def params
|
56
|
+
self.GET.update(self.POST)
|
57
|
+
rescue EOFError => boom
|
58
|
+
self.GET
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rambo
|
2
|
+
class Response < Rack::Response
|
3
|
+
def initialize
|
4
|
+
@status, @body = 200, []
|
5
|
+
@header = Rack::Utils::HeaderHash.new({'Content-Type' => 'text/html'})
|
6
|
+
end
|
7
|
+
|
8
|
+
# def write(str)
|
9
|
+
# @body << str.to_s
|
10
|
+
# str
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def finish
|
14
|
+
# @body = block if block_given?
|
15
|
+
# if [204, 304].include?(status.to_i)
|
16
|
+
# header.delete "Content-Type"
|
17
|
+
# [status.to_i, header.to_hash, []]
|
18
|
+
# else
|
19
|
+
# body = @body || []
|
20
|
+
# body = [body] if body.respond_to? :to_str
|
21
|
+
# if body.respond_to?(:to_ary)
|
22
|
+
# header["Content-Length"] = body.to_ary.
|
23
|
+
# inject(0) { |len, part| len + part.bytesize }.to_s
|
24
|
+
# end
|
25
|
+
# [status.to_i, header.to_hash, body]
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rambo/server.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rambo/env'
|
4
|
+
require 'rambo/controller'
|
5
|
+
require 'rambo/middleware'
|
6
|
+
require 'rambo/time'
|
7
|
+
require 'rambo/request'
|
8
|
+
require 'rambo/application_request'
|
9
|
+
require 'rambo/response'
|
10
|
+
require 'rambo/application_context'
|
11
|
+
|
12
|
+
# Server simply routes the request to the correct controller/action and returns the result
|
13
|
+
module Rambo
|
14
|
+
class Server
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
@options = options
|
18
|
+
env = Rambo::Env.new
|
19
|
+
@contexts = {
|
20
|
+
'default' => Rambo::ApplicationContext.new(),
|
21
|
+
#'blog' => Rambo::ApplicationContext.new('blog')
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(env)
|
26
|
+
begin
|
27
|
+
|
28
|
+
@contexts.each { |key, context| context.reload } if Rambo::Env.config
|
29
|
+
|
30
|
+
request = Request.new(env)
|
31
|
+
response = Response.new
|
32
|
+
|
33
|
+
if @contexts.keys.include? request.controller.downcase
|
34
|
+
current_context = @contexts[request.controller.downcase]
|
35
|
+
request = Rambo::ApplicationRequest.new(env)
|
36
|
+
end
|
37
|
+
current_context ||= @contexts['default']
|
38
|
+
request.application_context = current_context
|
39
|
+
|
40
|
+
#puts "rambo: looking for #{request.controller_class}"
|
41
|
+
|
42
|
+
begin
|
43
|
+
controller = Object.module_eval("::#{request.controller_class}", __FILE__, __LINE__).new
|
44
|
+
rescue Exception => e
|
45
|
+
return [404, response.header, "<h2>Routing error: controller <span style='color:grey'>#{request.controller}</span> not found</h2>"]
|
46
|
+
end
|
47
|
+
controller.request = request
|
48
|
+
controller.response = response
|
49
|
+
|
50
|
+
controller.init if controller.respond_to? :init
|
51
|
+
|
52
|
+
unless controller.respond_to? request.action
|
53
|
+
return [404, response.header, "<h2>Routing error: action <span style='color:grey'>#{request.action}</span> not found in <span style='color:grey'>#{request.controller}</span></h2>"]
|
54
|
+
end
|
55
|
+
|
56
|
+
result = controller.send(request.action) unless controller.already_rendered?
|
57
|
+
|
58
|
+
response.body = result if result
|
59
|
+
|
60
|
+
[response.status, response.header, response.body]
|
61
|
+
rescue Exception => e
|
62
|
+
puts e.message
|
63
|
+
return [500, {}, "<pre><b>#{e.message.gsub("<","<")}</b>\n#{e.backtrace.join("\n")}</pre>"]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/rambo/time.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
class MooTime < Time
|
2
|
+
RFC2822_DAY_NAME = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
|
3
|
+
RFC2822_MONTH_NAME = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
|
4
|
+
def httpdate
|
5
|
+
t = dup.utc
|
6
|
+
sprintf('%s, %02d %s %d %02d:%02d:%02d GMT',
|
7
|
+
RFC2822_DAY_NAME[t.wday],
|
8
|
+
t.day, RFC2822_MONTH_NAME[t.mon-1], t.year,
|
9
|
+
t.hour, t.min, t.sec)
|
10
|
+
end
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rambo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Richard Taylor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-30 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: rambo is an experimental ruby web framework
|
17
|
+
email: moomerman@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- lib/rambo.rb
|
27
|
+
- lib/rambo/application_context.rb
|
28
|
+
- lib/rambo/application_request.rb
|
29
|
+
- lib/rambo/controller/cache.rb
|
30
|
+
- lib/rambo/controller/params.rb
|
31
|
+
- lib/rambo/controller/redirect.rb
|
32
|
+
- lib/rambo/controller/template.rb
|
33
|
+
- lib/rambo/controller.rb
|
34
|
+
- lib/rambo/env.rb
|
35
|
+
- lib/rambo/middleware/lock.rb
|
36
|
+
- lib/rambo/middleware/proxy.rb
|
37
|
+
- lib/rambo/middleware/upload.rb
|
38
|
+
- lib/rambo/middleware.rb
|
39
|
+
- lib/rambo/request.rb
|
40
|
+
- lib/rambo/response.rb
|
41
|
+
- lib/rambo/server.rb
|
42
|
+
- lib/rambo/time.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/moomerman/rambo
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --inline-source
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: rambo
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: rambo is an experimental ruby web framework based on rack
|
72
|
+
test_files: []
|
73
|
+
|