http_spec 0.0.2 → 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/lib/http_spec/clients/rack.rb +1 -5
- data/lib/http_spec/clients/raddocs_proxy.rb +137 -0
- data/lib/http_spec/dsl/methods.rb +2 -1
- data/lib/http_spec/dsl/parameters.rb +35 -0
- data/lib/http_spec/dsl/resource.rb +14 -27
- data/lib/http_spec/types.rb +6 -1
- data/lib/http_spec.rb +9 -0
- metadata +69 -2
@@ -11,15 +11,11 @@ module HTTPSpec
|
|
11
11
|
def dispatch(request)
|
12
12
|
opts = headers_to_env(request.headers)
|
13
13
|
opts[:input] = request.body
|
14
|
-
|
14
|
+
@session.request(request.method, request.path, opts)
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
def from_rack(response)
|
20
|
-
Response.new(response.status, response.body, response.headers)
|
21
|
-
end
|
22
|
-
|
23
19
|
def headers_to_env(headers)
|
24
20
|
return {} unless headers
|
25
21
|
headers.inject({}) do |env, (k, v)|
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "http_spec/types"
|
2
|
+
require "raddocs"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module HTTPSpec
|
6
|
+
module Clients
|
7
|
+
class RaddocsProxy
|
8
|
+
def initialize(inner, metadata, dir = Raddocs.configuration.docs_dir)
|
9
|
+
@inner = inner
|
10
|
+
@resource_name = metadata.fetch(:resource_name)
|
11
|
+
@description = metadata[:description]
|
12
|
+
raise KeyError, "key not found :description" unless @description
|
13
|
+
@parameters = metadata[:parameters]
|
14
|
+
@explanation = metadata[:explanation]
|
15
|
+
@dir = dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def dispatch(request)
|
19
|
+
write_index
|
20
|
+
response = @inner.dispatch(request)
|
21
|
+
write_example(request, response)
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def write_index
|
28
|
+
filepath = File.join(@dir, "index.json")
|
29
|
+
index = load_or_new(Index, filepath)
|
30
|
+
index.add_example(@resource_name, @description, example_path)
|
31
|
+
File.open(filepath, "w") { |file| index.dump(file) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_example(request, response)
|
35
|
+
filepath = File.join(@dir, example_path)
|
36
|
+
FileUtils.mkdir_p(File.dirname(filepath))
|
37
|
+
example = load_or_new(Example, filepath, @resource_name, @description)
|
38
|
+
example.explanation = @explanation
|
39
|
+
example.parameters = @parameters
|
40
|
+
example.add_request(request, response)
|
41
|
+
File.open(filepath, "w") { |file| example.dump(file) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def example_path
|
45
|
+
dirname = @resource_name.gsub(/\s+/, '_').gsub(/\W/, '')
|
46
|
+
filename = @description.downcase.gsub(/\s+/, '_').gsub(/\W/, '')
|
47
|
+
File.join(dirname, filename + ".json")
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_or_new(klass, filepath, *args)
|
51
|
+
if File.exists?(filepath)
|
52
|
+
File.open(filepath, "r") { |file| klass.load(file) }
|
53
|
+
else
|
54
|
+
klass.new(*args)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Index
|
59
|
+
attr_reader :resources
|
60
|
+
|
61
|
+
def initialize(resources = [])
|
62
|
+
@resources = resources
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.load(io, serializer = JSON)
|
66
|
+
content = serializer.load(io)
|
67
|
+
resources = content.fetch("resources")
|
68
|
+
new(resources)
|
69
|
+
end
|
70
|
+
|
71
|
+
def dump(io, serializer = JSON)
|
72
|
+
content = { "resources" => resources }
|
73
|
+
serializer.dump(content, io)
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_example(resource_name, description, link)
|
77
|
+
resource = resources.find { |r| r["name"] == resource_name }
|
78
|
+
unless resource
|
79
|
+
resource = { "name" => resource_name, "examples" => [] }
|
80
|
+
resources.push(resource)
|
81
|
+
end
|
82
|
+
examples = resource.fetch("examples")
|
83
|
+
example = examples.find { |e| e["description"] == description }
|
84
|
+
unless example
|
85
|
+
example = { "description" => description, "link" => link }
|
86
|
+
examples.push(example)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Example
|
92
|
+
attr_reader :resource_name, :description, :requests
|
93
|
+
attr_accessor :explanation, :parameters
|
94
|
+
|
95
|
+
def initialize(resource_name, description, requests = [])
|
96
|
+
@resource_name = resource_name
|
97
|
+
@description = description
|
98
|
+
@requests = requests
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.load(io, serializer = JSON)
|
102
|
+
content = serializer.load(io)
|
103
|
+
resource_name = content.fetch("resource")
|
104
|
+
description = content.fetch("description")
|
105
|
+
requests = content.fetch("requests")
|
106
|
+
new(resource_name, description, requests).tap do |example|
|
107
|
+
example.explanation = content["explanation"]
|
108
|
+
example.parameters = content["parameters"]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def dump(io, serializer = JSON)
|
113
|
+
content = {
|
114
|
+
"resource" => resource_name,
|
115
|
+
"description" => description,
|
116
|
+
"explanation" => explanation,
|
117
|
+
"parameters" => parameters,
|
118
|
+
"requests" => requests
|
119
|
+
}
|
120
|
+
serializer.dump(content, io)
|
121
|
+
end
|
122
|
+
|
123
|
+
def add_request(request, response)
|
124
|
+
requests.push(
|
125
|
+
"request_headers" => request.headers || {},
|
126
|
+
"request_method" => request.method.upcase,
|
127
|
+
"request_path" => request.path,
|
128
|
+
"request_body" => request.body,
|
129
|
+
"response_status" => response.status,
|
130
|
+
"response_headers" => response.headers,
|
131
|
+
"response_body" => response.body
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "http_spec"
|
1
2
|
require "http_spec/types"
|
2
3
|
|
3
4
|
module HTTPSpec
|
@@ -7,7 +8,7 @@ module HTTPSpec
|
|
7
8
|
methods.each do |method|
|
8
9
|
define_method(method) do |path, body=nil, headers=nil|
|
9
10
|
request = Request.new(method, path, body, headers)
|
10
|
-
|
11
|
+
HTTPSpec.dispatch(request)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module HTTPSpec
|
2
|
+
module DSL
|
3
|
+
module Parameters
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
base.metadata[:parameters] = []
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def parameter(name, description, extra = {})
|
11
|
+
param = extra.merge(:name => name, :description => description)
|
12
|
+
copy_superclass_metadata(:parameters)
|
13
|
+
metadata[:parameters].push(param)
|
14
|
+
end
|
15
|
+
|
16
|
+
def copy_superclass_metadata(key)
|
17
|
+
return unless superclass_metadata && superclass_metadata[key]
|
18
|
+
if superclass_metadata[key].equal?(metadata[key])
|
19
|
+
metadata[key] = superclass_metadata[key].dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def params
|
25
|
+
return {} unless example.metadata[:parameters]
|
26
|
+
@params ||= {}
|
27
|
+
example.metadata[:parameters].each do |param|
|
28
|
+
name = param[:name]
|
29
|
+
@params[name] ||= send(name) if respond_to?(name)
|
30
|
+
end
|
31
|
+
@params
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "http_spec"
|
1
2
|
require "http_spec/types"
|
2
3
|
|
3
4
|
module HTTPSpec
|
@@ -5,30 +6,24 @@ module HTTPSpec
|
|
5
6
|
module Resource
|
6
7
|
def self.included(base)
|
7
8
|
base.extend(ClassMethods)
|
9
|
+
base.metadata[:default_headers] = {}
|
8
10
|
end
|
9
11
|
|
10
12
|
module ClassMethods
|
11
13
|
def self.define_actions(*methods)
|
12
14
|
methods.each do |method|
|
13
|
-
define_method(method) do |route, &block|
|
15
|
+
define_method(method) do |route, metadata = {}, &block|
|
14
16
|
description = "#{method.to_s.upcase} #{route}"
|
15
|
-
request = Request.new(method, route)
|
16
|
-
context(description,
|
17
|
+
metadata[:request] = Request.new(method, route)
|
18
|
+
context(description, metadata, &block)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
define_actions :get, :post, :put, :patch, :delete, :options, :head
|
22
24
|
|
23
|
-
def parameter(name, description, extra = {})
|
24
|
-
copy_superclass_metadata(:parameters)
|
25
|
-
metadata[:parameters] ||= {}
|
26
|
-
metadata[:parameters][name] = extra.merge(:description => description)
|
27
|
-
end
|
28
|
-
|
29
25
|
def header(name, value)
|
30
26
|
copy_superclass_metadata(:default_headers)
|
31
|
-
metadata[:default_headers] ||= {}
|
32
27
|
metadata[:default_headers][name] = value
|
33
28
|
end
|
34
29
|
|
@@ -41,21 +36,11 @@ module HTTPSpec
|
|
41
36
|
end
|
42
37
|
|
43
38
|
def do_request(options = {})
|
44
|
-
request = example.metadata[:request]
|
45
|
-
request.body = options
|
46
|
-
request.headers = default_headers(options
|
47
|
-
request
|
48
|
-
|
49
|
-
@last_response = client.dispatch(request)
|
50
|
-
end
|
51
|
-
|
52
|
-
def params
|
53
|
-
return {} unless example.metadata[:parameters]
|
54
|
-
params = {}
|
55
|
-
example.metadata[:parameters].each_key do |name|
|
56
|
-
params[name] = send(name) if respond_to?(name)
|
57
|
-
end
|
58
|
-
params
|
39
|
+
request = example.metadata[:request].dup
|
40
|
+
request.body = options.delete(:body)
|
41
|
+
request.headers = default_headers(options.delete(:headers))
|
42
|
+
build_path(request, options)
|
43
|
+
@last_response = HTTPSpec.dispatch(request)
|
59
44
|
end
|
60
45
|
|
61
46
|
def status
|
@@ -73,9 +58,11 @@ module HTTPSpec
|
|
73
58
|
|
74
59
|
private
|
75
60
|
|
76
|
-
def build_path(request)
|
61
|
+
def build_path(request, options)
|
77
62
|
request.path.gsub!(/:(\w+)/) do |match|
|
78
|
-
if
|
63
|
+
if options.key?($1.to_sym)
|
64
|
+
options[$1.to_sym]
|
65
|
+
elsif respond_to?($1)
|
79
66
|
send($1)
|
80
67
|
else
|
81
68
|
match
|
data/lib/http_spec/types.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
module HTTPSpec
|
2
|
-
Request = Struct.new(:method, :path, :body, :headers
|
2
|
+
Request = Struct.new(:method, :path, :body, :headers) do
|
3
|
+
def dup
|
4
|
+
Request.new(method, path.dup, body, headers)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
3
8
|
Response = Struct.new(:status, :body, :headers)
|
4
9
|
end
|
data/lib/http_spec.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -91,6 +91,38 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: raddocs
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rake
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
94
126
|
- !ruby/object:Gem::Dependency
|
95
127
|
name: simplecov
|
96
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +155,38 @@ dependencies:
|
|
123
155
|
- - ! '>='
|
124
156
|
- !ruby/object:Gem::Version
|
125
157
|
version: '0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: capybara
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: aruba
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
126
190
|
description:
|
127
191
|
email:
|
128
192
|
executables: []
|
@@ -132,10 +196,13 @@ files:
|
|
132
196
|
- lib/http_spec/clients/faraday.rb
|
133
197
|
- lib/http_spec/clients/fdoc_proxy.rb
|
134
198
|
- lib/http_spec/clients/rack.rb
|
199
|
+
- lib/http_spec/clients/raddocs_proxy.rb
|
135
200
|
- lib/http_spec/clients/webmachine.rb
|
136
201
|
- lib/http_spec/dsl/methods.rb
|
202
|
+
- lib/http_spec/dsl/parameters.rb
|
137
203
|
- lib/http_spec/dsl/resource.rb
|
138
204
|
- lib/http_spec/types.rb
|
205
|
+
- lib/http_spec.rb
|
139
206
|
homepage: https://github.com/smartlogic/http_spec
|
140
207
|
licenses: []
|
141
208
|
post_install_message:
|