rspec_api_documentation 4.9.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rspec_api_documentation/api_documentation.rb +2 -0
- data/lib/rspec_api_documentation/client_base.rb +8 -8
- data/lib/rspec_api_documentation/configuration.rb +12 -1
- data/lib/rspec_api_documentation/curl.rb +7 -2
- data/lib/rspec_api_documentation/dsl/endpoint/params.rb +19 -3
- data/lib/rspec_api_documentation/dsl/endpoint/set_param.rb +18 -5
- data/lib/rspec_api_documentation/dsl/endpoint.rb +44 -2
- data/lib/rspec_api_documentation/dsl/resource.rb +48 -1
- data/lib/rspec_api_documentation/dsl.rb +1 -1
- data/lib/rspec_api_documentation/example.rb +4 -0
- data/lib/rspec_api_documentation/open_api/contact.rb +9 -0
- data/lib/rspec_api_documentation/open_api/example.rb +7 -0
- data/lib/rspec_api_documentation/open_api/header.rb +12 -0
- data/lib/rspec_api_documentation/open_api/headers.rb +7 -0
- data/lib/rspec_api_documentation/open_api/helper.rb +29 -0
- data/lib/rspec_api_documentation/open_api/info.rb +12 -0
- data/lib/rspec_api_documentation/open_api/license.rb +8 -0
- data/lib/rspec_api_documentation/open_api/node.rb +112 -0
- data/lib/rspec_api_documentation/open_api/operation.rb +18 -0
- data/lib/rspec_api_documentation/open_api/parameter.rb +33 -0
- data/lib/rspec_api_documentation/open_api/path.rb +13 -0
- data/lib/rspec_api_documentation/open_api/paths.rb +7 -0
- data/lib/rspec_api_documentation/open_api/response.rb +10 -0
- data/lib/rspec_api_documentation/open_api/responses.rb +9 -0
- data/lib/rspec_api_documentation/open_api/root.rb +21 -0
- data/lib/rspec_api_documentation/open_api/schema.rb +15 -0
- data/lib/rspec_api_documentation/open_api/security_definitions.rb +7 -0
- data/lib/rspec_api_documentation/open_api/security_schema.rb +14 -0
- data/lib/rspec_api_documentation/open_api/tag.rb +9 -0
- data/lib/rspec_api_documentation/railtie.rb +1 -1
- data/lib/rspec_api_documentation/views/api_blueprint_example.rb +116 -0
- data/lib/rspec_api_documentation/views/api_blueprint_index.rb +105 -0
- data/lib/rspec_api_documentation/views/markdown_example.rb +1 -1
- data/lib/rspec_api_documentation/views/markup_example.rb +12 -3
- data/lib/rspec_api_documentation/views/markup_index.rb +2 -4
- data/lib/rspec_api_documentation/views/slate_index.rb +4 -0
- data/lib/rspec_api_documentation/writers/api_blueprint_writer.rb +29 -0
- data/lib/rspec_api_documentation/writers/combined_json_writer.rb +1 -1
- data/lib/rspec_api_documentation/writers/general_markup_writer.rb +20 -7
- data/lib/rspec_api_documentation/writers/json_iodocs_writer.rb +3 -2
- data/lib/rspec_api_documentation/writers/json_writer.rb +10 -6
- data/lib/rspec_api_documentation/writers/markdown_writer.rb +1 -1
- data/lib/rspec_api_documentation/writers/open_api_writer.rb +244 -0
- data/lib/rspec_api_documentation/writers/slate_writer.rb +2 -8
- data/lib/rspec_api_documentation.rb +29 -0
- data/templates/rspec_api_documentation/api_blueprint_index.mustache +80 -0
- data/templates/rspec_api_documentation/html_index.mustache +1 -1
- data/templates/rspec_api_documentation/markdown_example.mustache +4 -3
- data/templates/rspec_api_documentation/markdown_index.mustache +1 -0
- data/templates/rspec_api_documentation/slate_example.mustache +2 -2
- data/templates/rspec_api_documentation/slate_index.mustache +8 -0
- data/templates/rspec_api_documentation/textile_index.mustache +1 -0
- metadata +61 -3
@@ -0,0 +1,21 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module OpenApi
|
3
|
+
class Root < Node
|
4
|
+
add_setting :swagger, :default => '2.0', :required => true
|
5
|
+
add_setting :info, :default => Info.new, :required => true, :schema => Info
|
6
|
+
add_setting :host, :default => 'localhost:3000'
|
7
|
+
add_setting :basePath
|
8
|
+
add_setting :schemes, :default => %w(http https)
|
9
|
+
add_setting :consumes, :default => %w(application/json application/xml)
|
10
|
+
add_setting :produces, :default => %w(application/json application/xml)
|
11
|
+
add_setting :paths, :default => Paths.new, :required => true, :schema => Paths
|
12
|
+
add_setting :definitions
|
13
|
+
add_setting :parameters
|
14
|
+
add_setting :responses
|
15
|
+
add_setting :securityDefinitions, :schema => SecurityDefinitions
|
16
|
+
add_setting :security
|
17
|
+
add_setting :tags, :default => [], :schema => [Tag]
|
18
|
+
add_setting :externalDocs
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module OpenApi
|
3
|
+
class Schema < Node
|
4
|
+
add_setting :format
|
5
|
+
add_setting :title
|
6
|
+
add_setting :description, :default => ''
|
7
|
+
add_setting :required
|
8
|
+
add_setting :enum
|
9
|
+
add_setting :type
|
10
|
+
add_setting :items
|
11
|
+
add_setting :properties
|
12
|
+
add_setting :example
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module OpenApi
|
3
|
+
class SecuritySchema < Node
|
4
|
+
add_setting :type, :required => true
|
5
|
+
add_setting :description, :default => ''
|
6
|
+
add_setting :name
|
7
|
+
add_setting :in
|
8
|
+
add_setting :flow
|
9
|
+
add_setting :authorizationUrl
|
10
|
+
add_setting :tokenUrl
|
11
|
+
add_setting :scopes
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module Views
|
3
|
+
class ApiBlueprintExample < MarkupExample
|
4
|
+
TOTAL_SPACES_INDENTATION = 12.freeze
|
5
|
+
|
6
|
+
def initialize(example, configuration)
|
7
|
+
super
|
8
|
+
self.template_name = "rspec_api_documentation/api_blueprint_example"
|
9
|
+
end
|
10
|
+
|
11
|
+
def parameters
|
12
|
+
super.map do |parameter|
|
13
|
+
parameter.merge({
|
14
|
+
:required => !!parameter[:required],
|
15
|
+
:has_example => !!parameter[:example],
|
16
|
+
:has_type => !!parameter[:type]
|
17
|
+
})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def requests
|
22
|
+
super.map do |request|
|
23
|
+
request[:request_headers_text] = remove_utf8_for_json(remove_content_type(request[:request_headers_text]))
|
24
|
+
request[:request_headers_text] = indent(request[:request_headers_text])
|
25
|
+
request[:request_content_type] = content_type(request[:request_headers])
|
26
|
+
request[:request_content_type] = remove_utf8_for_json(request[:request_content_type])
|
27
|
+
request[:request_body] = body_to_json(request, :request)
|
28
|
+
request[:request_body] = indent(request[:request_body])
|
29
|
+
|
30
|
+
request[:response_headers_text] = remove_utf8_for_json(remove_content_type(request[:response_headers_text]))
|
31
|
+
request[:response_headers_text] = indent(request[:response_headers_text])
|
32
|
+
request[:response_content_type] = content_type(request[:response_headers])
|
33
|
+
request[:response_content_type] = remove_utf8_for_json(request[:response_content_type])
|
34
|
+
request[:response_body] = body_to_json(request, :response)
|
35
|
+
request[:response_body] = indent(request[:response_body])
|
36
|
+
|
37
|
+
request[:has_request?] = has_request?(request)
|
38
|
+
request[:has_response?] = has_response?(request)
|
39
|
+
request
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def extension
|
44
|
+
Writers::ApiBlueprintWriter::EXTENSION
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# `Content-Type` header is removed because the information would be duplicated
|
50
|
+
# since it's already present in `request[:request_content_type]`.
|
51
|
+
def remove_content_type(headers)
|
52
|
+
return unless headers
|
53
|
+
headers
|
54
|
+
.split("\n")
|
55
|
+
.reject { |header|
|
56
|
+
header.start_with?('Content-Type:')
|
57
|
+
}
|
58
|
+
.join("\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_request?(metadata)
|
62
|
+
metadata.any? do |key, value|
|
63
|
+
[:request_body, :request_headers, :request_content_type].include?(key) && value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_response?(metadata)
|
68
|
+
metadata.any? do |key, value|
|
69
|
+
[:response_status, :response_body, :response_headers, :response_content_type].include?(key) && value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def indent(string)
|
74
|
+
string.tap do |str|
|
75
|
+
str.gsub!(/\n/, "\n" + (" " * TOTAL_SPACES_INDENTATION)) if str
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# http_call: the hash that contains all information about the HTTP
|
80
|
+
# request and response.
|
81
|
+
# message_direction: either `request` or `response`.
|
82
|
+
def body_to_json(http_call, message_direction)
|
83
|
+
content_type = http_call["#{message_direction}_content_type".to_sym]
|
84
|
+
body = http_call["#{message_direction}_body".to_sym] # e.g request_body
|
85
|
+
|
86
|
+
if json?(content_type) && body
|
87
|
+
body = JSON.pretty_generate(JSON.parse(body))
|
88
|
+
end
|
89
|
+
|
90
|
+
body
|
91
|
+
end
|
92
|
+
|
93
|
+
# JSON requests should use UTF-8 by default according to
|
94
|
+
# http://www.ietf.org/rfc/rfc4627.txt, so we will remove `charset=utf-8`
|
95
|
+
# when we find it to remove noise.
|
96
|
+
def remove_utf8_for_json(headers)
|
97
|
+
return unless headers
|
98
|
+
headers
|
99
|
+
.split("\n")
|
100
|
+
.map { |header|
|
101
|
+
header.gsub!(/; *charset=utf-8/, "") if json?(header)
|
102
|
+
header
|
103
|
+
}
|
104
|
+
.join("\n")
|
105
|
+
end
|
106
|
+
|
107
|
+
def content_type(headers)
|
108
|
+
headers && headers.fetch("Content-Type", nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
def json?(string)
|
112
|
+
string =~ /application\/.*json/
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module Views
|
3
|
+
class ApiBlueprintIndex < MarkupIndex
|
4
|
+
def initialize(index, configuration)
|
5
|
+
super
|
6
|
+
self.template_name = "rspec_api_documentation/api_blueprint_index"
|
7
|
+
end
|
8
|
+
|
9
|
+
def sections
|
10
|
+
super.map do |section|
|
11
|
+
routes = section[:examples].group_by { |e| "#{e.route_uri}#{e.route_optionals}#{e.route_name}" }.map do |route, examples|
|
12
|
+
attrs = fields(:attributes, examples)
|
13
|
+
params = fields(:parameters, examples)
|
14
|
+
|
15
|
+
methods = examples.group_by(&:http_method).map do |http_method, examples|
|
16
|
+
{
|
17
|
+
http_method: http_method,
|
18
|
+
description: examples.first.respond_to?(:action_name) && examples.first.action_name,
|
19
|
+
examples: examples
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
{
|
24
|
+
"has_attributes?".to_sym => attrs.size > 0,
|
25
|
+
"has_parameters?".to_sym => params.size > 0,
|
26
|
+
route: format_route(examples[0]),
|
27
|
+
route_name: examples[0][:route_name],
|
28
|
+
attributes: attrs,
|
29
|
+
parameters: params,
|
30
|
+
http_methods: methods
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
section.merge({
|
35
|
+
routes: routes
|
36
|
+
})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def examples
|
41
|
+
@index.examples.map do |example|
|
42
|
+
ApiBlueprintExample.new(example, @configuration)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# APIB follows the RFC 6570 to format URI templates.
|
49
|
+
# According to it, simple string expansion (used to perform variable
|
50
|
+
# expansion) should be represented by `{var}` and not by `/:var`
|
51
|
+
# For example `/posts/:id` should become `/posts/{id}`
|
52
|
+
# cf. https://github.com/apiaryio/api-blueprint/blob/format-1A/API%20Blueprint%20Specification.md#431-resource-section
|
53
|
+
# cf. https://tools.ietf.org/html/rfc6570#section-3.2.6
|
54
|
+
def format_route(example)
|
55
|
+
route_uri = example[:route_uri].gsub(/:(.*?)([.\/?{]|$)/, '{\1}\2')
|
56
|
+
"#{route_uri}#{example[:route_optionals]}"
|
57
|
+
end
|
58
|
+
|
59
|
+
# APIB has both `parameters` and `attributes`. This generates a hash
|
60
|
+
# with all of its properties, like name, description, required.
|
61
|
+
# {
|
62
|
+
# required: true,
|
63
|
+
# example: "1",
|
64
|
+
# type: "string",
|
65
|
+
# name: "id",
|
66
|
+
# description: "The id",
|
67
|
+
# properties_description: "required, string"
|
68
|
+
# }
|
69
|
+
def fields(property_name, examples)
|
70
|
+
examples
|
71
|
+
.map { |example| example.metadata[property_name] }
|
72
|
+
.flatten
|
73
|
+
.compact
|
74
|
+
.uniq { |property| property[:name] }
|
75
|
+
.map do |property|
|
76
|
+
properties = []
|
77
|
+
if property[:required] == true
|
78
|
+
properties << 'required'
|
79
|
+
else
|
80
|
+
properties << 'optional'
|
81
|
+
end
|
82
|
+
properties << property[:type] if property[:type]
|
83
|
+
if properties.count > 0
|
84
|
+
property[:properties_description] = properties.join(", ")
|
85
|
+
else
|
86
|
+
property[:properties_description] = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
property[:description] = nil if description_blank?(property)
|
90
|
+
property
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# When no `description` was specified for a parameter, the DSL class
|
95
|
+
# is making `description = "#{scope} #{name}"`, which is bad because it
|
96
|
+
# assumes that all formats want this behavior. To avoid changing there
|
97
|
+
# and breaking everything, I do my own check here and if description
|
98
|
+
# equals the name, I assume it is blank.
|
99
|
+
def description_blank?(property)
|
100
|
+
!property[:description] ||
|
101
|
+
property[:description].to_s.strip == property[:name].to_s.strip
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -3,6 +3,8 @@ require 'mustache'
|
|
3
3
|
module RspecApiDocumentation
|
4
4
|
module Views
|
5
5
|
class MarkupExample < Mustache
|
6
|
+
SPECIAL_CHARS = /[<>:"\/\\|?*]/.freeze
|
7
|
+
|
6
8
|
def initialize(example, configuration)
|
7
9
|
@example = example
|
8
10
|
@host = configuration.curl_host
|
@@ -19,12 +21,11 @@ module RspecApiDocumentation
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def dirname
|
22
|
-
resource_name.to_s.downcase
|
24
|
+
sanitize(resource_name.to_s.downcase)
|
23
25
|
end
|
24
26
|
|
25
27
|
def filename
|
26
|
-
|
27
|
-
basename = description.downcase.gsub(/\s+/, '_').gsub(special_chars, '')
|
28
|
+
basename = sanitize(description.downcase)
|
28
29
|
basename = Digest::MD5.new.update(description).to_s if basename.blank?
|
29
30
|
"#{basename}.#{extension}"
|
30
31
|
end
|
@@ -83,6 +84,14 @@ module RspecApiDocumentation
|
|
83
84
|
end
|
84
85
|
end.join
|
85
86
|
end
|
87
|
+
|
88
|
+
def content_type(headers)
|
89
|
+
headers && headers.fetch("Content-Type", nil)
|
90
|
+
end
|
91
|
+
|
92
|
+
def sanitize(name)
|
93
|
+
name.gsub(/\s+/, '_').gsub(SPECIAL_CHARS, '')
|
94
|
+
end
|
86
95
|
end
|
87
96
|
end
|
88
97
|
end
|
@@ -3,16 +3,14 @@ require 'mustache'
|
|
3
3
|
module RspecApiDocumentation
|
4
4
|
module Views
|
5
5
|
class MarkupIndex < Mustache
|
6
|
+
delegate :api_name, :api_explanation, to: :@configuration, prefix: false
|
7
|
+
|
6
8
|
def initialize(index, configuration)
|
7
9
|
@index = index
|
8
10
|
@configuration = configuration
|
9
11
|
self.template_path = configuration.template_path
|
10
12
|
end
|
11
13
|
|
12
|
-
def api_name
|
13
|
-
@configuration.api_name
|
14
|
-
end
|
15
|
-
|
16
14
|
def sections
|
17
15
|
RspecApiDocumentation::Writers::IndexHelper.sections(examples, @configuration)
|
18
16
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RspecApiDocumentation
|
2
|
+
module Writers
|
3
|
+
class ApiBlueprintWriter < GeneralMarkupWriter
|
4
|
+
EXTENSION = 'apib'
|
5
|
+
|
6
|
+
def markup_index_class
|
7
|
+
RspecApiDocumentation::Views::ApiBlueprintIndex
|
8
|
+
end
|
9
|
+
|
10
|
+
def markup_example_class
|
11
|
+
RspecApiDocumentation::Views::ApiBlueprintExample
|
12
|
+
end
|
13
|
+
|
14
|
+
def extension
|
15
|
+
EXTENSION
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# API Blueprint is a spec, not navigable like HTML, therefore we generate
|
21
|
+
# only one file with all resources.
|
22
|
+
def render_options
|
23
|
+
super.merge({
|
24
|
+
examples: false
|
25
|
+
})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -7,7 +7,7 @@ module RspecApiDocumentation
|
|
7
7
|
File.open(configuration.docs_dir.join("combined.json"), "w+") do |f|
|
8
8
|
examples = []
|
9
9
|
index.examples.each do |rspec_example|
|
10
|
-
examples << Formatter.to_json(
|
10
|
+
examples << Formatter.to_json(JSONExample.new(rspec_example, configuration))
|
11
11
|
end
|
12
12
|
|
13
13
|
f.write "["
|
@@ -6,16 +6,20 @@ module RspecApiDocumentation
|
|
6
6
|
|
7
7
|
# Write out the generated documentation
|
8
8
|
def write
|
9
|
-
|
10
|
-
|
9
|
+
if render_options.fetch(:index, true)
|
10
|
+
File.open(configuration.docs_dir.join(index_file_name + '.' + extension), "w+") do |f|
|
11
|
+
f.write markup_index_class.new(index, configuration).render
|
12
|
+
end
|
11
13
|
end
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
if render_options.fetch(:examples, true)
|
16
|
+
index.examples.each do |example|
|
17
|
+
markup_example = markup_example_class.new(example, configuration)
|
18
|
+
FileUtils.mkdir_p(configuration.docs_dir.join(markup_example.dirname))
|
16
19
|
|
17
|
-
|
18
|
-
|
20
|
+
File.open(configuration.docs_dir.join(markup_example.dirname, markup_example.filename), "w+") do |f|
|
21
|
+
f.write markup_example.render
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -27,6 +31,15 @@ module RspecApiDocumentation
|
|
27
31
|
def extension
|
28
32
|
raise 'Parent class. This method should not be called.'
|
29
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def render_options
|
38
|
+
{
|
39
|
+
index: true,
|
40
|
+
examples: true
|
41
|
+
}
|
42
|
+
end
|
30
43
|
end
|
31
44
|
end
|
32
45
|
end
|
@@ -32,7 +32,7 @@ module RspecApiDocumentation
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def examples
|
35
|
-
@index.examples.map { |example|
|
35
|
+
@index.examples.map { |example| JsonIodocsExample.new(example, @configuration) }
|
36
36
|
end
|
37
37
|
|
38
38
|
def as_json(opts = nil)
|
@@ -48,7 +48,7 @@ module RspecApiDocumentation
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
class
|
51
|
+
class JsonIodocsExample
|
52
52
|
def initialize(example, configuration)
|
53
53
|
@example = example
|
54
54
|
end
|
@@ -94,6 +94,7 @@ module RspecApiDocumentation
|
|
94
94
|
{
|
95
95
|
@api_key.to_sym => {
|
96
96
|
:name => @configuration.api_name,
|
97
|
+
:description => @configuration.api_explanation,
|
97
98
|
:protocol => @configuration.io_docs_protocol,
|
98
99
|
:publicPath => "",
|
99
100
|
:baseURL => @configuration.curl_host
|
@@ -2,19 +2,19 @@ require 'rspec_api_documentation/writers/formatter'
|
|
2
2
|
|
3
3
|
module RspecApiDocumentation
|
4
4
|
module Writers
|
5
|
-
class
|
5
|
+
class JSONWriter < Writer
|
6
6
|
delegate :docs_dir, :to => :configuration
|
7
7
|
|
8
8
|
def write
|
9
9
|
File.open(docs_dir.join("index.json"), "w+") do |f|
|
10
|
-
f.write Formatter.to_json(
|
10
|
+
f.write Formatter.to_json(JSONIndex.new(index, configuration))
|
11
11
|
end
|
12
12
|
write_examples
|
13
13
|
end
|
14
14
|
|
15
15
|
def write_examples
|
16
16
|
index.examples.each do |example|
|
17
|
-
json_example =
|
17
|
+
json_example = JSONExample.new(example, configuration)
|
18
18
|
FileUtils.mkdir_p(docs_dir.join(json_example.dirname))
|
19
19
|
File.open(docs_dir.join(json_example.dirname, json_example.filename), "w+") do |f|
|
20
20
|
f.write Formatter.to_json(json_example)
|
@@ -23,7 +23,11 @@ module RspecApiDocumentation
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
# https://github.com/zipmark/rspec_api_documentation/issues/382
|
27
|
+
# backward compatibilty json for configuration of config.format
|
28
|
+
class JsonWriter < JSONWriter; end
|
29
|
+
|
30
|
+
class JSONIndex
|
27
31
|
def initialize(index, configuration)
|
28
32
|
@index = index
|
29
33
|
@configuration = configuration
|
@@ -34,7 +38,7 @@ module RspecApiDocumentation
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def examples
|
37
|
-
@index.examples.map { |example|
|
41
|
+
@index.examples.map { |example| JSONExample.new(example, @configuration) }
|
38
42
|
end
|
39
43
|
|
40
44
|
def as_json(opts = nil)
|
@@ -61,7 +65,7 @@ module RspecApiDocumentation
|
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
64
|
-
class
|
68
|
+
class JSONExample
|
65
69
|
def initialize(example, configuration)
|
66
70
|
@example = example
|
67
71
|
@host = configuration.curl_host
|