redrock 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/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
+