rack-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 0.1.0 / 2009-06-14
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Tim Carey-Smith
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,63 @@
1
+ h1. What's this?
2
+
3
+ Rack::Client is an HTTP client that aims to be a good Rack
4
+ citizen.
5
+
6
+ h2. Rack responses
7
+
8
+ Rack::Client can be used to make HTTP requests to any type of server, not
9
+ just ones using Rack. However, when a request is made then a proper
10
+ Rack response (specifically a Rack::MockResponse) object is returned.
11
+ For Rubyists, this means you don't need to learn yet another interface
12
+ and can just stick with Rack both on the server, test, and client side of
13
+ things.
14
+
15
+ <pre>
16
+ response = Rack::Client.get("http://some-website.com/blah.txt")
17
+ response.code #=> 200
18
+ response.body #=> "some body"
19
+ </pre>
20
+
21
+ h2. Middleware
22
+
23
+ Rack::Client is actually a subclass of Rack::Builder. This means that
24
+ Rack::Client objects yield actual Rack apps. More importantly, this
25
+ means you can reuse existing Rack middleware on the client side too
26
+ (but also feel free to make new middleware that only makes sense on
27
+ the client side under the Rack::Client namespace). Note that by default
28
+ Rack::Client will "run" Rack::Client::HTTP as an endpoint, but this
29
+ will not be performed if you specify your own "run" endpoint.
30
+
31
+ <pre>
32
+ client = Rack::Client.new { use Rack::ETag }
33
+ response = client.get("http://localhost:9292/no-etag")
34
+ </pre>
35
+
36
+ h2. Rack::Test compatibility
37
+
38
+ Rack::Client reuses a lot of Rack::Test to provide users with a
39
+ familiar interface. What's even cooler is that you can use a
40
+ Rack::Client object as your "app" in Rack::Test. This means that you
41
+ can test-drive an application with Rack::Test, then when ready
42
+ actually run your Rack app, switch your Rack::Test "app" to a
43
+ Rack::Client, and get free full-blown integration testing! Note that
44
+ the integration-tested server does not need to be all-Rack, so you can
45
+ develop quickly with middleware like Rack::Cache but then remove it
46
+ and integration test with a dedicated cache server like Varnish.
47
+
48
+ <pre>
49
+ # NOTE: For a complete example, look in the "demo" directory
50
+ describe Demo, "/store resource" do
51
+ include Rack::Test::Methods
52
+ def app
53
+ # replace this with Rack::Client.new
54
+ # for integration testing
55
+ Demo::App.new
56
+ end
57
+ # ... etc
58
+ end
59
+ </pre>
60
+
61
+ h1. Contributors
62
+
63
+ halorgium, larrytheliquid
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require 'rake'
2
+ require "rake/gempackagetask"
3
+ require "rake/clean"
4
+ require "spec/rake/spectask"
5
+ require File.expand_path("./lib/rack/client")
6
+
7
+ Spec::Rake::SpecTask.new(:spec) do |t|
8
+ t.spec_files = FileList['spec/*_spec.rb']
9
+ t.spec_opts = ['-c']
10
+ end
11
+
12
+ task :default => :spec
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = "rack-client"
16
+ s.version = Rack::Client::VERSION
17
+ s.author = "Tim Carey-Smith"
18
+ s.email = "time" + "@" + "spork.in"
19
+ s.homepage = "http://github.com/halorgium/rack-client"
20
+ s.summary = "A client wrapper around a Rack app or HTTP"
21
+ s.description = s.summary
22
+ s.files = %w[History.txt LICENSE README.textile Rakefile] + Dir["lib/**/*"] + Dir["demo/**/*"]
23
+ s.test_files = Dir["spec/**/*"]
24
+ end
25
+
26
+ Rake::GemPackageTask.new(spec) do |package|
27
+ package.gem_spec = spec
28
+ end
29
+
30
+ desc 'Install the package as a gem.'
31
+ task :install => [:clean, :package] do
32
+ gem = Dir['pkg/*.gem'].first
33
+ sh "sudo gem install --no-rdoc --no-ri --local #{gem}"
34
+ end
data/demo/client.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "rubygems"
2
+ require "rack/client"
3
+ require "rack/contrib"
4
+
5
+ puts "PUT'ing /store/fruit (with strawberry)"
6
+ puts
7
+ Rack::Client.put "http://localhost:9292/store/fruit", "strawberry"
8
+
9
+ puts "GET'ing /store/fruit"
10
+ response = Rack::Client.get "http://localhost:9292/store/fruit"
11
+ puts ">> status: #{response.status}"
12
+ puts ">> body: #{response.body.inspect}"
13
+ puts ">> etag: #{response.headers["ETag"].inspect}"
14
+ puts
15
+
16
+ puts "GET'ing /store/fruit (with ETag middleware)"
17
+ response = Rack::Client.new do
18
+ use Rack::ETag
19
+ end.get "http://localhost:9292/store/fruit"
20
+ puts ">> status: #{response.status}"
21
+ puts ">> body: #{response.body.inspect}"
22
+ puts ">> etag: #{response.headers["ETag"].inspect}"
23
+ puts
24
+
25
+ puts "DELETE'ing /store"
26
+ Rack::Client.delete("http://localhost:9292/store")
data/demo/config.ru ADDED
@@ -0,0 +1,3 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/demo")
2
+
3
+ run Demo::App
data/demo/demo.rb ADDED
@@ -0,0 +1,31 @@
1
+ require "rubygems"
2
+ require "rack"
3
+ require "sinatra/base"
4
+
5
+ module Demo
6
+ Store = Hash.new
7
+
8
+ class App < Sinatra::Base
9
+ get "/store/:id" do
10
+ if item = Store[ params[:id] ]
11
+ item
12
+ else
13
+ status 404
14
+ ""
15
+ end
16
+ end
17
+
18
+ put "/store/:id" do
19
+ Store[ params[:id] ] = request.body.read
20
+ end
21
+
22
+ delete "/store" do
23
+ Store.clear
24
+ ""
25
+ end
26
+
27
+ delete "/store/:id" do
28
+ Store.delete params[:id]
29
+ end
30
+ end
31
+ end
data/demo/demo_spec.rb ADDED
@@ -0,0 +1,54 @@
1
+ require "demo"
2
+ require "rubygems"
3
+ require "spec"
4
+ require "rack"
5
+ require "rack/test"
6
+ require "rack/client"
7
+
8
+ describe Demo, "/store resource" do
9
+ include Rack::Test::Methods
10
+ def app
11
+ # Be sure to run "rackup" on the config.ru in this demo directory
12
+ Rack::Client.new
13
+ # Demo::App.new
14
+ end
15
+ before(:all) { delete "http://localhost:9292/store" }
16
+ after { delete "http://localhost:9292/store" }
17
+
18
+ it "should return a 404 if a resource does not exist" do
19
+ get "http://localhost:9292/store/does-not-exist"
20
+ last_response.status.should == 404
21
+ last_response.body.should be_empty
22
+ end
23
+
24
+ it "should be able to store and retrieve invididual items" do
25
+ put "http://localhost:9292/store/fruit", "strawberry"
26
+ put "http://localhost:9292/store/car", "lotus"
27
+ get "http://localhost:9292/store/fruit"
28
+ last_response.status.should == 200
29
+ last_response.body.should == "strawberry"
30
+ get "http://localhost:9292/store/car"
31
+ last_response.status.should == 200
32
+ last_response.body.should == "lotus"
33
+ end
34
+
35
+ it "should be able to clear the store of all items" do
36
+ put "http://localhost:9292/store/fruit", "strawberry"
37
+ put "http://localhost:9292/store/car", "lotus"
38
+ delete "http://localhost:9292/store"
39
+ get "http://localhost:9292/store/fruit"
40
+ last_response.status.should == 404
41
+ last_response.body.should be_empty
42
+ get "http://localhost:9292/store/car"
43
+ last_response.status.should == 404
44
+ last_response.body.should be_empty
45
+ end
46
+
47
+ it "should be able to clear the store of an invididual item" do
48
+ put "http://localhost:9292/store/fruit", "strawberry"
49
+ delete "http://localhost:9292/store/fruit"
50
+ get "http://localhost:9292/store/fruit"
51
+ last_response.status.should == 404
52
+ last_response.body.should be_empty
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__) + "/.."))
2
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/.."))
3
+ end
4
+
5
+ require 'rack'
6
+ require 'rack/test'
7
+ require 'forwardable'
8
+
9
+ module Rack
10
+ class Client < Rack::Builder
11
+ VERSION = "0.1.0"
12
+ include Rack::Test::Methods
13
+ HTTP_METHODS = [:head, :get, :put, :post, :delete]
14
+
15
+ class << self
16
+ extend Forwardable
17
+ def_delegators :new, *HTTP_METHODS
18
+ end
19
+
20
+ def run(*args, &block)
21
+ @ran = true
22
+ super(*args, &block)
23
+ end
24
+
25
+ def to_app(*args, &block)
26
+ run Rack::Client::HTTP unless @ran
27
+ super(*args, &block)
28
+ end
29
+ alias app to_app
30
+ end
31
+ end
32
+
33
+ $:.unshift File.dirname(__FILE__)
34
+
35
+ require 'client/http'
36
+ require 'client/auth'
37
+ require 'client/follow_redirects'
@@ -0,0 +1,13 @@
1
+ module Rack::Client::Auth
2
+ class Basic
3
+ def initialize(app, username, password)
4
+ @app, @username, @password = app, username, password
5
+ end
6
+
7
+ def call(env)
8
+ encoded_login = ["#{@username}:#{@password}"].pack("m*")
9
+ env['HTTP_AUTHORIZATION'] = "Basic #{encoded_login}"
10
+ @app.call(env)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ class Rack::Client::FollowRedirects
2
+ include Rack::Test::Methods
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ status, headers, body = @app.call(env)
10
+ response = Rack::Response.new(body, status, headers)
11
+ if response.redirect?
12
+ uri = URI.parse(response["Location"])
13
+ new_env = {}
14
+ env.each do |k,v|
15
+ if %w| HTTP_HOST SERVER_NAME SERVER_PORT |.include?(k)
16
+ new_env[k] = v
17
+ end
18
+ end
19
+ new_env["REQUEST_METHOD"] = "GET"
20
+ session = Rack::Test::Session.new(@app)
21
+ env = session.send(:env_for, uri.to_s, new_env)
22
+ call(env)
23
+ else
24
+ [status, headers, body]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,77 @@
1
+ require 'net/http'
2
+
3
+ class Rack::Client::HTTP
4
+ def self.call(env)
5
+ new(env).run
6
+ end
7
+
8
+ def initialize(env)
9
+ @env = env
10
+ end
11
+
12
+ def run
13
+ case request.request_method
14
+ when "HEAD"
15
+ head = Net::HTTP::Head.new(request.path, request_headers)
16
+ http.request(head) do |response|
17
+ return parse(response)
18
+ end
19
+ when "GET"
20
+ get = Net::HTTP::Get.new(request.path, request_headers)
21
+ http.request(get) do |response|
22
+ return parse(response)
23
+ end
24
+ when "POST"
25
+ post = Net::HTTP::Post.new(request.path, request_headers)
26
+ post.body = @env["rack.input"].read
27
+ http.request(post) do |response|
28
+ return parse(response)
29
+ end
30
+ when "PUT"
31
+ put = Net::HTTP::Put.new(request.path, request_headers)
32
+ put.body = @env["rack.input"].read
33
+ http.request(put) do |response|
34
+ return parse(response)
35
+ end
36
+ when "DELETE"
37
+ delete = Net::HTTP::Delete.new(request.path, request_headers)
38
+ http.request(delete) do |response|
39
+ return parse(response)
40
+ end
41
+ else
42
+ raise "Unsupported method: #{request.request_method.inspect}"
43
+ end
44
+ end
45
+
46
+ def http
47
+ Net::HTTP.new(request.host, request.port)
48
+ end
49
+
50
+ def parse(response)
51
+ status = response.code.to_i
52
+ headers = {}
53
+ response.each do |key,value|
54
+ key = key.gsub(/(\w+)/) do |matches|
55
+ matches.sub(/^./) do |char|
56
+ char.upcase
57
+ end
58
+ end
59
+ headers[key] = value
60
+ end
61
+ [status, headers, response.body.to_s]
62
+ end
63
+
64
+ def request
65
+ @request ||= Rack::Request.new(@env)
66
+ end
67
+
68
+ def request_headers
69
+ headers = {}
70
+ @env.each do |k,v|
71
+ if k =~ /^HTTP_(.*)$/
72
+ headers[$1] = v
73
+ end
74
+ end
75
+ headers
76
+ end
77
+ end
@@ -0,0 +1,84 @@
1
+ require 'sinatra/base'
2
+
3
+ class ExampleOrg < Sinatra::Base
4
+ get "/empty" do
5
+ ""
6
+ end
7
+
8
+ get "/ping" do
9
+ "pong"
10
+ end
11
+
12
+ get "/redirect" do
13
+ redirect request.script_name + "/after-redirect"
14
+ end
15
+
16
+ get "/after-redirect" do
17
+ "after redirect"
18
+ end
19
+
20
+ head "/shelf" do
21
+ response["ETag"] = "828ef3fdfa96f00ad9f27c383fc9ac7f"
22
+ ""
23
+ end
24
+
25
+ put "/shelf/:book" do
26
+ response["Location"] = "/shelf/#{params[:book]}"
27
+ ""
28
+ end
29
+
30
+ delete "/shelf/:book" do
31
+ status 204
32
+ ""
33
+ end
34
+
35
+ post "/posted" do
36
+ if request.body.read == "some data"
37
+ status 201
38
+ response["Created"] = "awesome"
39
+ ""
40
+ else
41
+ raise "Not valid"
42
+ end
43
+ end
44
+
45
+ get "/no-etag" do
46
+ ""
47
+ end
48
+ end
49
+
50
+ require 'pp'
51
+ class Debug
52
+ def initialize(app)
53
+ @app = app
54
+ end
55
+
56
+ def call(env)
57
+ puts "*" * 80
58
+ puts "env is:"
59
+ pp env
60
+ res = @app.call(env)
61
+ puts "response is:"
62
+ pp res
63
+ puts "*" * 80
64
+ res
65
+ end
66
+ end
67
+
68
+ use Rack::CommonLogger
69
+ use Debug if ENV["DEBUG"]
70
+
71
+ map "http://localhost/" do
72
+ map "/auth/" do
73
+ use Rack::Auth::Basic do |username,password|
74
+ username == "username" && password == "password"
75
+ end
76
+ run ExampleOrg
77
+ end
78
+
79
+ map "/" do
80
+ run ExampleOrg
81
+ end
82
+ end
83
+
84
+ # vim:filetype=ruby
data/spec/auth_spec.rb ADDED
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Rack::Client, "with an Auth::Basic middleware" do
4
+ it "succeeds with authorization" do
5
+ client = Rack::Client.new do
6
+ use Rack::Client::Auth::Basic, "username", "password"
7
+ end
8
+ response = client.get("http://localhost:9292/auth/ping")
9
+ response.status.should == 200
10
+ response.headers["Content-Type"].should == "text/html"
11
+ response.body.should == "pong"
12
+ end
13
+
14
+ it "fails with authorization" do
15
+ client = Rack::Client.new do
16
+ use Rack::Client::Auth::Basic, "username", "fail"
17
+ end
18
+ response = client.get("http://localhost:9292/auth/ping")
19
+ response.status.should == 401
20
+ response.body.should == ""
21
+ end
22
+ end
data/spec/core_spec.rb ADDED
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Rack::Client, "without middleware" do
4
+ context "at the instance level" do
5
+ it "returns an empty body" do
6
+ response = Rack::Client.new.get("http://localhost:9292/empty")
7
+ response.status.should == 200
8
+ response.headers["Content-Type"].should == "text/html"
9
+ response.headers["Content-Length"].should == "0"
10
+ response.body.should == ""
11
+ end
12
+
13
+ it "returns a 302" do
14
+ response = Rack::Client.new.get("http://localhost:9292/redirect")
15
+ response.status.should == 302
16
+ response["Location"].should == "/after-redirect"
17
+ end
18
+
19
+ it "heads data" do
20
+ response = Rack::Client.new.head "http://localhost:9292/shelf"
21
+ response.status.should == 200
22
+ response["ETag"].should == "828ef3fdfa96f00ad9f27c383fc9ac7f"
23
+ end
24
+
25
+ it "puts data" do
26
+ response = Rack::Client.new.put "http://localhost:9292/shelf/ctm", "some data"
27
+ response.status.should == 200
28
+ response["Location"].should == "/shelf/ctm"
29
+ end
30
+
31
+ it "deletes data" do
32
+ response = Rack::Client.new.delete "http://localhost:9292/shelf/ctm"
33
+ response.status.should == 204
34
+ end
35
+
36
+ it "posts data" do
37
+ response = Rack::Client.new.post("http://localhost:9292/posted", "some data")
38
+ response.status.should == 201
39
+ response["Created"].should == "awesome"
40
+ end
41
+ end
42
+
43
+ context "at the class level" do
44
+ it "returns an empty body" do
45
+ response = Rack::Client.get("http://localhost:9292/empty")
46
+ response.status.should == 200
47
+ response.headers["Content-Type"].should == "text/html"
48
+ response.headers["Content-Length"].should == "0"
49
+ response.body.should == ""
50
+ end
51
+
52
+ it "returns a 302" do
53
+ response = Rack::Client.get("http://localhost:9292/redirect")
54
+ response.status.should == 302
55
+ response["Location"].should == "/after-redirect"
56
+ end
57
+
58
+ it "heads data" do
59
+ response = Rack::Client.head "http://localhost:9292/shelf"
60
+ response.status.should == 200
61
+ response["ETag"].should == "828ef3fdfa96f00ad9f27c383fc9ac7f"
62
+ end
63
+
64
+ it "puts data" do
65
+ response = Rack::Client.put "http://localhost:9292/shelf/ctm", "some data"
66
+ response.status.should == 200
67
+ response["Location"].should == "/shelf/ctm"
68
+ end
69
+
70
+ it "deletes data" do
71
+ response = Rack::Client.delete "http://localhost:9292/shelf/ctm"
72
+ response.status.should == 204
73
+ end
74
+
75
+ it "posts data" do
76
+ response = Rack::Client.post("http://localhost:9292/posted", "some data")
77
+ response.status.should == 201
78
+ response["Created"].should == "awesome"
79
+ end
80
+ end
81
+
82
+ context "at the rack-test level" do
83
+ include Rack::Test::Methods
84
+ def app() Rack::Client.new end
85
+
86
+ it "returns an empty body" do
87
+ get "http://localhost:9292/empty"
88
+ last_response.status.should == 200
89
+ last_response.headers["Content-Type"].should == "text/html"
90
+ last_response.headers["Content-Length"].should == "0"
91
+ last_response.body.should == ""
92
+ end
93
+
94
+ it "returns a 302" do
95
+ get "http://localhost:9292/redirect"
96
+ last_response.status.should == 302
97
+ last_response["Location"].should == "/after-redirect"
98
+ end
99
+
100
+ it "heads data" do
101
+ head "http://localhost:9292/shelf"
102
+ last_response.status.should == 200
103
+ last_response["ETag"].should == "828ef3fdfa96f00ad9f27c383fc9ac7f"
104
+ end
105
+
106
+ it "puts data" do
107
+ put "http://localhost:9292/shelf/ctm", "some data"
108
+ last_response.status.should == 200
109
+ last_response["Location"].should == "/shelf/ctm"
110
+ end
111
+
112
+ it "deletes data" do
113
+ delete "http://localhost:9292/shelf/ctm"
114
+ last_response.status.should == 204
115
+ end
116
+
117
+ it "posts data" do
118
+ post "http://localhost:9292/posted", "some data"
119
+ last_response.status.should == 201
120
+ last_response["Created"].should == "awesome"
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'sinatra/base'
4
+
5
+ class MyApp < Sinatra::Base
6
+ get "/awesome" do
7
+ "test"
8
+ end
9
+ end
10
+
11
+ describe Rack::Client, "with an Rack app endpoint" do
12
+ it "returns the body" do
13
+ client = Rack::Client.new do
14
+ run Rack::URLMap.new("http://example.org/" => MyApp)
15
+ end
16
+ response = client.get("http://example.org/awesome")
17
+ response.status.should == 200
18
+ response.body.should == "test"
19
+ end
20
+
21
+ describe "with a custom domain" do
22
+ it "returns the body" do
23
+ client = Rack::Client.new do
24
+ run Rack::URLMap.new("http://google.com/" => MyApp)
25
+ end
26
+ response = client.get("http://google.com/awesome")
27
+ response.status.should == 200
28
+ response.body.should == "test"
29
+ end
30
+
31
+ it "only functions for that domain" do
32
+ client = Rack::Client.new do
33
+ run Rack::URLMap.new("http://google.com/" => MyApp)
34
+ end
35
+ response = client.get("http://example.org/")
36
+ response.status.should == 404
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Rack::Client, "with a standard piece of Rack middleware" do
4
+ it "successfully uses that middleware" do
5
+ client = Rack::Client.new { use Rack::ETag }
6
+ response = client.get("http://localhost:9292/no-etag")
7
+ response.status.should == 200
8
+ response.headers["ETag"].should_not be_empty
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Rack::Client, "with a FollowRedirects middleware" do
4
+ it "follows redirects" do
5
+ client = Rack::Client.new do
6
+ use Rack::Client::FollowRedirects
7
+ end
8
+ response = client.get("http://localhost:9292/redirect")
9
+ response.status.should == 200
10
+ response.body.should == "after redirect"
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'rack/contrib'
4
+ gem 'rack-test'
5
+
6
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/rack/client")
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tim Carey-Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-14 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A client wrapper around a Rack app or HTTP
17
+ email: time@spork.in
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - History.txt
26
+ - LICENSE
27
+ - README.textile
28
+ - Rakefile
29
+ - lib/rack
30
+ - lib/rack/client
31
+ - lib/rack/client/auth.rb
32
+ - lib/rack/client/http.rb
33
+ - lib/rack/client/follow_redirects.rb
34
+ - lib/rack/client.rb
35
+ - demo/config.ru
36
+ - demo/demo_spec.rb
37
+ - demo/client.rb
38
+ - demo/demo.rb
39
+ has_rdoc: false
40
+ homepage: http://github.com/halorgium/rack-client
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.3.1
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: A client wrapper around a Rack app or HTTP
65
+ test_files:
66
+ - spec/redirect_spec.rb
67
+ - spec/auth_spec.rb
68
+ - spec/spec_helper.rb
69
+ - spec/apps
70
+ - spec/apps/example.org.ru
71
+ - spec/endpoint_spec.rb
72
+ - spec/core_spec.rb
73
+ - spec/middleware_spec.rb