Permalink
Browse files

Added README, LICENSE, and a demo app

  • Loading branch information...
1 parent 7cd76b1 commit 02cd4c4f1f49e5ec114ae34f409562b1c196c762 Larry Diehl committed Jun 14, 2009
Showing with 201 additions and 0 deletions.
  1. +19 −0 LICENSE
  2. +68 −0 README.textile
  3. +26 −0 demo/client.rb
  4. +3 −0 demo/config.ru
  5. +31 −0 demo/demo.rb
  6. +54 −0 demo/demo_spec.rb
View
@@ -0,0 +1,19 @@
+Copyright (c) 2009 Tim Carey-Smith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
@@ -0,0 +1,68 @@
+h1. What's this?
+
+Rack::Client is an HTTP client that aims to be a good Rack
+citizen.
+
+h1. Features
+
+h2. Rack responses
+
+Rack::Client can be used to make HTTP requests to any type of server, not
+just ones using Rack. However, when a request is made then a proper
+Rack response (specifically a Rack::MockResponse) object is returned.
+For Rubyists, this means you don't need to learn yet another interface
+and can just stick with Rack both on the server, test, and client side of
+things.
+
+h3. Examples:
+<pre>
+response = Rack::Client.get("http://some-website.com/blah.txt")
+response.code #=> 200
+response.body #=> "some body"
+</pre>
+
+h2. Middleware
+
+Rack::Client is actually a subclass of Rack::Builder. This means that
+Rack::Client objects yield actual Rack apps. More importantly, this
+means you can reuse existing Rack middleware on the client side too
+(but also feel free to make new middleware that only makes sense on
+the client side under the Rack::Client namespace). Note that by default
+Rack::Client will "run" Rack::Client::HTTP as an endpoint, but this
+will not be performed if you specify your own "run" endpoint.
+
+h3. Examples:
+<pre>
+client = Rack::Client.new { use Rack::ETag }
+response = client.get("http://localhost:9292/no-etag")
+</pre>
+
+h2. Rack::Test compatibility
+
+Rack::Client reuses a lot of Rack::Test to provide users with a
+familiar interface. What's even cooler is that you can use a
+Rack::Client object as your "app" in Rack::Test. This means that you
+can test-drive an application with Rack::Test, then when ready
+actually run your Rack app, switch your Rack::Test "app" to a
+Rack::Client, and get free full-blown integration testing! Note that
+the integration-tested server does not need to be all-Rack, so you can
+develop quickly with middleware like Rack::Cache but then remove it
+and integration test with a dedicated cache server like Varnish.
+
+h3. Examples:
+<pre>
+# NOTE: For a complete example, look in the "demo" directory
+describe Demo, "/store resource" do
+ include Rack::Test::Methods
+ def app
+ # replace this with Rack::Client.new
+ # for integration testing
+ Demo::App.new
+ end
+ # ... etc
+end
+</pre>
+
+h1. Contributors
+
+halorgium, larrytheliquid
View
@@ -0,0 +1,26 @@
+require "rubygems"
+require "rack/client"
+require "rack/contrib"
+
+puts "PUT'ing /store/fruit (with strawberry)"
+puts
+Rack::Client.put "http://localhost:9292/store/fruit", "strawberry"
+
+puts "GET'ing /store/fruit"
+response = Rack::Client.get "http://localhost:9292/store/fruit"
+puts ">> status: #{response.status}"
+puts ">> body: #{response.body.inspect}"
+puts ">> etag: #{response.headers["ETag"].inspect}"
+puts
+
+puts "GET'ing /store/fruit (with ETag middleware)"
+response = Rack::Client.new do
+ use Rack::ETag
+end.get "http://localhost:9292/store/fruit"
+puts ">> status: #{response.status}"
+puts ">> body: #{response.body.inspect}"
+puts ">> etag: #{response.headers["ETag"].inspect}"
+puts
+
+puts "DELETE'ing /store"
+Rack::Client.delete("http://localhost:9292/store")
View
@@ -0,0 +1,3 @@
+require File.expand_path(File.dirname(__FILE__) + "/demo")
+
+run Demo::App
View
@@ -0,0 +1,31 @@
+require "rubygems"
+require "rack"
+require "sinatra/base"
+
+module Demo
+ Store = Hash.new
+
+ class App < Sinatra::Base
+ get "/store/:id" do
+ if item = Store[ params[:id] ]
+ item
+ else
+ status 404
+ ""
+ end
+ end
+
+ put "/store/:id" do
+ Store[ params[:id] ] = request.body.read
+ end
+
+ delete "/store" do
+ Store.clear
+ ""
+ end
+
+ delete "/store/:id" do
+ Store.delete params[:id]
+ end
+ end
+end
View
@@ -0,0 +1,54 @@
+require "demo"
+require "rubygems"
+require "spec"
+require "rack"
+require "rack/test"
+require "rack/client"
+
+describe Demo, "/store resource" do
+ include Rack::Test::Methods
+ def app
+ # Be sure to run "rackup" on the config.ru in this demo directory
+ Rack::Client.new
+ # Demo::App.new
+ end
+ before(:all) { delete "http://localhost:9292/store" }
+ after { delete "http://localhost:9292/store" }
+
+ it "should return a 404 if a resource does not exist" do
+ get "http://localhost:9292/store/does-not-exist"
+ last_response.status.should == 404
+ last_response.body.should be_empty
+ end
+
+ it "should be able to store and retrieve invididual items" do
+ put "http://localhost:9292/store/fruit", "strawberry"
+ put "http://localhost:9292/store/car", "lotus"
+ get "http://localhost:9292/store/fruit"
+ last_response.status.should == 200
+ last_response.body.should == "strawberry"
+ get "http://localhost:9292/store/car"
+ last_response.status.should == 200
+ last_response.body.should == "lotus"
+ end
+
+ it "should be able to clear the store of all items" do
+ put "http://localhost:9292/store/fruit", "strawberry"
+ put "http://localhost:9292/store/car", "lotus"
+ delete "http://localhost:9292/store"
+ get "http://localhost:9292/store/fruit"
+ last_response.status.should == 404
+ last_response.body.should be_empty
+ get "http://localhost:9292/store/car"
+ last_response.status.should == 404
+ last_response.body.should be_empty
+ end
+
+ it "should be able to clear the store of an invididual item" do
+ put "http://localhost:9292/store/fruit", "strawberry"
+ delete "http://localhost:9292/store/fruit"
+ get "http://localhost:9292/store/fruit"
+ last_response.status.should == 404
+ last_response.body.should be_empty
+ end
+end

0 comments on commit 02cd4c4

Please sign in to comment.