hyperspec 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,118 @@
1
+ # This is Work in Progress
2
+
3
+ __ __ ______
4
+ / / / /_ _________________/ ____/________________
5
+ / /_/ / / / / __ \ _ \_ __/____ \/ __ \ _ \ ___/
6
+ / __ / /_/ / /_/ / __/ / ____/ / /_/ / __/ /__
7
+ /_/ /_/\__, / ____/\___/_/ /_____/ ____/\___/\___/
8
+ /____/_/ /_/
9
+
10
+ A full stack testing framework for HTTP APIs.
11
+
12
+ By extending `minitest/spec` HyperSpec provides a Ruby DSL for testing
13
+ HTTP APIs from the outside.
14
+
15
+ ## Example
16
+
17
+ service "http://localhost:4567" do
18
+ def response_json
19
+ JSON.parse(response.body)
20
+ end
21
+
22
+ resource "/lolz" do
23
+ get do
24
+ it { responds_with.status :ok }
25
+ it { response_json['lolz'].must_be_instance_of Array }
26
+
27
+ with_query("q=monorail") do
28
+ it "only lists lolz that match the query" do
29
+ response_json['lolz'].wont_be_empty
30
+ response_json['lolz'].each do |lol|
31
+ lol['title'].must_match /monorail/
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ post do
38
+ describe "without request body" do
39
+ it { responds_with.status :unprocessable_entity }
40
+ end
41
+
42
+ describe "with request body" do
43
+ with_headers({ 'Content-Type' => 'application/json' }) do
44
+ with_request_body({ "title" => "Roflcopter!" }.to_json) do
45
+ it { responds_with.status :created }
46
+ it { response_json['lol']['title'].must_equal 'Roflcopter!' }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ ## Concepts
55
+
56
+ ### `service`
57
+
58
+ Sets the `BASE_URI` of the API.
59
+
60
+ ### `resource`
61
+
62
+ Sets the `URI` under test. Absolute or relative to the current scope.
63
+
64
+ ### `get`, `head`, `post`, `put` and `delete`
65
+
66
+ Selects the HTTP method for the request.
67
+
68
+ ### `with_query_string`
69
+
70
+ Sets the query parameters used for a request. Merges with previously set parameters.
71
+
72
+ ### `with_headers`
73
+
74
+ Sets the headers used for a request. Merges with previously set headers.
75
+
76
+ ### `with_body`
77
+
78
+ Sets the body used for a request. Overrides previously set parameters.
79
+
80
+ ### `response`
81
+
82
+ An object for accessing properties of the "raw" response.
83
+
84
+ ### `responds_with`
85
+
86
+ Issues the request and returns an object that has the following convenience matchers:
87
+
88
+ #### `status`
89
+
90
+ Allows for comparing against named status code symbols.
91
+
92
+ #### `content_type`
93
+
94
+ #### `content_charset`
95
+
96
+ ## Upcoming features
97
+
98
+ ### Representations
99
+
100
+ - DSL for matching representations.
101
+
102
+ ## Concerns
103
+
104
+ - Efficient ways of building up and verifying precondition state.
105
+ - Verify an eventual consistent state.
106
+ - Allowing whitebox testing by "wormholing" into the application(s).
107
+
108
+ ## Acknowledgments
109
+
110
+ Thanks to Daniel Bornkessel for inspiring me to do README driven development.
111
+
112
+ ## History
113
+
114
+ ### 2012 02 07
115
+
116
+ #### 0.0.1
117
+
118
+ - Initial release
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ require 'sinatra'
2
+ require 'json'
3
+
4
+ get "/lolz" do
5
+ title = params[:q]
6
+ %^{"lolz": [ { "title": "#{title}" } ]}^
7
+ end
8
+
9
+ post "/lolz" do
10
+ if request.env['CONTENT_TYPE'] == "application/json"
11
+ params = JSON.parse(request.env['rack.input'].read)
12
+
13
+ if params.nil? || params.empty?
14
+ status 422
15
+ %^{"error": "An error occurred!"}^
16
+ else
17
+ status 201
18
+ %^{"lol": {"title": "Roflcopter!"}}^
19
+ end
20
+ else
21
+ status 422
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+
3
+ require './example'
4
+
5
+ run Sinatra::Application
@@ -0,0 +1,52 @@
1
+ require 'hyperspec'
2
+ require 'minitest/autorun'
3
+
4
+ require 'json'
5
+
6
+ # Run `shotgun -p 4567 example.ru` from `examples/service/`.
7
+
8
+ service "http://localhost:4567" do
9
+ def response_json
10
+ JSON.parse(response.body)
11
+ end
12
+
13
+ resource "/lolz" do
14
+ get do
15
+ it { responds_with.status :ok }
16
+ it { response_json['lolz'].must_be_instance_of Array }
17
+
18
+ with_query("q=monorail") do
19
+ it "only lists lolz that match the query" do
20
+ response_json['lolz'].wont_be_empty
21
+ response_json['lolz'].each do |lol|
22
+ lol['title'].must_match /monorail/
23
+ end
24
+ end
25
+ end
26
+
27
+ with_query("q=looong") do
28
+ it "only lists lolz that match the query" do
29
+ response_json['lolz'].wont_be_empty
30
+ response_json['lolz'].each do |lol|
31
+ lol['title'].must_match /looong/
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ post do
38
+ describe "without request body" do
39
+ it { responds_with.status :unprocessable_entity }
40
+ end
41
+
42
+ describe "with request body" do
43
+ with_headers({ 'Content-Type' => 'application/json' }) do
44
+ with_request_body({ "title" => "Roflcopter!" }.to_json) do
45
+ it { responds_with.status :created }
46
+ it { response_json['lol']['title'].must_equal 'Roflcopter!' }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "hyperspec/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "hyperspec"
7
+ s.version = HyperSpec::VERSION
8
+ s.authors = [ "Hannes Tydén" ]
9
+ s.email = [ "hannes@soundcloud.com" ]
10
+ s.homepage = "http://github.com/hannestyden/hyperspec"
11
+ s.summary = "Full stack HTTP API testing DSL."
12
+ s.description = <<-DESCRIPTION
13
+ By extending minitest/spec HyperSpec provides a Ruby DSL for testing HTTP APIs from the "outside".
14
+ DESCRIPTION
15
+
16
+ # Required for validation.
17
+ s.rubyforge_project = "hyperspec"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = [ "lib" ]
23
+
24
+ dependencies =
25
+ [
26
+ [ "minitest", "~> 2.11" ],
27
+ ]
28
+
29
+ developement_dependencies =
30
+ [
31
+ [ "vcr", "~> 1.6" ],
32
+ [ "webmock" ],
33
+ ]
34
+
35
+ runtime_dependencies = []
36
+
37
+ (dependencies + developement_dependencies).each do |dependency|
38
+ s.add_development_dependency *dependency
39
+ end
40
+
41
+ (dependencies + developement_dependencies).each do |dependency|
42
+ s.add_runtime_dependency *dependency
43
+ end
44
+ end
@@ -0,0 +1,193 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ gem 'minitest' # Ensure gem is used over built in.
5
+ require 'minitest/spec'
6
+
7
+ require 'hyperspec/version'
8
+
9
+ module HyperSpec
10
+ module ObjectExtensions
11
+ private
12
+ def service(desc, additional_desc = nil, &block)
13
+ cls = describe(desc, additional_desc, &block)
14
+ cls.send(:define_method, :base_uri) { URI.parse(desc) }
15
+ cls.send(:define_method, :headers) { {} }
16
+ cls.send(:define_method, :request_body) { "" }
17
+ cls
18
+ end
19
+
20
+ def resource(path, additional_desc = nil, &block)
21
+ cls = describe(desc, additional_desc, &block)
22
+
23
+ cls.send(:define_method, :base_uri) do
24
+ s = super()
25
+ s.path = [ s.path, path ].reject(&:empty?).join("/")
26
+ s
27
+ end
28
+ cls
29
+ end
30
+
31
+ def with_headers(hash, additional_desc = nil, &block)
32
+ cls = describe("with headers", additional_desc, &block)
33
+ cls.send(:define_method, :headers) { super().merge(hash) }
34
+ cls
35
+ end
36
+
37
+ def with_query(string, additional_desc = nil, &block)
38
+ cls = describe("with query", additional_desc, &block)
39
+ cls.send(:define_method, :base_uri) do
40
+ s = super()
41
+ s.query = [ s.query.to_s, string ].reject(&:empty?).join("&")
42
+ s
43
+ end
44
+ cls
45
+ end
46
+
47
+ def with_request_body(string, additional_desc = nil, &block)
48
+ cls = describe("with request body", additional_desc, &block)
49
+ cls.send(:define_method, :request_body) do
50
+ string
51
+ end
52
+ cls
53
+ end
54
+
55
+ # HTTP method selection
56
+ #
57
+ def get(additional_desc = nil, &block)
58
+ cls = describe('GET', additional_desc, &block)
59
+ cls.instance_eval { |_| def request_type; :get; end }
60
+ cls
61
+ end
62
+
63
+ def head(additional_desc = nil, &block)
64
+ cls = describe('HEAD', additional_desc, &block)
65
+ cls.instance_eval { |_| def request_type; :head; end }
66
+ cls
67
+ end
68
+ def post(additional_desc = nil, &block)
69
+ cls = describe('POST', additional_desc, &block)
70
+ cls.instance_eval { |_| def request_type; :post; end }
71
+ cls
72
+ end
73
+ def put(additional_desc = nil, &block)
74
+ cls = describe('PUT', additional_desc, &block)
75
+ cls.instance_eval { |_| def request_type; :put; end }
76
+ cls
77
+ end
78
+ def delete(additional_desc = nil, &block)
79
+ cls = describe('DELETE', additional_desc, &block)
80
+ cls.instance_eval { |_| def request_type; :delete; end }
81
+ cls
82
+ end
83
+ end
84
+
85
+ module MiniTest
86
+ module SpecExtensions
87
+ def response
88
+ do_request
89
+ end
90
+
91
+ def request_type
92
+ self.class.request_type
93
+ end
94
+
95
+ def responds_with
96
+ Have.new(response)
97
+ end
98
+
99
+ private
100
+ def do_request
101
+ klass = eval("Net::HTTP::#{request_type.to_s.gsub(/^\w/) { |c| c.upcase }}")
102
+ @do_request ||=
103
+ request_response(klass, base_uri, headers, request_body)
104
+ end
105
+
106
+ def request_response(klass, uri, headers, body = '')
107
+ http = Net::HTTP.new(uri.host, uri.port)
108
+ http.use_ssl = URI::HTTPS === uri
109
+
110
+ # NO DON'T DO IT!
111
+ # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
112
+ # YOU DIDN'T DO IT, DID YOU?
113
+
114
+ resp =
115
+ http.start do
116
+ request_uri = [ uri.path, uri.query ].join("?")
117
+ req = klass.new(request_uri)
118
+ headers.inject(req) { |m, (k, v)| m[k] = v; m }
119
+ req.body = body if body
120
+ if headers['Content-Type']
121
+ req.content_type = headers['Content-Type']
122
+ end
123
+ http.request(req)
124
+ end
125
+ Response.from_net_http_response(resp)
126
+ end
127
+ end
128
+ end
129
+
130
+ Response = Struct.new(:status_code, :headers, :body) do
131
+ STATI = {
132
+ # 2xx
133
+ 200 => :ok,
134
+ 201 => :created,
135
+
136
+ # 4xx
137
+ 401 => :unauthorized,
138
+ 411 => :length_required,
139
+
140
+ # WebDav extensions
141
+ 422 => :unprocessable_entity,
142
+ }
143
+
144
+ def self.from_net_http_response(http)
145
+ status_code = http.code.to_i
146
+ body = http.body
147
+
148
+ headers =
149
+ CaseInsensitiveHash.from_hash(http.to_hash)
150
+
151
+ new(status_code, headers, body)
152
+ end
153
+
154
+ def content_type
155
+ headers['Content-Type'].split(';').first
156
+ end
157
+
158
+ def content_charset
159
+ (md = headers['Content-Type'].match(/;charset=(.*)/)) && md[1]
160
+ end
161
+
162
+ def status
163
+ STATI[status_code]
164
+ end
165
+ end
166
+
167
+ class CaseInsensitiveHash < Hash
168
+ def self.from_hash(hash)
169
+ hash.inject(new) do |m, (k, v)|
170
+ m[k] = v.first
171
+ m
172
+ end
173
+ end
174
+
175
+ def []=(key, value)
176
+ super(key.downcase, value)
177
+ end
178
+
179
+ def [](key)
180
+ super(key.downcase)
181
+ end
182
+ end
183
+
184
+ Have = Struct.new(:proxy) do
185
+ def method_missing(method_name, *arguments, &block)
186
+ proxy.send(method_name).must_equal(*arguments)
187
+ end
188
+ end
189
+ end
190
+
191
+
192
+ ::Object.send(:include, HyperSpec::ObjectExtensions)
193
+ ::MiniTest::Spec.send(:include, HyperSpec::MiniTest::SpecExtensions)
@@ -0,0 +1,6 @@
1
+ module HyperSpec
2
+ MAJOR = 0
3
+ MINOR = 0
4
+ PATCH = 1
5
+ VERSION = [ MAJOR, MINOR, PATCH ].join(".")
6
+ end
@@ -0,0 +1,94 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://localhost:80/
6
+ headers:
7
+ body:
8
+ response: !ruby/struct:VCR::Response
9
+ http_version: "1.1"
10
+ status: !ruby/struct:VCR::ResponseStatus
11
+ code: 200
12
+ message: OK
13
+ headers:
14
+ content-length:
15
+ - "22"
16
+ content-type:
17
+ - application/json;charset=utf-8
18
+ body: |+
19
+ {"is-this-json":true}
20
+
21
+ - !ruby/struct:VCR::HTTPInteraction
22
+ request: !ruby/struct:VCR::Request
23
+ method: :head
24
+ uri: http://localhost:80/
25
+ headers:
26
+ body:
27
+ response: !ruby/struct:VCR::Response
28
+ http_version: "1.1"
29
+ status: !ruby/struct:VCR::ResponseStatus
30
+ code: 200
31
+ message: OK
32
+ headers:
33
+ content-length:
34
+ - "22"
35
+ content-type:
36
+ - application/json;charset=utf-8
37
+ body:
38
+ - !ruby/struct:VCR::HTTPInteraction
39
+ request: !ruby/struct:VCR::Request
40
+ method: :post
41
+ uri: http://localhost:80/
42
+ headers:
43
+ body:
44
+ response: !ruby/struct:VCR::Response
45
+ http_version: "1.1"
46
+ status: !ruby/struct:VCR::ResponseStatus
47
+ code: 200
48
+ message: OK
49
+ headers:
50
+ content-length:
51
+ - "22"
52
+ content-type:
53
+ - application/json;charset=utf-8
54
+ body: |+
55
+ {"is-this-json":true}
56
+
57
+ - !ruby/struct:VCR::HTTPInteraction
58
+ request: !ruby/struct:VCR::Request
59
+ method: :put
60
+ uri: http://localhost:80/
61
+ headers:
62
+ body:
63
+ response: !ruby/struct:VCR::Response
64
+ http_version: "1.1"
65
+ status: !ruby/struct:VCR::ResponseStatus
66
+ code: 200
67
+ message: OK
68
+ headers:
69
+ content-length:
70
+ - "22"
71
+ content-type:
72
+ - application/json;charset=utf-8
73
+ body: |+
74
+ {"is-this-json":true}
75
+
76
+ - !ruby/struct:VCR::HTTPInteraction
77
+ request: !ruby/struct:VCR::Request
78
+ method: :delete
79
+ uri: http://localhost:80/
80
+ headers:
81
+ body:
82
+ response: !ruby/struct:VCR::Response
83
+ http_version: "1.1"
84
+ status: !ruby/struct:VCR::ResponseStatus
85
+ code: 200
86
+ message: OK
87
+ headers:
88
+ content-length:
89
+ - "22"
90
+ content-type:
91
+ - application/json;charset=utf-8
92
+ body: |+
93
+ {"is-this-json":true}
94
+
@@ -0,0 +1,202 @@
1
+ require 'uri'
2
+
3
+ gem 'minitest' # Ensure gem is used over built in.
4
+ require 'minitest/spec'
5
+ require 'minitest/autorun'
6
+
7
+ require 'vcr'
8
+ require './spec/support/vcr'
9
+ require './spec/support/meta_spec'
10
+
11
+ $:.push File.expand_path("../../lib", __FILE__)
12
+ require 'hyperspec'
13
+
14
+ VCR.config do |c|
15
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
16
+ c.stub_with :fakeweb
17
+ end
18
+
19
+ describe HyperSpec do
20
+ include MetaSpec
21
+
22
+ use_vcr_cassette('localhost')
23
+
24
+ it "should be of version 0.0.0" do
25
+ HyperSpec::VERSION.must_equal "0.0.0"
26
+ end
27
+
28
+ describe "MiniTest::Spec extensions" do
29
+ describe "service" do
30
+ # `service` is added to `Kernel`, but conveniently enough
31
+ # returns a sub class of MiniTest::Spec which can be tested.
32
+ subject do
33
+ service("http://lolc.at") {}.
34
+ new("Required name.")
35
+ end
36
+
37
+ it { subject.must_be_kind_of MiniTest::Spec }
38
+ it { subject.base_uri.must_equal URI.parse("http://lolc.at/") }
39
+ it { subject.headers.must_equal({}) }
40
+ end
41
+
42
+ describe "resource" do
43
+ # `resource` is added to `Kernel`, but conveniently enough
44
+ # returns a sub class of MiniTest::Spec which can be tested,
45
+ # though this time we must tap into the `service` and bind it.
46
+ subject do
47
+ the_spec do |bound|
48
+ service("http://lolc.at") do
49
+ bound.value = resource("/lolz") {}
50
+ end
51
+ end
52
+ end
53
+
54
+ it { subject.must_be_kind_of MiniTest::Spec }
55
+ it { subject.base_uri.must_equal URI.parse("http://lolc.at/lolz") }
56
+ it { subject.headers.must_equal({}) }
57
+ end
58
+
59
+ describe "nested resource" do
60
+ # `resource` is added to `Kernel`, but conveniently enough
61
+ # returns a sub class of MiniTest::Spec which can be tested,
62
+ # though this time we must tap into the `service` and bind it.
63
+ subject do
64
+ the_spec do |bound|
65
+ service("http://lolc.at") do
66
+ resource("/lolz") do
67
+ bound.value = resource("catz") {}
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ it { subject.base_uri.must_equal URI.parse("http://lolc.at/lolz/catz") }
74
+ end
75
+
76
+ describe "with_headers" do
77
+ subject do
78
+ the_spec do |bound|
79
+ service("http://localhost") do
80
+ resource("/lolz") do
81
+ bound.value = with_headers({ 'X-Camel-Size' => 'LARGE' }) {}
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ it { subject.must_be_kind_of MiniTest::Spec }
88
+ it { subject.base_uri.must_equal URI.parse("http://localhost/lolz") }
89
+ it { subject.headers.must_equal({ 'X-Camel-Size' => 'LARGE' }) }
90
+ end
91
+
92
+ describe "with_query" do
93
+ subject do
94
+ the_spec do |bound|
95
+ service("http://localhost") do
96
+ resource("/lolz") do
97
+ bound.value = with_query("q=monorail") {}
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ it { subject.must_be_kind_of MiniTest::Spec }
104
+ it { subject.base_uri.query.must_equal "q=monorail" }
105
+ end
106
+
107
+ describe "with_request_body" do
108
+ subject do
109
+ the_spec do |bound|
110
+ service("http://localhost") do
111
+ resource("/lolz") do
112
+ bound.value = with_request_body("lol[title]=Roflcopter") {}
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ it { subject.must_be_kind_of MiniTest::Spec }
119
+ it { subject.request_body.must_equal "lol[title]=Roflcopter" }
120
+ end
121
+
122
+ %w[ get head post put delete ].map(&:to_sym).each do |http_method|
123
+ describe "HTTP method selection" do
124
+ subject do
125
+ the_spec do |bound|
126
+ service("http://localhost") do
127
+ resource("/") do
128
+ bound.value = send(http_method) {}
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ it { subject.request_type.must_equal http_method }
135
+ end
136
+ end
137
+
138
+ describe "response" do
139
+ subject do
140
+ the_spec do |bound|
141
+ service("http://localhost") do
142
+ resource("/") do
143
+ bound.value = get {}
144
+ end
145
+ end
146
+ end.response
147
+ end
148
+
149
+ it { subject.status_code.must_be_kind_of Integer }
150
+ it { subject.headers.must_be_kind_of Hash }
151
+ it { subject.body.must_be_kind_of String }
152
+
153
+ it { subject.content_type.must_be_kind_of String }
154
+ it { subject.status.must_be_kind_of Symbol }
155
+
156
+ describe "status" do
157
+ {
158
+ 200 => :ok,
159
+ 201 => :created,
160
+ 401 => :unauthorized,
161
+ 411 => :length_required,
162
+ 422 => :unprocessable_entity,
163
+ }.each do |code, status|
164
+ it do
165
+ subject.status_code = code
166
+ subject.status.must_equal status
167
+ end
168
+ end
169
+ end
170
+
171
+ describe "content_charset" do
172
+ it { subject.content_charset.must_be_kind_of String }
173
+ it do
174
+ subject.headers['Content-Type'] = "application/xml"
175
+ subject.content_charset.must_be_nil
176
+ end
177
+ end
178
+
179
+ describe "header access" do
180
+ it "must be case insensitive" do
181
+ subject.headers['Content-Length'].must_equal \
182
+ subject.headers['content-length']
183
+ end
184
+ end
185
+ end
186
+
187
+ describe "responds_with" do
188
+ subject do
189
+ the_spec do |bound|
190
+ service("http://localhost") do
191
+ resource("/") do
192
+ bound.value = get {}
193
+ end
194
+ end
195
+ end.responds_with
196
+ end
197
+
198
+ it { subject.status_code 200 }
199
+ it { subject.status :ok }
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,14 @@
1
+ module MetaSpec
2
+ def the_spec(&block)
3
+ intercept(&block).new("The required name.")
4
+ end
5
+
6
+ private
7
+ Bound = Struct.new(:value)
8
+
9
+ def intercept(&block)
10
+ bound = Bound.new
11
+ yield bound
12
+ bound.value
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ ::MiniTest::Spec.send(:extend, VCR::RSpec::Macros)
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hyperspec
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - "Hannes Tyd\xC3\xA9n"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-02-07 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: minitest
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "2.11"
24
+ type: :development
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: vcr
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: "1.6"
35
+ type: :development
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: webmock
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: minitest
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: "2.11"
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: vcr
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: "1.6"
68
+ type: :runtime
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: webmock
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ type: :runtime
80
+ version_requirements: *id006
81
+ description: " By extending minitest/spec HyperSpec provides a Ruby DSL for testing HTTP APIs from the \"outside\".\n"
82
+ email:
83
+ - hannes@soundcloud.com
84
+ executables: []
85
+
86
+ extensions: []
87
+
88
+ extra_rdoc_files: []
89
+
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - README.md
94
+ - Rakefile
95
+ - examples/service/example.rb
96
+ - examples/service/example.ru
97
+ - examples/spec/example_spec.rb
98
+ - hyperspec.gemspec
99
+ - lib/hyperspec.rb
100
+ - lib/hyperspec/version.rb
101
+ - spec/fixtures/vcr_cassettes/localhost.yml
102
+ - spec/hyperspec_spec.rb
103
+ - spec/support/meta_spec.rb
104
+ - spec/support/vcr.rb
105
+ homepage: http://github.com/hannestyden/hyperspec
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options: []
110
+
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project: hyperspec
128
+ rubygems_version: 1.8.15
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Full stack HTTP API testing DSL.
132
+ test_files:
133
+ - spec/fixtures/vcr_cassettes/localhost.yml
134
+ - spec/hyperspec_spec.rb
135
+ - spec/support/meta_spec.rb
136
+ - spec/support/vcr.rb