moomerman-rambo 0.3

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/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
+