hyperspec 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,3 @@
1
- # This is Work in Progress
2
-
3
1
  __ __ ______
4
2
  / / / /_ _________________/ ____/________________
5
3
  / /_/ / / / / __ \ _ \_ __/____ \/ __ \ _ \ ___/
@@ -14,42 +12,44 @@ HTTP APIs from the outside.
14
12
 
15
13
  ## Example
16
14
 
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
15
+ ```ruby
16
+ service "http://localhost:4567" do
17
+ def response_json
18
+ JSON.parse(response.body)
19
+ end
20
+
21
+ resource "/lolz" do
22
+ get do
23
+ it { responds_with.status :ok }
24
+ it { response_json['lolz'].must_be_instance_of Array }
25
+
26
+ with_query("q=monorail") do
27
+ it "only lists lolz that match the query" do
28
+ response_json['lolz'].wont_be_empty
29
+ response_json['lolz'].each do |lol|
30
+ lol['title'].must_match /monorail/
34
31
  end
35
32
  end
33
+ end
34
+ end
36
35
 
37
- post do
38
- describe "without request body" do
39
- it { responds_with.status :unprocessable_entity }
40
- end
36
+ post do
37
+ describe "without request body" do
38
+ it { responds_with.status :unprocessable_entity }
39
+ end
41
40
 
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
41
+ describe "with request body" do
42
+ with_headers({ 'Content-Type' => 'application/json' }) do
43
+ with_request_body({ "title" => "Roflcopter!" }.to_json) do
44
+ it { responds_with.status :created }
45
+ it { response_json['lol']['title'].must_equal 'Roflcopter!' }
49
46
  end
50
47
  end
51
48
  end
52
49
  end
50
+ end
51
+ end
52
+ ```
53
53
 
54
54
  ## Concepts
55
55
 
@@ -99,6 +99,10 @@ Allows for comparing against named status code symbols.
99
99
 
100
100
  - DSL for matching representations.
101
101
 
102
+ ### Documentation
103
+
104
+ - Adding an output format for docs.
105
+
102
106
  ## Concerns
103
107
 
104
108
  - Efficient ways of building up and verifying precondition state.
@@ -107,12 +111,24 @@ Allows for comparing against named status code symbols.
107
111
 
108
112
  ## Acknowledgments
109
113
 
110
- Thanks to Daniel Bornkessel for inspiring me to do README driven development.
114
+ Thanks to:
115
+
116
+ - [Daniel Bornkessel](https://github.com/kesselborn) for inspiring me to do `README` driven development.
117
+ - [Matthias Georgi](https://github.com/georgi) for suggestions for code improvements.
118
+ - [Lars Gierth](https://github.com/lgierth) for updating the example server to respond with 415 Unsupported Media Type in the appropriate case.
119
+ - [Anton Lindqvist](https://github.com/mptre) for adding HTTP Basic Auth
111
120
 
112
121
  ## History
113
122
 
114
- ### 2012 02 07
123
+ ### 0.0.2
124
+
125
+ #### 2012 03 30
126
+
127
+ - Correcting environment dependencies.
128
+ - Adding support for HTTP Basic Auth.
129
+
130
+ ### 0.0.1
115
131
 
116
- #### 0.0.1
132
+ #### 2012 02 07
117
133
 
118
134
  - Initial release
@@ -18,6 +18,6 @@ post "/lolz" do
18
18
  %^{"lol": {"title": "Roflcopter!"}}^
19
19
  end
20
20
  else
21
- status 422
21
+ status 415
22
22
  end
23
23
  end
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_development_dependency *dependency
39
39
  end
40
40
 
41
- (dependencies + developement_dependencies).each do |dependency|
41
+ (dependencies + runtime_dependencies).each do |dependency|
42
42
  s.add_runtime_dependency *dependency
43
43
  end
44
44
  end
@@ -10,75 +10,71 @@ module HyperSpec
10
10
  module ObjectExtensions
11
11
  private
12
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
13
+ describe(desc, additional_desc, &block).tap do |cls|
14
+ cls.class_eval do
15
+ define_method(:base_uri) { URI.parse(desc) }
16
+ define_method(:headers) { {} }
17
+ define_method(:request_body) { "" }
18
+ end
19
+ end
18
20
  end
19
21
 
20
22
  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
23
+ describe(desc, additional_desc, &block).tap do |cls|
24
+ cls.class_eval do
25
+ define_method(:base_uri) do
26
+ super().tap do |s|
27
+ s.path = [ s.path, path ].reject(&:empty?).join("/")
28
+ end
29
+ end
30
+ end
27
31
  end
28
- cls
29
32
  end
30
33
 
31
34
  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
+ describe("with headers", additional_desc, &block).tap do |cls|
36
+ cls.class_eval do
37
+ define_method(:headers) { super().merge(hash) }
38
+ end
39
+ end
35
40
  end
36
41
 
37
42
  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
+ describe("with query", additional_desc, &block).tap do |cls|
44
+ cls.class_eval do
45
+ define_method(:base_uri) do
46
+ super().tap do |s|
47
+ s.query = [ s.query.to_s, string ].reject(&:empty?).join("&")
48
+ end
49
+ end
50
+ end
43
51
  end
44
- cls
45
52
  end
46
53
 
47
54
  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
55
+ describe("with request body", additional_desc, &block).tap do |cls|
56
+ cls.class_eval do
57
+ define_method(:request_body) { string }
58
+ end
51
59
  end
52
- cls
53
60
  end
54
61
 
55
62
  # HTTP method selection
56
63
  #
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
64
+ {
65
+ 'get' => Net::HTTP::Get,
66
+ 'head' => Net::HTTP::Head,
67
+ 'post' => Net::HTTP::Post,
68
+ 'put' => Net::HTTP::Put,
69
+ 'delete' => Net::HTTP::Delete,
70
+ }.each do |http_method, request_class|
71
+ define_method(http_method) do |additional_desc = nil, &block|
72
+ describe(http_method.upcase, additional_desc, &block).tap do |cls|
73
+ cls.class_eval do
74
+ define_method(:request_class) { request_class }
75
+ end
76
+ end
77
+ end
82
78
  end
83
79
  end
84
80
 
@@ -88,19 +84,14 @@ module HyperSpec
88
84
  do_request
89
85
  end
90
86
 
91
- def request_type
92
- self.class.request_type
93
- end
94
-
95
87
  def responds_with
96
88
  Have.new(response)
97
89
  end
98
90
 
99
91
  private
100
92
  def do_request
101
- klass = eval("Net::HTTP::#{request_type.to_s.gsub(/^\w/) { |c| c.upcase }}")
102
93
  @do_request ||=
103
- request_response(klass, base_uri, headers, request_body)
94
+ request_response(request_class, base_uri, headers, request_body)
104
95
  end
105
96
 
106
97
  def request_response(klass, uri, headers, body = '')
@@ -117,11 +108,13 @@ module HyperSpec
117
108
  req = klass.new(request_uri)
118
109
  headers.inject(req) { |m, (k, v)| m[k] = v; m }
119
110
  req.body = body if body
111
+ req.basic_auth(uri.user, uri.password) if uri.userinfo
120
112
  if headers['Content-Type']
121
113
  req.content_type = headers['Content-Type']
122
114
  end
123
115
  http.request(req)
124
116
  end
117
+
125
118
  Response.from_net_http_response(resp)
126
119
  end
127
120
  end
@@ -188,6 +181,5 @@ module HyperSpec
188
181
  end
189
182
  end
190
183
 
191
-
192
184
  ::Object.send(:include, HyperSpec::ObjectExtensions)
193
185
  ::MiniTest::Spec.send(:include, HyperSpec::MiniTest::SpecExtensions)
@@ -1,6 +1,6 @@
1
1
  module HyperSpec
2
2
  MAJOR = 0
3
3
  MINOR = 0
4
- PATCH = 1
4
+ PATCH = 2
5
5
  VERSION = [ MAJOR, MINOR, PATCH ].join(".")
6
6
  end
@@ -92,3 +92,44 @@
92
92
  body: |+
93
93
  {"is-this-json":true}
94
94
 
95
+ - !ruby/struct:VCR::HTTPInteraction
96
+ request: !ruby/struct:VCR::Request
97
+ method: :get
98
+ uri: http://username@localhost:80/secret
99
+ headers:
100
+ authorization:
101
+ - Basic dXNlcm5hbWU6cGFzc3dvcmQ=
102
+ body:
103
+ response: !ruby/struct:VCR::Response
104
+ http_version: "1.1"
105
+ status: !ruby/struct:VCR::ResponseStatus
106
+ code: 200
107
+ message: OK
108
+ headers:
109
+ content-length:
110
+ - "24"
111
+ content-type:
112
+ - application/json;charset=utf-8
113
+ body: |+
114
+ {"is-this-secret":true}
115
+
116
+ - !ruby/struct:VCR::HTTPInteraction
117
+ request: !ruby/struct:VCR::Request
118
+ method: :get
119
+ uri: http://username:password@localhost:80/secret
120
+ headers:
121
+ authorization:
122
+ - Basic dXNlcm5hbWU6cGFzc3dvcmQ=
123
+ body:
124
+ response: !ruby/struct:VCR::Response
125
+ http_version: "1.1"
126
+ status: !ruby/struct:VCR::ResponseStatus
127
+ code: 200
128
+ message: OK
129
+ headers:
130
+ content-length:
131
+ - "24"
132
+ content-type:
133
+ - application/json;charset=utf-8
134
+ body: |+
135
+ {"is-this-secret":true}
@@ -21,8 +21,8 @@ describe HyperSpec do
21
21
 
22
22
  use_vcr_cassette('localhost')
23
23
 
24
- it "should be of version 0.0.0" do
25
- HyperSpec::VERSION.must_equal "0.0.0"
24
+ it "should be of version 0.0.1" do
25
+ HyperSpec::VERSION.must_equal "0.0.1"
26
26
  end
27
27
 
28
28
  describe "MiniTest::Spec extensions" do
@@ -119,7 +119,13 @@ describe HyperSpec do
119
119
  it { subject.request_body.must_equal "lol[title]=Roflcopter" }
120
120
  end
121
121
 
122
- %w[ get head post put delete ].map(&:to_sym).each do |http_method|
122
+ {
123
+ 'get' => Net::HTTP::Get,
124
+ 'head' => Net::HTTP::Head,
125
+ 'post' => Net::HTTP::Post,
126
+ 'put' => Net::HTTP::Put,
127
+ 'delete' => Net::HTTP::Delete,
128
+ }.each do |http_method, request_class|
123
129
  describe "HTTP method selection" do
124
130
  subject do
125
131
  the_spec do |bound|
@@ -131,7 +137,7 @@ describe HyperSpec do
131
137
  end
132
138
  end
133
139
 
134
- it { subject.request_type.must_equal http_method }
140
+ it { subject.request_class.must_equal request_class }
135
141
  end
136
142
  end
137
143
 
@@ -198,5 +204,35 @@ describe HyperSpec do
198
204
  it { subject.status_code 200 }
199
205
  it { subject.status :ok }
200
206
  end
207
+
208
+ describe "basic auth" do
209
+ describe "with username" do
210
+ subject do
211
+ the_spec do |bound|
212
+ service("http://username@localhost") do
213
+ resource("/secret") do
214
+ bound.value = get {}
215
+ end
216
+ end
217
+ end.response
218
+ end
219
+
220
+ it { subject.status_code.must_equal 200 }
221
+ end
222
+
223
+ describe "with username and password" do
224
+ subject do
225
+ the_spec do |bound|
226
+ service("http://username:password@localhost") do
227
+ resource("/secret") do
228
+ bound.value = get {}
229
+ end
230
+ end
231
+ end.response
232
+ end
233
+
234
+ it { subject.status_code.must_equal 200 }
235
+ end
236
+ end
201
237
  end
202
238
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: hyperspec
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - "Hannes Tyd\xC3\xA9n"
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-02-07 00:00:00 Z
13
+ date: 2012-03-30 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: minitest
@@ -56,28 +56,6 @@ dependencies:
56
56
  version: "2.11"
57
57
  type: :runtime
58
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
59
  description: " By extending minitest/spec HyperSpec provides a Ruby DSL for testing HTTP APIs from the \"outside\".\n"
82
60
  email:
83
61
  - hannes@soundcloud.com