moomerman-rambo 0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,12 @@
1
+ To install the gem:
2
+
3
+ gem sources -a http://gems.github.com
4
+ sudo gem install moomerman-rambo
5
+
6
+ To run the example:
7
+
8
+ clone the repo (the examples are not part of the gem)
9
+ cd rambo/example/blog/
10
+ thin start -R server.ru -p 4000 --threaded
11
+
12
+ head over to http://localhost:4000/
@@ -0,0 +1,71 @@
1
+ load 'rambo/templating.rb'
2
+
3
+ module Rambo
4
+ class BaseController
5
+ include Templating
6
+
7
+ attr_accessor :params, :request, :response
8
+
9
+ def params
10
+ if !self.request.params.keys.join.include?('[')
11
+ @params ||= indifferent_hash.merge(self.request.params)
12
+ else
13
+ @params ||= self.request.params.inject indifferent_hash do |res, (key,val)|
14
+ if key.include?('[')
15
+ head = key.split(/[\]\[]+/)
16
+ last = head.pop
17
+ head.inject(res){ |hash,k| hash[k] ||= indifferent_hash }[last] = val
18
+ else
19
+ res[key] = val
20
+ end
21
+ res
22
+ end
23
+ end
24
+ if request.path_components.size() > 2
25
+ @params.merge!(:id => request.path_components[3])
26
+ end
27
+ @params
28
+ end
29
+
30
+ def fresh?(model, options={})
31
+ @@etags ||= {}
32
+ etag = Digest::SHA1.hexdigest(model.inspect)
33
+ response.header['ETag'] = "\"#{etag}\""
34
+ response.header['Expires'] = (MooTime.now + options[:expires_in]).httpdate if options[:expires_in]
35
+ response.header['Cache-Control'] = 'public'
36
+ if @@etags[request.uri] == etag
37
+ response.status = 304
38
+ response.body = ''
39
+ return true
40
+ else
41
+ @@etags[request.uri] = etag
42
+ return false
43
+ end
44
+ end
45
+
46
+ def controller
47
+ self.request.controller
48
+ end
49
+
50
+ def action
51
+ self.request.action
52
+ end
53
+
54
+ def indifferent_hash
55
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
56
+ end
57
+
58
+ def redirect(destination, options={})
59
+ destination = destination.to_s if destination.is_a? Symbol
60
+ unless destination[0,1] == "/"
61
+ destination = "/#{self.controller}/#{destination}"
62
+ end
63
+ puts "redirecting to #{destination}"
64
+
65
+ response.status = 302
66
+ response.header['Location'] = destination
67
+ return ""
68
+ end
69
+
70
+ end
71
+ end
data/lib/rambo/lock.rb ADDED
@@ -0,0 +1,18 @@
1
+ module Rack
2
+ class Lock
3
+ FLAG = 'rack.multithread'.freeze
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,39 @@
1
+ module Rambo
2
+ class Request < Rack::Request
3
+ def user_agent
4
+ @env['HTTP_USER_AGENT']
5
+ end
6
+
7
+ # Returns an array of acceptable media types for the response
8
+ def accept
9
+ @env['HTTP_ACCEPT'].to_s.split(',').map { |a| a.strip }
10
+ end
11
+
12
+ def path
13
+ env["REQUEST_PATH"]
14
+ end
15
+
16
+ def uri
17
+ env["REQUEST_URI"]
18
+ end
19
+
20
+ def path_components
21
+ @path_components ||= path.split('/')
22
+ end
23
+
24
+ def controller
25
+ path_components[1] || 'home'
26
+ end
27
+
28
+ def action
29
+ path_components[2] || 'index'
30
+ end
31
+
32
+ # Override Rack 0.9.x's #params implementation (see #72 in lighthouse)
33
+ def params
34
+ self.GET.update(self.POST)
35
+ rescue EOFError => boom
36
+ self.GET
37
+ end
38
+ end
39
+ 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
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'thin'
5
+
6
+ require 'rambo/lock'
7
+ require 'rambo/proxy'
8
+ require 'rambo/templating'
9
+ require 'rambo/base_controller'
10
+ require 'rambo/time'
11
+ require 'rambo/upload'
12
+ require 'rambo/request'
13
+ require 'rambo/response'
14
+
15
+ module Rambo
16
+ class Server
17
+
18
+ def initialize(options = {})
19
+ @options = options
20
+ # load from config - only do this IF database required
21
+ require 'dm-core'
22
+ require 'dm-validations'
23
+ require 'dm-timestamps'
24
+ #DataMapper.setup(:default, 'mysql://localhost/moo_development')
25
+ DataMapper.setup(:default, :adapter => :mysql, :host => 'localhost', :database => 'moo_development', :username => 'root', :password => '')
26
+ #DataObjects::Mysql.logger = DataObjects::Logger.new(STDOUT, :debug)
27
+ end
28
+
29
+ def call(env)
30
+ begin
31
+ Dir["controller/*.rb"].each { |x| funkyload x }
32
+ Dir["model/*.rb"].each { |x| funkyload x }
33
+ Dir["lib/*.rb"].each { |x| funkyload x }
34
+
35
+ request = Request.new(env)
36
+ response = Response.new
37
+
38
+ ctl_string = (request.controller.downcase.gsub(/^[a-z]|\s+[a-z]/) { |a| a.upcase } + 'Controller')
39
+ begin
40
+ obj = Object.module_eval("::#{ctl_string}", __FILE__, __LINE__).new
41
+ rescue Exception => e
42
+ return [404, response.header, "<h1>Controller #{ctl_string} Not Found</h1>"]
43
+ end
44
+ obj.request = request
45
+ obj.response = response
46
+
47
+ #begin
48
+ result = obj.send(request.action)
49
+ #rescue Exception => e
50
+ #return [404, response.header, "<h1>Action #{request.action} Not Found</h1>"]
51
+ #end
52
+ response.body = result if result
53
+
54
+ [response.status, response.header, response.body]
55
+ rescue Exception => e
56
+ puts e.message
57
+ return [500, response.header, "<pre><b>#{e.message.gsub("<","&lt;")}</b>\n#{e.backtrace.join("\n")}</pre>"]
58
+ end
59
+ end
60
+
61
+ private
62
+ # turn this into a thread that checks every x seconds
63
+ # (any chance of a callback?) so it is outside of the
64
+ # request/response cycle
65
+ def funkyload(file)
66
+ @@loadcache ||= {}
67
+ if cache = @@loadcache[file]
68
+ if (mtime = File.mtime(file)) > cache
69
+ puts "reloading: #{file}"
70
+ load file
71
+ @@loadcache[file] = mtime
72
+ end
73
+ else
74
+ puts "loading: #{file}"
75
+ load file
76
+ @@loadcache[file] = File.mtime(file)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,68 @@
1
+ module Templating
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
+ private
11
+ def render(engine, template, options={}, locals={})
12
+ # extract generic options
13
+ layout = options.delete(:layout)
14
+ layout = :layout if layout.nil? || layout == true
15
+ views = options.delete(:views) || "./view"
16
+ locals = options.delete(:locals) || locals || {}
17
+
18
+ # render template
19
+ data = lookup_template(engine, template, views)
20
+ output = __send__("render_#{engine}", template, data, options, locals)
21
+
22
+ # render layout
23
+ if layout && data = lookup_layout(engine, layout, views)
24
+ __send__("render_#{engine}", layout, data, options, {}) { output }
25
+ else
26
+ output
27
+ end
28
+ end
29
+
30
+ def lookup_template(engine, template, views_dir)
31
+ case template
32
+ when Symbol
33
+ # if cached = @@template_cache[template]
34
+ # cached
35
+ # else
36
+ path = ::File.join(views_dir, "#{template}.#{engine}")
37
+ res = ::File.read(path)
38
+ # @@template_cache[template] = res
39
+ # res
40
+ #end
41
+ when Proc
42
+ template.call
43
+ when String
44
+ template
45
+ else
46
+ raise ArgumentError
47
+ end
48
+ end
49
+
50
+ def lookup_layout(engine, template, views_dir)
51
+ lookup_template(engine, template, views_dir)
52
+ rescue Errno::ENOENT
53
+ nil
54
+ end
55
+
56
+ def render_erb(template, data, options, locals, &block)
57
+ original_out_buf = @_out_buf
58
+ data = data.call if data.kind_of? Proc
59
+
60
+ instance = ::ERB.new(data, nil, nil, '@_out_buf')
61
+ locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
62
+
63
+ src = "#{locals_assigns.join("\n")}\n#{instance.src}"
64
+ eval src, binding, '(__ERB__)', locals_assigns.length + 1
65
+ @_out_buf, result = original_out_buf, @_out_buf
66
+ result
67
+ end
68
+ 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
@@ -0,0 +1,16 @@
1
+ module Rack
2
+ class Upload
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ request = Rack::Request.new(env)
9
+
10
+ #puts "UPLOAD SAYS HELLO"
11
+
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+
data/lib/rambo.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'rambo/server'
2
+
3
+ module Rambo
4
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moomerman-rambo
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.3"
5
+ platform: ruby
6
+ authors:
7
+ - Richard Taylor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-17 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: oauth
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.3.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.2
34
+ version:
35
+ description: rambo is an experimental ruby web framework
36
+ email: moomerman@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - README
45
+ - lib/rambo.rb
46
+ - lib/rambo
47
+ - lib/rambo/base_controller.rb
48
+ - lib/rambo/lock.rb
49
+ - lib/rambo/server.rb
50
+ - lib/rambo/proxy.rb
51
+ - lib/rambo/request.rb
52
+ - lib/rambo/response.rb
53
+ - lib/rambo/templating.rb
54
+ - lib/rambo/time.rb
55
+ - lib/rambo/upload.rb
56
+ has_rdoc: false
57
+ homepage: http://github.com/moomerman/rambo
58
+ post_install_message:
59
+ rdoc_options:
60
+ - --inline-source
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project: rambo
79
+ rubygems_version: 1.2.0
80
+ signing_key:
81
+ specification_version: 2
82
+ summary: rambo is an experimental ruby web framework
83
+ test_files: []
84
+