Created
July 17, 2009 11:01
-
-
Save madx/149002 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Rackable is a tiny module that aims to provide a REST-like interface to | |
# any object. | |
# | |
# It uses Rack under the hood, thus any âRackedâ object is a valid Rack | |
# application. | |
# | |
# I really don't know if this is useful, but it's more a proof of concept than | |
# anything. | |
module Rackable | |
attr_accessor :response, :env, :header | |
attr_reader :request, :data, :query | |
def call(env) | |
@env = env | |
@request = Rack::Request.new(env) | |
@response = Rack::Response.new | |
@header = response.header | |
@query = request.GET.inject({}) {|h, (k,v)| h[k.to_sym] = v; h } | |
@data = request.POST.inject({}) {|h, (k,v)| h[k.to_sym] = v; h } | |
method = env['REQUEST_METHOD'].downcase.to_sym | |
args = env['PATH_INFO'][1..-1].split('/').collect { |arg| | |
Rack::Utils.unescape(arg) | |
} | |
status, body = catch(:halt) do | |
begin | |
[200, response.write(send(method, *args))] | |
rescue NoMethodError | |
header['Allow'] = valid_methods.join(', ') | |
http_error 405 | |
rescue ArgumentError | |
http_error 400 | |
end | |
end | |
response.status = status | |
if status != 200 | |
response.body = body | |
response.length = header['Content-Length'] = | |
Rack::Utils.bytesize(body).to_s | |
end | |
response.finish | |
end | |
private | |
def valid_methods | |
[:get, :post, :put, :delete].delete_if {|m| !respond_to?(m) }.map { |m| | |
m.to_s.upcase | |
} | |
end | |
def http_error(code) | |
throw :halt, [code, Rack::Utils::HTTP_STATUS_CODES[code]] | |
end | |
end | |
if $0 =~ /bacon$/ | |
require 'rubygems' | |
require 'rack/test' | |
Bacon::Context.send :include, Rack::Test::Methods | |
class MockApp | |
include Rackable | |
def get(failing=nil) | |
http_error 404 if failing | |
"Hello, world" | |
end | |
end | |
def app | |
MockApp.new | |
end | |
describe Rackable do | |
it 'provides a call() method' do | |
app.should.respond_to :call | |
end | |
it 'calls the appropriate method on the racked object' do | |
get '/' | |
last_response.should.be.ok | |
last_response.body.should == app.get | |
end | |
it 'catches errors thrown inside the method' do | |
get '/fail' | |
last_response.status.should == 404 | |
last_response.body.should == 'Not Found' | |
end | |
it 'throws a 405 when the method is not defined' do | |
post '/' | |
last_response.status.should == 405 | |
last_response.headers['Allow'].should.not.include?('POST') | |
last_response.headers['Allow'].should. include?('GET') | |
end | |
it 'throws a 400 on argument errors' do | |
get '/foo/bar' | |
last_response.status.should == 400 | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require File.join(File.dirname(__FILE__), 'rackable') | |
class RestString | |
include Rackable | |
def initialize | |
@string = "Hello, world!" | |
end | |
def get() | |
@string | |
end | |
def put() | |
if data[:body] | |
@string << data[:body] | |
else | |
http_error 400 | |
end | |
end | |
def delete() | |
@string = "" | |
end | |
end | |
run RestString.new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment