rack-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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