redrock 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,88 @@
1
+ = RedRock
2
+
3
+ == What is this?
4
+
5
+ A wrapper for running WebMock[link:http://github.com/bblimke/webmock] remotely
6
+ (ie mocking requests made by an application that's not running in the same
7
+ process as your tests).
8
+
9
+ == When might I want to use it?
10
+
11
+ If you're testing an application that makes remote web requests, and for some
12
+ reason you can't run the application code directly inside your test framework.
13
+ This might be because you're running integration tests against a stack of
14
+ applications, you're using something like
15
+ Culerity[link:http://github.com/langalex/culerity] or
16
+ Selenium[link:http://seleniumhq.org/], or maybe the application doesn't use one
17
+ of the HTTP libraries that WebMock supports, or isn't even written in Ruby.
18
+
19
+ == Getting started
20
+
21
+ gem install redrock
22
+
23
+ Somewhere in your tests:
24
+
25
+ require "redrock"
26
+ include RedRock
27
+
28
+ You can then make most of the same calls you would normally make to WebMock,
29
+ and they will be transparently handled by RedRock. For example:
30
+
31
+ stub_request :any, "localhost:4242/chunky/bacon"
32
+ # ...
33
+ RedRock.should have_requested :get, "http://localhost:4242/chunky/bacon"
34
+
35
+ The RedRock server starts automatically when required, but you can start it
36
+ manually if you want to run it on a different port:
37
+
38
+ RedRock.start 1234
39
+
40
+ You can also stop it manually:
41
+
42
+ RedRock.stop
43
+
44
+ If you want to use a host other than localhost, you can map it in
45
+ <tt>/etc/hosts</tt>. If you can't override the port your application talks to,
46
+ you'll have to set up a reverse proxy as well.
47
+
48
+ == How does it work?
49
+
50
+ RedRock fires up a thin[link:http://code.macournoyer.com/thin/] server (by
51
+ default on port 4242), which attempts to proxy all incoming requests using
52
+ Net::HTTP, at which point they are intercepted by WebMock. You point your
53
+ application under test at this server, instead of the real service it's
54
+ supposed to interact with.
55
+
56
+ All calls to WebMock methods in your tests are proxied through to the RedRock
57
+ server, which means that stubs and expectations are effectively being applied
58
+ to the requests being made by the application under test.
59
+
60
+ === Unsupported WebMock features
61
+
62
+ Allowing real requests doesn't really make any sense for RedRock, so if you
63
+ call <tt>allow_net_connect!</tt> or <tt>disable_net_connect!</tt> you'll get an
64
+ error.
65
+
66
+ Raising exceptions or timing out won't work as expected, because the exceptions
67
+ will be handled in the RedRock server, not the application under test.
68
+
69
+ == TODO
70
+
71
+ * Better documentation!
72
+ * Refactor the server, which is currently a small ball of mud.
73
+
74
+ == Why "RedRock"?
75
+
76
+ I started with "Remote WebMock". "RWebMock" doesn't exactly trip off the
77
+ tongue, so I thought maybe "RebMock". That sounded like Scooby-Doo saying
78
+ "WebMock", although he'd probably say "RebRock". That sounded almost like
79
+ "RedRock", which is where I stopped. I'm a bit surprised that there isn't
80
+ already a redrock gem, given that a ruby is basically a red rock, but hey,
81
+ you've had seven years or so.
82
+
83
+ == Other random stuff
84
+
85
+ Version 0.1.0 was released on Whyday, 19 August 2010.
86
+
87
+ RedRock is intended to replace FakeTTP[link:http://github.com/kerryb/fakettp],
88
+ which no-one apart from me and a few colleagues ever used.
@@ -0,0 +1,43 @@
1
+ require "thin"
2
+ require "net/http"
3
+ require "json"
4
+ require "webmock"
5
+ require "webmock/rspec"
6
+
7
+ Thin::Logging.silent = true
8
+
9
+ module RedRock
10
+ class Server
11
+ include Singleton
12
+ include WebMock
13
+ include WebMock::Matchers
14
+
15
+ def call env
16
+ request = Rack::Request.new env
17
+ http_method = request.request_method
18
+ request_body = request.body.read
19
+ request_headers = {}
20
+ env.each do |k, v|
21
+ request_headers[k.sub(/^HTTP_/, '')] = v if k =~ /^HTTP_|CONTENT_TYPE|CONTENT_LENGTH/
22
+ end
23
+ begin
24
+ ::Net::HTTP.start(request_headers["HOST"]) do |http|
25
+ request_class = ::Net::HTTP.const_get(http_method.capitalize)
26
+ path = request.path_info
27
+ path << "?#{request.query_string}" unless request.query_string.empty?
28
+ request = request_class.new request.path_info, request_headers
29
+ request.body = request_body unless request_body.empty?
30
+ @response = http.request request
31
+ end
32
+ rescue WebMock::NetConnectNotAllowedError => e
33
+ return [500,
34
+ {"Content-Type" => "text/plain", "Content-Length" => e.message.length.to_s},
35
+ e.message]
36
+ end
37
+ response_headers = {}
38
+ @response.to_hash.each {|k,v| response_headers[k] = v.join "\n"}
39
+ response_headers.delete "status"
40
+ [@response.code, response_headers, @response.body]
41
+ end
42
+ end
43
+ end
data/lib/redrock.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "redrock/server"
2
+
3
+ module RedRock
4
+ def start port = 4242
5
+ raise "RedRock is already running" if @server_thread
6
+ @server_thread = Thread.new do
7
+ Thin::Server.start('0.0.0.0', port) do
8
+ run RedRock::Server.instance
9
+ end
10
+ end
11
+ end
12
+
13
+ def stop
14
+ if @server_thread
15
+ @server_thread.exit
16
+ @server_thread = nil
17
+ end
18
+ end
19
+
20
+ def allow_net_connect!
21
+ raise "RedRock does not support allowing real connections"
22
+ end
23
+
24
+ def disable_net_connect!
25
+ raise "RedRock does not support disabling real connections"
26
+ end
27
+
28
+ def method_missing name, *args, &block
29
+ super unless Server.instance.respond_to? name
30
+ start unless @server_thread
31
+ Server.instance.send name, *args, &block
32
+ end
33
+ end
@@ -0,0 +1,465 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ # Mostly uses curb to avoid going via net/http, to prove that the stubbing
4
+ # isn't happening locally.
5
+
6
+ describe RedRock do
7
+ after do
8
+ RedRock.stop
9
+ end
10
+
11
+ context "server" do
12
+ it "listens on port 4242 by default" do
13
+ stub_request :any, "localhost:4242"
14
+ curl = Curl::Easy.http_get "http://localhost:4242"
15
+ curl.response_code.should == 200
16
+ end
17
+
18
+ it "allows the port to be overridden" do
19
+ RedRock.start 4567
20
+ stub_request :any, "localhost:4567"
21
+ curl = Curl::Easy.http_get "http://localhost:4567"
22
+ curl.response_code.should == 200
23
+ end
24
+
25
+ it "silently ignores attempts to stop non-running server" do
26
+ lambda {RedRock.stop}.should_not raise_error
27
+ end
28
+
29
+ it "only runs one server at a time" do
30
+ RedRock.start 4567
31
+ lambda {RedRock.start 4568}.should raise_error(RuntimeError, "RedRock is already running")
32
+ end
33
+ end
34
+
35
+ context "on receipt of an unexpected request" do
36
+ let(:curl) { Curl::Easy.http_get "http://localhost:4567" }
37
+
38
+ it "returns a 500 error" do
39
+ curl.response_code.should == 500
40
+ end
41
+
42
+ it "returns a useful message in the body" do
43
+ curl.body_str.should =~ /Real HTTP connections are disabled/
44
+ end
45
+ end
46
+
47
+ context "stubbing with URI only and default response" do
48
+ before do
49
+ stub_request :any, "localhost:4242/foo"
50
+ end
51
+
52
+ it "accepts matching requests" do
53
+ curl = Curl::Easy.http_get "http://localhost:4242/foo"
54
+ curl.response_code.should == 200
55
+ end
56
+
57
+ it "rejects non-matching requests" do
58
+ curl = Curl::Easy.http_get "http://localhost:4242/bar"
59
+ curl.response_code.should == 500
60
+ end
61
+ end
62
+
63
+ context "stubbing with method, URI, body and headers" do
64
+ before do
65
+ stub_request(:any, "localhost:4242/foo").with(:body => "onion", :headers => { "bacon-preference" => "chunky" })
66
+ end
67
+
68
+ it "accepts matching requests" do
69
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
70
+ c.headers["bacon-preference"] = "chunky"
71
+ end
72
+ curl.response_code.should == 200
73
+ end
74
+
75
+ it "rejects requests with the wrong URI" do
76
+ curl = Curl::Easy.http_post "http://localhost:4242/bar", "onion" do |c|
77
+ c.headers["bacon-preference"] = "chunky"
78
+ end
79
+ curl.response_code.should == 500
80
+ end
81
+
82
+ it "rejects requests with the wrong body" do
83
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "cabbage" do |c|
84
+ c.headers["bacon-preference"] = "chunky"
85
+ end
86
+ curl.response_code.should == 500
87
+ end
88
+
89
+ it "rejects requests with the wrong headers" do
90
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
91
+ c.headers["bacon-preference"] = "streaky"
92
+ end
93
+ curl.response_code.should == 500
94
+ end
95
+ end
96
+
97
+ context "matching request body and headers against regular expressions" do
98
+ before do
99
+ stub_request(:any, "localhost:4242/foo").with(:body => /nion/, :headers => { "bacon-preference" => /c.*y/ })
100
+ end
101
+
102
+ it "accepts matching requests" do
103
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "onion" do |c|
104
+ c.headers["bacon-preference"] = "chunky"
105
+ end
106
+ curl.response_code.should == 200
107
+ end
108
+
109
+ it "rejects requests with the wrong body" do
110
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "neon" do |c|
111
+ c.headers["bacon-preference"] = "crispy"
112
+ end
113
+ curl.response_code.should == 500
114
+ end
115
+
116
+ it "rejects requests with the wrong headers" do
117
+ curl = Curl::Easy.http_post "http://localhost:4242/foo", "bunion" do |c|
118
+ c.headers["bacon-preference"] = "streaky"
119
+ end
120
+ curl.response_code.should == 500
121
+ end
122
+ end
123
+
124
+ context "matching request body against a hash" do
125
+ before do
126
+ stub_http_request(:post, "localhost:4242").with(:body => {:data => {:a => '1', :b => 'five'}})
127
+ end
128
+
129
+ it "matches URL-encoded data" do
130
+ curl = Curl::Easy.http_post "http://localhost:4242/", "data[a]=1&data[b]=five" do |c|
131
+ c.headers["Content-Type"] = "application/x-www-form-urlencoded"
132
+ end
133
+ curl.response_code.should == 200
134
+ end
135
+
136
+ it "matches JSON data" do
137
+ curl = Curl::Easy.http_post "http://localhost:4242/", %({"data":{"a":"1","b":"five"}}) do |c|
138
+ c.headers["Content-Type"] = "application/json"
139
+ end
140
+ curl.response_code.should == 200
141
+ end
142
+
143
+ it "matches XML data" do
144
+ curl = Curl::Easy.http_post "http://localhost:4242/", %(<data a="1" b="five" />) do |c|
145
+ c.headers["Content-Type"] = "application/xml"
146
+ end
147
+ curl.response_code.should == 200
148
+ end
149
+ end
150
+
151
+ context "matching multiple headers with the same name" do
152
+ before do
153
+ stub_http_request(:get, "localhost:4242").with(:headers => {"Accept" => ["image/jpeg", "image/png"]})
154
+ end
155
+
156
+ it "matches when both header values are present" do
157
+ # Curb can't do multiple headers with the same name
158
+ req = Net::HTTP::Get.new("/")
159
+ req['Accept'] = ['image/png']
160
+ req.add_field('Accept', 'image/jpeg')
161
+ resp = Net::HTTP.start("localhost:4242") {|http| http.request(req) }
162
+ resp.should be_an_instance_of Net::HTTPOK
163
+ end
164
+
165
+ it "rejects requests with missing values" do
166
+ curl = Curl::Easy.http_get "http://localhost:4242/" do |c|
167
+ c.headers["Accept"] = "image/jpeg"
168
+ end
169
+ curl.response_code.should == 500
170
+ end
171
+ end
172
+
173
+ context "matching requests against a block" do
174
+ before do
175
+ stub_request(:post, "localhost:4242").with { |request| request.body == "abc" }
176
+ end
177
+
178
+ it "matches when the block returns true" do
179
+ curl = Curl::Easy.http_post "http://localhost:4242", "abc"
180
+ curl.response_code.should == 200
181
+ end
182
+
183
+ it "does not match when the block returns false" do
184
+ curl = Curl::Easy.http_post "http://localhost:4242", "def"
185
+ curl.response_code.should == 500
186
+ end
187
+ end
188
+
189
+ context "using basic auth" do
190
+ before do
191
+ stub_request(:get, "user:pass@localhost:4242")
192
+ end
193
+
194
+ it "matches when the username and password are correct" do
195
+ curl = Curl::Easy.http_get "http://localhost:4242/" do |c|
196
+ c.http_auth_types = :basic
197
+ c.username = "user"
198
+ c.password = "pass"
199
+ end
200
+ curl.response_code.should == 200
201
+ end
202
+ end
203
+
204
+ context "matching URIs against regular expressions" do
205
+ before do
206
+ stub_request :any, %r(local.*/foo)
207
+ end
208
+
209
+ it "accepts matching requests" do
210
+ curl = Curl::Easy.http_get "http://localhost:4242/wibble/foo"
211
+ curl.response_code.should == 200
212
+ end
213
+
214
+ it "rejects non-matching requests" do
215
+ curl = Curl::Easy.http_get "http://localhost:4242/bar"
216
+ curl.response_code.should == 500
217
+ end
218
+ end
219
+
220
+ context "matching query params using a hash" do
221
+ before do
222
+ stub_http_request(:get, "localhost:4242").with(:query => {"a" => ["b", "c"]})
223
+ end
224
+
225
+ it "accepts matching requests" do
226
+ curl = Curl::Easy.http_get "http://localhost:4242?a[]=b&a[]=c"
227
+ curl.response_code.should == 200
228
+ end
229
+
230
+ it "rejects non-matching requests" do
231
+ curl = Curl::Easy.http_get "http://localhost:4242?a[]=d"
232
+ curl.response_code.should == 500
233
+ end
234
+ end
235
+
236
+ context "returning a custom response" do
237
+ before do
238
+ stub_request(:any, "localhost:4242").to_return(:body => "abc", :status => 201,
239
+ :headers => { "Location" => "nowhere"})
240
+ end
241
+
242
+ let(:curl) { Curl::Easy.http_get "http://localhost:4242" }
243
+
244
+ it "returns the specified body" do
245
+ curl.body_str.should == "abc"
246
+ end
247
+
248
+ it "returns the specified response code" do
249
+ curl.response_code.should == 201
250
+ end
251
+
252
+ it "returns the specified headers" do
253
+ curl.header_str.should =~ /location: nowhere/
254
+ end
255
+ end
256
+
257
+ it "supports specification of a response body as an IO object" do
258
+ stub_request(:any, "localhost:4242").to_return(:body => StringIO.new("chunky bacon"), :status => 200)
259
+ curl = Curl::Easy.http_get "http://localhost:4242"
260
+ curl.body_str.should == "chunky bacon"
261
+ end
262
+
263
+ context "returning a custom status message" do
264
+ before do
265
+ stub_request(:any, "localhost:4242").to_return(:status => [500, "Pixies are on strike"])
266
+ end
267
+
268
+ let(:resp) do
269
+ uri = URI.parse "http://localhost:4242"
270
+ Net::HTTP.start(uri.host, uri.port) {|http|
271
+ http.get "/"
272
+ }
273
+ end
274
+
275
+ it "returns the specified response code" do
276
+ resp.code.should == "500"
277
+ end
278
+
279
+ it "returns the specified message" do
280
+ resp.message.should == "Pixies are on strike"
281
+ end
282
+ end
283
+
284
+ context "replaying raw responses recorded with curl -is" do
285
+ let(:raw_response) do
286
+ <<-EOF
287
+ HTTP/1.1 200 OK
288
+ Date: Wed, 18 Aug 2010 13:24:53 GMT
289
+ Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 Phusion_Passenger/2.2.11
290
+ Last-Modified: Mon, 29 Jun 2009 12:57:40 GMT
291
+ ETag: "13b358c-117-46d7c3c301900"
292
+ Accept-Ranges: bytes
293
+ Content-Length: 13
294
+ Content-Type: text/p[ain
295
+
296
+ Chunky bacon!
297
+ EOF
298
+ end
299
+
300
+ shared_examples_for "a raw response" do
301
+ it "returns the response" do
302
+ curl = Curl::Easy.http_get "http://localhost:4242"
303
+ curl.body_str.should == "Chunky bacon!"
304
+ end
305
+ end
306
+
307
+ context "as a file" do
308
+ before do
309
+ File.open "response", "w" do |f|
310
+ f.puts raw_response
311
+ end
312
+ stub_request(:any, "localhost:4242").to_return File.new("response")
313
+ end
314
+
315
+ after do
316
+ FileUtils.rm_rf "response"
317
+ end
318
+
319
+ it_should_behave_like "a raw response"
320
+ end
321
+
322
+ context "as a string" do
323
+ before do
324
+ stub_request(:any, "localhost:4242").to_return raw_response
325
+ end
326
+
327
+ it_should_behave_like "a raw response"
328
+ end
329
+ end
330
+
331
+ context "dynamically evaluating responses" do
332
+ shared_examples_for "a dynamic response" do
333
+ it "returns the correct response" do
334
+ curl = Curl::Easy.http_post "http://localhost:4242", "!nocab yknuhC"
335
+ curl.body_str.should == "Chunky bacon!"
336
+ end
337
+ end
338
+
339
+ context "from a block" do
340
+ before do
341
+ stub_request(:any, "localhost:4242").to_return { |request| {:body => request.body.reverse} }
342
+ end
343
+
344
+ it_should_behave_like "a dynamic response"
345
+ end
346
+
347
+ context "from a lambda" do
348
+ before do
349
+ stub_request(:any, "localhost:4242").to_return(lambda { |request| {:body => request.body.reverse} })
350
+ end
351
+
352
+ it_should_behave_like "a dynamic response"
353
+ end
354
+
355
+ context "by part" do
356
+ before do
357
+ stub_request(:any, "localhost:4242").to_return(:body => lambda { |request| request.body.reverse })
358
+ end
359
+
360
+ it_should_behave_like "a dynamic response"
361
+ end
362
+ end
363
+
364
+ context "setting multiple responses" do
365
+ shared_examples_for "multiple responses" do
366
+ it "returns the correct values" do
367
+ curl = Curl::Easy.new "http://localhost:4242"
368
+ (1..3).map do
369
+ curl.http_get
370
+ curl.body_str
371
+ end.should == %w(chunky chunky bacon)
372
+ end
373
+ end
374
+
375
+ context "individually" do
376
+ before do
377
+ stub_request(:get, "localhost:4242").to_return({:body => "chunky"},
378
+ {:body => "chunky"},
379
+ {:body => "bacon"})
380
+ end
381
+
382
+ it_should_behave_like "multiple responses"
383
+ end
384
+
385
+ context "using method chaining" do
386
+ before do
387
+ stub_request(:get, "localhost:4242").to_return({:body => "chunky"}).then.
388
+ to_return({:body => "chunky"}).then.to_return({:body => "bacon"})
389
+ end
390
+
391
+ it_should_behave_like "multiple responses"
392
+ end
393
+
394
+ context "specifying the number of times to return a given response" do
395
+ before do
396
+ stub_request(:get, "localhost:4242").to_return({:body => "chunky"}).times(2).then.
397
+ to_return({:body => "bacon"})
398
+ end
399
+
400
+ it_should_behave_like "multiple responses"
401
+ end
402
+ end
403
+
404
+ context "assertions" do
405
+ before do
406
+ stub_request :any, "localhost:4242/foo"
407
+ Curl::Easy.http_get "http://localhost:4242/foo"
408
+ end
409
+
410
+ context "in the test/unit style" do
411
+ it "can assert requests made" do
412
+ assert_requested :get, "http://localhost:4242/foo"
413
+ end
414
+
415
+ it "can assert requests not made" do
416
+ assert_not_requested :get, "http://localhost:4242/bar"
417
+ end
418
+ end
419
+
420
+ context "in the rspec style" do
421
+ it "can assert requests made" do
422
+ RedRock.should have_requested :get, "http://localhost:4242/foo"
423
+ end
424
+
425
+ it "can assert requests not made" do
426
+ RedRock.should_not have_requested :get, "http://localhost:4242/bar"
427
+ end
428
+ end
429
+
430
+ context "in the alternative rspec style" do
431
+ it "can assert requests made" do
432
+ request(:get, "http://localhost:4242/foo").should have_been_made
433
+ end
434
+
435
+ it "can assert requests not made" do
436
+ request(:get, "http://localhost:4242/bar").should_not have_been_made
437
+ end
438
+ end
439
+ end
440
+
441
+ context "resetting" do
442
+ before do
443
+ stub_request :any, "localhost:4242"
444
+ Curl::Easy.http_get "http://localhost:4242"
445
+ reset_webmock
446
+ end
447
+
448
+ it "clears stubs" do
449
+ curl = Curl::Easy.http_get "http://localhost:4242"
450
+ curl.response_code.should == 500
451
+ end
452
+
453
+ it "clears history" do
454
+ request(:get, "http://localhost:4242").should_not have_been_made
455
+ end
456
+ end
457
+
458
+ it "does not support enabling local requests" do
459
+ lambda {allow_net_connect!}.should raise_error RuntimeError, "RedRock does not support allowing real connections"
460
+ end
461
+
462
+ it "does not support disabling local requests" do
463
+ lambda {disable_net_connect!}.should raise_error RuntimeError, "RedRock does not support disabling real connections"
464
+ end
465
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "spec"
3
+ require "curb"
4
+ require "stringio"
5
+ require "redrock"
6
+ include RedRock
7
+ require "webmock/test_unit"
8
+ require "webmock/rspec"
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redrock
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Kerry Buckley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-19 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thin
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 15
30
+ segments:
31
+ - 1
32
+ - 0
33
+ version: "1.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: curb
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ description:
65
+ email: kerryjbuckley@gmail.com
66
+ executables: []
67
+
68
+ extensions: []
69
+
70
+ extra_rdoc_files:
71
+ - README.rdoc
72
+ files:
73
+ - spec/redrock_spec.rb
74
+ - spec/spec_helper.rb
75
+ - lib/redrock/server.rb
76
+ - lib/redrock.rb
77
+ - README.rdoc
78
+ has_rdoc: true
79
+ homepage: http://github.com/kerryb/redrock
80
+ licenses: []
81
+
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --main
85
+ - README.rdoc
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.3.7
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Proxy for using WebMock remotely
113
+ test_files: []
114
+