Skip to content

Commit

Permalink
Merge pull request #52 from lgierth/hatetepe-adapter
Browse files Browse the repository at this point in the history
Hatetepe adapter
  • Loading branch information
Lars Gierth committed Aug 18, 2012
2 parents c89fe90 + 75a8340 commit aedcfa2
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ end
Webmachine.application.run
```

Webmachine includes adapters for [Webrick](http://rubydoc.info/stdlib/webrick), [Mongrel](https://github.com/evan/mongrel), and [Hatetepe](https://github.com/lgierth/hatetepe). Additionally, the [Rack](https://github.com/rack/rack) adapter lets it run on any webserver that provides a Rack interface.

### Visual debugger

It can be hard to understand all of the decisions that Webmachine
Expand Down
3 changes: 2 additions & 1 deletion lib/webmachine/adapters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Webmachine
# Contains classes and modules that connect Webmachine to Ruby
# application servers.
module Adapters
autoload :Mongrel, 'webmachine/adapters/mongrel'
autoload :Mongrel, 'webmachine/adapters/mongrel'
autoload :Hatetepe, 'webmachine/adapters/hatetepe'
end
end
104 changes: 104 additions & 0 deletions lib/webmachine/adapters/hatetepe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
require 'hatetepe/server'

unless Hatetepe::VERSION >= '0.5.0'
raise LoadError, 'webmachine only supports hatetepe >= 0.5.0'
end

require 'webmachine/version'
require 'webmachine/headers'
require 'webmachine/request'
require 'webmachine/response'
require 'webmachine/dispatcher'
require 'webmachine/chunked_body'

module Webmachine
module Adapters
class Hatetepe < Adapter
def options
{
:host => configuration.ip,
:port => configuration.port,
:app => [
::Hatetepe::Server::Pipeline,
::Hatetepe::Server::KeepAlive,
method(:call)
]
}
end

def run
EM.epoll
EM.synchrony do
::Hatetepe::Server.start(options)
trap("INT") { EM.stop }
end
end

def call(request, &respond)
response = Webmachine::Response.new
dispatcher.dispatch(convert_request(request), response)

respond.call(convert_response(response))
end

private

def convert_request(request)
args = [
request.verb,
build_request_uri(request),
Webmachine::Headers[request.headers.map {|k, v| [k.downcase, v] }],
Body.new(request.body)
]
Webmachine::Request.new(*args)
end

def convert_response(response)
response.headers["Server"] = [
Webmachine::SERVER_STRING,
"hatetepe/#{::Hatetepe::VERSION}"
].join(" ")

args = [
response.code.to_i,
response.headers,
convert_body(response.body)
]
::Hatetepe::Response.new(*args)
end

def convert_body(body)
if body.respond_to?(:call)
[ body.call ]
elsif body.respond_to?(:to_s)
[ body.to_s ]
else
body
end
end

def build_request_uri(request)
uri = URI.parse(request.uri)
uri.scheme = "http"

host = request.headers.fetch("Host", "").split(":")
uri.host = host[0] || configuration.ip
uri.port = host[1].to_i || configuration.port

URI.parse(uri.to_s)
end

class Body < Struct.new(:body)
def each(&block)
body.rewind
body.each(&block)
end

def to_s
body.rewind
body.read.to_s
end
end
end
end
end
64 changes: 64 additions & 0 deletions spec/webmachine/adapters/hatetepe_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require "spec_helper"

examples = proc do
let(:configuration) { Webmachine::Configuration.default }
let(:dispatcher) { Webmachine::Dispatcher.new }
let(:adapter) { described_class.new(configuration, dispatcher) }

it "inherits from Webmachine::Adapter" do
adapter.should be_a(Webmachine::Adapter)
end

describe "#run" do
it "starts a server" do
Hatetepe::Server.should_receive(:start).with(adapter.options) { EM.stop }
adapter.run
end
end

describe "#call" do
let :request do
Hatetepe::Request.new(:get, "/", {}, StringIO.new("hello, world!"))
end

it "builds a string-like and enumerable request body" do
dispatcher.should_receive(:dispatch) do |req, res|
req.body.to_s.should eq("hello, world!")
enum_to_s(req.body).should eq("hello, world!")
end
adapter.call(request) {}
end

shared_examples "enumerable response body" do
before do
dispatcher.stub(:dispatch) {|_, response| response.body = body }
end

it "builds an enumerable response body" do
adapter.call(request) do |response|
enum_to_s(response.body).should eq("bye, world!")
end
end
end

describe "with normal response" do
let(:body) { "bye, world!" }

it_behaves_like "enumerable response body"
end

describe "with streaming response" do
let(:body) { proc { "bye, world!" } }

it_behaves_like "enumerable response body"
end
end

def enum_to_s(enum)
Enumerator.new(enum).to_a.join
end
end

if RUBY_VERSION >= "1.9"
describe Webmachine::Adapters::Hatetepe, &examples
end
1 change: 1 addition & 0 deletions webmachine.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Gem::Specification.new do |gem|
gem.add_development_dependency(%q<yard>, ["~> 0.7.3"])
gem.add_development_dependency(%q<rake>)
gem.add_development_dependency(%q<mongrel>, ['~>1.2.beta'])
gem.add_development_dependency(%q<hatetepe>, ['~> 0.5'])
gem.add_development_dependency(%q<rack>)
gem.add_development_dependency(%q<rack-test>)

Expand Down

0 comments on commit aedcfa2

Please sign in to comment.