Permalink
Browse files

Merge pull request #52 from lgierth/hatetepe-adapter

Hatetepe adapter
  • Loading branch information...
2 parents c89fe90 + 75a8340 commit aedcfa2c55d396da5729fac84b5922f2261e97b1 @lgierth lgierth committed Aug 18, 2012
Showing with 173 additions and 1 deletion.
  1. +2 −0 README.md
  2. +2 −1 lib/webmachine/adapters.rb
  3. +104 −0 lib/webmachine/adapters/hatetepe.rb
  4. +64 −0 spec/webmachine/adapters/hatetepe_spec.rb
  5. +1 −0 webmachine.gemspec
View
2 README.md
@@ -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
View
3 lib/webmachine/adapters.rb
@@ -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
View
104 lib/webmachine/adapters/hatetepe.rb
@@ -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
View
64 spec/webmachine/adapters/hatetepe_spec.rb
@@ -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
View
1 webmachine.gemspec
@@ -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>)

0 comments on commit aedcfa2

Please sign in to comment.